@@ -52,6 +52,7 @@ class FakeHttpClient final : public HttpClientBase {
5252 HeaderList last_get_headers;
5353 std::vector<HeaderList> get_headers_history;
5454 bool fail_first_get_with_401 = false ;
55+ bool fail_token_fetch = false ;
5556
5657protected:
5758 HttpResponse DoGet (const std::string& endpoint, const HeaderList& headers) override {
@@ -72,6 +73,9 @@ class FakeHttpClient final : public HttpClientBase {
7273 ++post_calls;
7374 if (endpoint == " /token" ) {
7475 ++token_calls;
76+ if (fail_token_fetch) {
77+ return HttpResponse (401 , " " , " Unauthorized" );
78+ }
7579 // Use far-future expiry so the cached token is always considered valid.
7680 const TokenResp* tr = nullptr ;
7781 if (!token_responses_.empty ()) {
@@ -172,4 +176,28 @@ TEST(HttpClientBaseTest, RetryOnceOn401FetchesNewTokenAndRetries) {
172176 ASSERT_EQ (auth2->second , " Bearer t2" );
173177}
174178
179+ TEST (HttpClientBaseTest, PrefetchTokenFetchesAndCachesToken) {
180+ FakeHttpClient client ({{" client_id" , " clientA" }, {" api_key" , " keyA" }});
181+ client.SetTokenResponse (" prefetch" , " Bearer" , 4102444800 );
182+
183+ auto error = client.PrefetchToken ();
184+ ASSERT_FALSE (error.has_value ());
185+ ASSERT_EQ (client.token_calls .load (), 1 );
186+
187+ auto r = client.Get (" /statusz" );
188+ ASSERT_TRUE (r.error_message .empty ());
189+ ASSERT_EQ (r.status_code , 200 );
190+ ASSERT_EQ (client.token_calls .load (), 1 );
191+ }
192+
193+ TEST (HttpClientBaseTest, PrefetchTokenReturnsErrorOnFailure) {
194+ FakeHttpClient client ({{" client_id" , " clientA" }, {" api_key" , " keyA" }});
195+ client.fail_token_fetch = true ;
196+
197+ auto error = client.PrefetchToken ();
198+ ASSERT_TRUE (error.has_value ());
199+ ASSERT_NE (error->find (" status code: 401" ), std::string::npos);
200+ ASSERT_EQ (client.token_calls .load (), 1 );
201+ }
202+
175203
0 commit comments