Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/browser/loader/async_revalidation_driver.h" | |
| 6 | |
| 7 #include <string> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/location.h" | |
|
Bence
2015/11/17 13:12:22
What do you need this include for?
Adam Rice
2015/11/17 17:45:52
For FROM_HERE. Comment added.
| |
| 12 #include "base/macros.h" | |
| 13 #include "base/run_loop.h" | |
| 14 #include "content/public/test/test_browser_thread_bundle.h" | |
| 15 #include "ipc/ipc_message.h" | |
| 16 #include "net/base/io_buffer.h" | |
|
Bence
2015/11/17 13:12:22
Please remove this include, because you have alrea
| |
| 17 #include "net/base/net_errors.h" | |
| 18 #include "net/base/request_priority.h" | |
| 19 #include "net/ssl/ssl_cert_request_info.h" | |
| 20 #include "net/url_request/url_request.h" | |
|
Bence
2015/11/17 13:12:22
Please remove this include, because you have alrea
Adam Rice
2015/11/17 17:45:51
Thanks, done.
| |
| 21 #include "net/url_request/url_request_job_factory.h" | |
| 22 #include "net/url_request/url_request_job_factory_impl.h" | |
| 23 #include "net/url_request/url_request_status.h" | |
| 24 #include "net/url_request/url_request_test_job.h" | |
| 25 #include "net/url_request/url_request_test_util.h" | |
| 26 #include "testing/gtest/include/gtest/gtest.h" | |
| 27 | |
| 28 namespace content { | |
| 29 namespace { | |
| 30 | |
| 31 // A mock URLRequestJob which simulates an SSL client auth request. | |
| 32 class MockClientCertURLRequestJob : public net::URLRequestTestJob { | |
| 33 public: | |
| 34 MockClientCertURLRequestJob(net::URLRequest* request, | |
| 35 net::NetworkDelegate* network_delegate) | |
| 36 : net::URLRequestTestJob(request, network_delegate, true) {} | |
| 37 | |
| 38 static std::vector<std::string> test_authorities() { | |
| 39 return std::vector<std::string>(1, "dummy"); | |
| 40 } | |
| 41 | |
| 42 // net::URLRequestTestJob: | |
|
Bence
2015/11/17 13:12:22
Add " implementation" right before colon.
Adam Rice
2015/11/17 17:45:52
Done.
| |
| 43 void Start() override { | |
| 44 scoped_refptr<net::SSLCertRequestInfo> cert_request_info( | |
| 45 new net::SSLCertRequestInfo); | |
| 46 cert_request_info->cert_authorities = test_authorities(); | |
| 47 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 48 FROM_HERE, | |
| 49 base::Bind(&MockClientCertURLRequestJob::NotifyCertificateRequested, | |
| 50 this, cert_request_info)); | |
| 51 } | |
| 52 | |
| 53 void ContinueWithCertificate(net::X509Certificate* cert) override { | |
| 54 ADD_FAILURE() << "Certificate supplied"; | |
|
Bence
2015/11/17 13:12:22
Optional: consider adding a period to end this sen
Adam Rice
2015/11/17 17:45:52
Done.
| |
| 55 } | |
| 56 | |
| 57 private: | |
| 58 ~MockClientCertURLRequestJob() override {} | |
| 59 | |
| 60 DISALLOW_COPY_AND_ASSIGN(MockClientCertURLRequestJob); | |
|
Bence
2015/11/17 13:12:22
This class does not have any members so it should
Adam Rice
2015/11/17 17:45:52
It's not actually copyable because of the base cla
Bence
2015/11/17 21:34:27
Oh okay, that makes sense. Thank you for clarifyi
| |
| 61 }; | |
| 62 | |
| 63 class MockClientCertJobProtocolHandler | |
| 64 : public net::URLRequestJobFactory::ProtocolHandler { | |
| 65 public: | |
| 66 // URLRequestJobFactory::ProtocolHandler implementation: | |
| 67 net::URLRequestJob* MaybeCreateJob( | |
| 68 net::URLRequest* request, | |
| 69 net::NetworkDelegate* network_delegate) const override { | |
| 70 return new MockClientCertURLRequestJob(request, network_delegate); | |
| 71 } | |
| 72 }; | |
| 73 | |
| 74 // A mock URLRequestJob which simulates an SSL certificate error. | |
| 75 class MockSSLErrorURLRequestJob : public net::URLRequestTestJob { | |
| 76 public: | |
| 77 MockSSLErrorURLRequestJob(net::URLRequest* request, | |
| 78 net::NetworkDelegate* network_delegate) | |
| 79 : net::URLRequestTestJob(request, network_delegate, true) {} | |
| 80 | |
| 81 // net::URLRequestTestJob: | |
|
Bence
2015/11/17 13:12:22
Add " implementation" right before colon.
Adam Rice
2015/11/17 17:45:52
Done.
| |
| 82 void Start() override { | |
| 83 // This SSLInfo isn't really valid, but it is good enough for testing. | |
| 84 net::SSLInfo ssl_info; | |
| 85 ssl_info.SetCertError(net::ERR_CERT_DATE_INVALID); | |
| 86 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 87 FROM_HERE, | |
| 88 base::Bind(&MockSSLErrorURLRequestJob::NotifySSLCertificateError, this, | |
| 89 ssl_info, false)); | |
| 90 } | |
| 91 | |
| 92 void ContinueDespiteLastError() override { | |
| 93 ADD_FAILURE() << "ContinueDespiteLastError called"; | |
|
Bence
2015/11/17 13:12:22
Optional: consider adding a full stop to end this
Adam Rice
2015/11/17 17:45:52
Done.
| |
| 94 } | |
| 95 | |
| 96 private: | |
| 97 ~MockSSLErrorURLRequestJob() override {} | |
| 98 | |
| 99 DISALLOW_COPY_AND_ASSIGN(MockSSLErrorURLRequestJob); | |
|
Bence
2015/11/17 13:12:22
Why?
Adam Rice
2015/11/17 17:45:52
No particular reason, just making it explicit.
Bence
2015/11/17 21:34:27
Sounds good.
| |
| 100 }; | |
| 101 | |
| 102 class MockSSLErrorJobProtocolHandler | |
| 103 : public net::URLRequestJobFactory::ProtocolHandler { | |
| 104 public: | |
| 105 // URLRequestJobFactory::ProtocolHandler implementation: | |
| 106 net::URLRequestJob* MaybeCreateJob( | |
| 107 net::URLRequest* request, | |
| 108 net::NetworkDelegate* network_delegate) const override { | |
| 109 return new MockSSLErrorURLRequestJob(request, network_delegate); | |
| 110 } | |
| 111 }; | |
| 112 | |
| 113 // Dummy implementation of ResourceThrottle, an instance of which is needed to | |
| 114 // initialize AsyncRevalidationDriver. | |
| 115 class ResourceThrottleStub : public ResourceThrottle { | |
| 116 public: | |
| 117 ResourceThrottleStub() {} | |
| 118 | |
| 119 // If true, defers the request in WillStartRequest. | |
| 120 void set_defer_request_on_will_start_request( | |
| 121 bool defer_request_on_will_start_request) { | |
| 122 defer_request_on_will_start_request_ = defer_request_on_will_start_request; | |
| 123 } | |
| 124 | |
| 125 // If true, defers the request in WillStartUsingNetwork. | |
| 126 void set_defer_request_on_will_start_using_network( | |
| 127 bool defer_request_on_will_start_using_network) { | |
| 128 defer_request_on_will_start_using_network_ = | |
| 129 defer_request_on_will_start_using_network; | |
| 130 } | |
| 131 | |
| 132 // If true, defers the request in WillProcessResponse. | |
| 133 void set_defer_request_on_will_process_response( | |
| 134 bool defer_request_on_will_process_response) { | |
| 135 defer_request_on_will_process_response_ = | |
| 136 defer_request_on_will_process_response; | |
| 137 } | |
| 138 | |
| 139 bool will_redirect_request_called() const { | |
| 140 return will_redirect_request_called_; | |
| 141 } | |
| 142 | |
| 143 // ResourceThrottler implementation: | |
| 144 void WillStartRequest(bool* defer) override { | |
| 145 *defer = defer_request_on_will_start_request_; | |
| 146 } | |
| 147 | |
| 148 void WillStartUsingNetwork(bool* defer) override { | |
| 149 *defer = defer_request_on_will_start_using_network_; | |
| 150 } | |
| 151 | |
| 152 void WillRedirectRequest(const net::RedirectInfo& redirect_info, | |
| 153 bool* defer) override { | |
| 154 will_redirect_request_called_ = true; | |
| 155 } | |
| 156 | |
| 157 void WillProcessResponse(bool* defer) override { | |
| 158 *defer = defer_request_on_will_process_response_; | |
| 159 } | |
| 160 | |
| 161 // Returns the name of the throttle, as a UTF-8 C-string, for logging | |
| 162 // purposes. nullptr is not allowed. Caller does *not* take ownership of the | |
|
Bence
2015/11/17 13:12:22
Optional: consider writing |nullptr| to mitigate t
Adam Rice
2015/11/17 17:45:52
It appears for some reason I copied this comment v
Bence
2015/11/17 21:34:28
That would also be fine with me
| |
| 163 // returned string. | |
| 164 const char* GetNameForLogging() const override { | |
| 165 return "ResourceThrottleStub"; | |
| 166 } | |
| 167 | |
| 168 private: | |
| 169 bool defer_request_on_will_start_request_ = false; | |
| 170 bool defer_request_on_will_start_using_network_ = false; | |
| 171 bool will_redirect_request_called_ = false; | |
| 172 bool defer_request_on_will_process_response_ = false; | |
| 173 | |
| 174 DISALLOW_COPY_AND_ASSIGN(ResourceThrottleStub); | |
|
Bence
2015/11/17 13:12:22
Copying and assigning this class seems to be safe
Adam Rice
2015/11/17 17:45:51
I don't want to provide a guarantee that copying i
Bence
2015/11/17 21:34:27
Fair enough.
| |
| 175 }; | |
| 176 | |
| 177 // This class is a variation on URLRequestTestJob that will call | |
| 178 // URLRequest::WillStartUsingNetwork before starting. | |
| 179 class URLRequestTestDelayedNetworkJob : public net::URLRequestTestJob { | |
|
Bence
2015/11/17 13:12:22
This class does not seem to be used anywhere. Ple
Adam Rice
2015/11/17 17:45:52
Ah, sorry, I failed to remove this. The history is
| |
| 180 public: | |
| 181 URLRequestTestDelayedNetworkJob(net::URLRequest* request, | |
| 182 net::NetworkDelegate* network_delegate) | |
| 183 : net::URLRequestTestJob(request, network_delegate, true) {} | |
| 184 | |
| 185 // Only start if not deferred for network start. | |
| 186 void Start() override { | |
| 187 bool defer = false; | |
| 188 NotifyBeforeNetworkStart(&defer); | |
| 189 if (defer) | |
| 190 return; | |
| 191 net::URLRequestTestJob::Start(); | |
|
Bence
2015/11/17 13:12:22
Early returns seems a bit contorted to me. Consid
Adam Rice
2015/11/17 17:45:52
Acknowledged.
| |
| 192 } | |
| 193 | |
| 194 void ResumeNetworkStart() override { net::URLRequestTestJob::StartAsync(); } | |
| 195 | |
| 196 private: | |
| 197 ~URLRequestTestDelayedNetworkJob() override {} | |
| 198 | |
| 199 DISALLOW_COPY_AND_ASSIGN(URLRequestTestDelayedNetworkJob); | |
|
Bence
2015/11/17 13:12:22
Why?
Adam Rice
2015/11/17 17:45:52
I like to be explicit.
| |
| 200 }; | |
| 201 | |
| 202 } // namespace | |
| 203 | |
| 204 class AsyncRevalidationDriverTest : public testing::Test { | |
| 205 protected: | |
| 206 AsyncRevalidationDriverTest() | |
| 207 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), | |
| 208 raw_ptr_resource_throttle_(nullptr), | |
| 209 raw_ptr_to_request_(nullptr) { | |
| 210 test_url_request_context_.set_job_factory(&job_factory_); | |
| 211 } | |
| 212 | |
| 213 GURL test_url() const { return net::URLRequestTestJob::test_url_1(); } | |
| 214 | |
| 215 std::string test_data() const { | |
| 216 return net::URLRequestTestJob::test_data_1(); | |
| 217 } | |
| 218 | |
| 219 bool async_revalidation_complete_called() const { | |
| 220 return async_revalidation_complete_called_; | |
| 221 } | |
| 222 | |
| 223 virtual net::URLRequestJobFactory::ProtocolHandler* CreateProtocolHandler() { | |
| 224 return net::URLRequestTestJob::CreateProtocolHandler(); | |
| 225 } | |
| 226 | |
| 227 void SetUpAsyncRevalidationDriverWithRequest( | |
| 228 scoped_ptr<net::URLRequest> request) { | |
| 229 raw_ptr_to_request_ = request.get(); | |
| 230 | |
| 231 scoped_ptr<ResourceThrottleStub> resource_throttle( | |
|
Bence
2015/11/17 13:12:22
Optional: throw away |resource_throttle| local var
Adam Rice
2015/11/17 17:45:52
Done.
| |
| 232 new ResourceThrottleStub()); | |
| 233 raw_ptr_resource_throttle_ = resource_throttle.get(); | |
| 234 // This use of base::Unretained() is safe because |driver_|, and the closure | |
| 235 // passed to it, will be destroyed before this object is. | |
| 236 driver_.reset(new AsyncRevalidationDriver( | |
| 237 request.Pass(), resource_throttle.Pass(), | |
| 238 base::Bind(&AsyncRevalidationDriverTest::OnAsyncRevalidationComplete, | |
| 239 base::Unretained(this)))); | |
| 240 } | |
| 241 | |
| 242 void SetUp() override { | |
| 243 job_factory_.SetProtocolHandler("test", CreateProtocolHandler()); | |
| 244 | |
| 245 scoped_ptr<net::URLRequest> request(test_url_request_context_.CreateRequest( | |
| 246 test_url(), net::DEFAULT_PRIORITY, nullptr /* delegate */)); | |
| 247 SetUpAsyncRevalidationDriverWithRequest(request.Pass()); | |
| 248 } | |
| 249 | |
| 250 void OnAsyncRevalidationComplete() { | |
| 251 EXPECT_FALSE(async_revalidation_complete_called_); | |
| 252 async_revalidation_complete_called_ = true; | |
| 253 } | |
| 254 | |
| 255 TestBrowserThreadBundle thread_bundle_; | |
| 256 net::URLRequestJobFactoryImpl job_factory_; | |
| 257 net::TestURLRequestContext test_url_request_context_; | |
| 258 | |
| 259 // The AsyncRevalidationDriver owns the URLRequest and the ResourceThrottle. | |
| 260 ResourceThrottleStub* raw_ptr_resource_throttle_; | |
| 261 net::URLRequest* raw_ptr_to_request_; | |
|
Bence
2015/11/17 13:12:22
Please harmonise prefix: raw_ptr_ or raw_ptr_to_ f
Adam Rice
2015/11/17 17:45:52
Done.
| |
| 262 scoped_ptr<AsyncRevalidationDriver> driver_; | |
| 263 bool async_revalidation_complete_called_ = false; | |
| 264 }; | |
| 265 | |
| 266 TEST_F(AsyncRevalidationDriverTest, NormalRequestCompletes) { | |
| 267 driver_->StartRequest(); | |
| 268 base::RunLoop().RunUntilIdle(); | |
| 269 EXPECT_TRUE(async_revalidation_complete_called()); | |
| 270 } | |
| 271 | |
| 272 class AsyncRevalidationDriverClientCertTest | |
| 273 : public AsyncRevalidationDriverTest { | |
| 274 net::URLRequestJobFactory::ProtocolHandler* CreateProtocolHandler() override { | |
| 275 return new MockClientCertJobProtocolHandler(); | |
| 276 } | |
| 277 }; | |
| 278 | |
| 279 // Verifies that async revalidation requests do not attempt to provide client | |
| 280 // certificates. | |
| 281 TEST_F(AsyncRevalidationDriverClientCertTest, RequestRejected) { | |
| 282 scoped_ptr<net::URLRequest> request(test_url_request_context_.CreateRequest( | |
| 283 test_url(), net::LOW, nullptr /* delegate */)); | |
| 284 | |
| 285 SetUpAsyncRevalidationDriverWithRequest(request.Pass()); | |
| 286 | |
| 287 // Start the request and wait for it to pause. | |
| 288 driver_->StartRequest(); | |
| 289 base::RunLoop().RunUntilIdle(); | |
| 290 | |
| 291 // Check that SelectClientCertificate wasn't called and the request aborted. | |
| 292 const net::URLRequestStatus& status = raw_ptr_to_request_->status(); | |
| 293 EXPECT_FALSE(status.is_success()); | |
| 294 EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, status.error()); | |
| 295 EXPECT_TRUE(async_revalidation_complete_called()); | |
| 296 } | |
| 297 | |
| 298 class AsyncRevalidationDriverSSLErrorTest : public AsyncRevalidationDriverTest { | |
| 299 net::URLRequestJobFactory::ProtocolHandler* CreateProtocolHandler() override { | |
| 300 return new MockSSLErrorJobProtocolHandler(); | |
| 301 } | |
| 302 }; | |
| 303 | |
| 304 // Verifies that async revalidation requests do not attempt to recover from SSL | |
| 305 // certificate errors. | |
| 306 TEST_F(AsyncRevalidationDriverSSLErrorTest, RequestWithSSLErrorRejected) { | |
| 307 scoped_ptr<net::URLRequest> request(test_url_request_context_.CreateRequest( | |
| 308 test_url(), net::LOW, nullptr /* delegate */)); | |
| 309 | |
| 310 SetUpAsyncRevalidationDriverWithRequest(request.Pass()); | |
| 311 | |
| 312 // Start the request and wait for it to pause. | |
| 313 driver_->StartRequest(); | |
| 314 base::RunLoop().RunUntilIdle(); | |
| 315 | |
| 316 // Check that the request has been aborted. | |
| 317 const net::URLRequestStatus& status = raw_ptr_to_request_->status(); | |
| 318 EXPECT_FALSE(status.is_success()); | |
| 319 EXPECT_EQ(net::ERR_ABORTED, status.error()); | |
| 320 EXPECT_TRUE(async_revalidation_complete_called()); | |
| 321 } | |
| 322 | |
| 323 // Verifies that resuming a cancelled request does not start it again. | |
| 324 TEST_F(AsyncRevalidationDriverTest, ResumeCancelledRequest) { | |
| 325 raw_ptr_resource_throttle_->set_defer_request_on_will_start_request(true); | |
| 326 | |
| 327 driver_->StartRequest(); | |
| 328 driver_->CancelRequest(); | |
| 329 implicit_cast<ResourceController*>(driver_.get())->Resume(); | |
|
Bence
2015/11/17 13:12:22
Please do not do implicit_cast, because it is used
Adam Rice
2015/11/17 17:45:52
Also, since I wrote this I accidentally got implic
| |
| 330 base::RunLoop().RunUntilIdle(); | |
| 331 EXPECT_TRUE(async_revalidation_complete_called()); | |
| 332 EXPECT_FALSE(raw_ptr_to_request_->status().is_success()); | |
| 333 } | |
| 334 | |
| 335 // Verify that a cancelled request calls |completion_callback|. | |
| 336 TEST_F(AsyncRevalidationDriverTest, CancelledRequestCallsCompleteCallback) { | |
| 337 driver_->StartRequest(); | |
| 338 driver_->CancelRequest(); | |
| 339 base::RunLoop().RunUntilIdle(); | |
| 340 EXPECT_TRUE(async_revalidation_complete_called()); | |
| 341 } | |
| 342 | |
| 343 // Verifies that request that should be deferred at start is deferred. | |
| 344 TEST_F(AsyncRevalidationDriverTest, DeferOnStart) { | |
| 345 raw_ptr_resource_throttle_->set_defer_request_on_will_start_request(true); | |
| 346 | |
| 347 driver_->StartRequest(); | |
| 348 base::RunLoop().RunUntilIdle(); | |
| 349 EXPECT_FALSE(raw_ptr_to_request_->is_pending()); | |
| 350 EXPECT_FALSE(async_revalidation_complete_called()); | |
| 351 } | |
| 352 | |
| 353 // Verifies that redirects are not followed. | |
| 354 TEST_F(AsyncRevalidationDriverTest, RedirectsAreNotFollowed) { | |
| 355 scoped_ptr<net::URLRequest> request(test_url_request_context_.CreateRequest( | |
| 356 net::URLRequestTestJob::test_url_redirect_to_url_2(), | |
| 357 net::DEFAULT_PRIORITY, nullptr /* delegate */)); | |
| 358 SetUpAsyncRevalidationDriverWithRequest(request.Pass()); | |
| 359 | |
| 360 driver_->StartRequest(); | |
| 361 while (net::URLRequestTestJob::ProcessOnePendingMessage()) | |
| 362 base::RunLoop().RunUntilIdle(); | |
| 363 base::RunLoop().RunUntilIdle(); | |
| 364 const net::URLRequestStatus& status = raw_ptr_to_request_->status(); | |
| 365 EXPECT_FALSE(status.is_success()); | |
| 366 EXPECT_EQ(net::ERR_ABORTED, status.error()); | |
| 367 EXPECT_TRUE(async_revalidation_complete_called()); | |
| 368 } | |
| 369 | |
| 370 // A URLRequestTestJob that sets |request_time| and |was_cached| on their | |
| 371 // response_info, and causes the test to fail if Read() is called. | |
| 372 class FromCacheURLRequestJob : public net::URLRequestTestJob { | |
| 373 public: | |
| 374 FromCacheURLRequestJob(net::URLRequest* request, | |
| 375 net::NetworkDelegate* network_delegate) | |
| 376 : net::URLRequestTestJob(request, network_delegate, true) {} | |
| 377 | |
| 378 void GetResponseInfo(net::HttpResponseInfo* info) override { | |
| 379 URLRequestTestJob::GetResponseInfo(info); | |
| 380 info->request_time = base::Time::Now(); | |
| 381 info->was_cached = true; | |
| 382 } | |
| 383 | |
| 384 bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override { | |
| 385 ADD_FAILURE() << "ReadRawData() was called"; | |
| 386 return URLRequestTestJob::ReadRawData(buf, buf_size, bytes_read); | |
| 387 } | |
| 388 | |
| 389 private: | |
| 390 ~FromCacheURLRequestJob() override {} | |
| 391 | |
| 392 DISALLOW_COPY_AND_ASSIGN(FromCacheURLRequestJob); | |
|
Bence
2015/11/17 13:12:22
Why bother?
Adam Rice
2015/11/17 17:45:52
It seems like the right thing to do.
Bence
2015/11/17 21:34:27
Okay then.
| |
| 393 }; | |
| 394 | |
| 395 class FromCacheProtocolHandler | |
| 396 : public net::URLRequestJobFactory::ProtocolHandler { | |
| 397 public: | |
| 398 // URLRequestJobFactory::ProtocolHandler implementation: | |
| 399 net::URLRequestJob* MaybeCreateJob( | |
| 400 net::URLRequest* request, | |
| 401 net::NetworkDelegate* network_delegate) const override { | |
| 402 return new FromCacheURLRequestJob(request, network_delegate); | |
| 403 } | |
| 404 }; | |
| 405 | |
| 406 class AsyncRevalidationDriverFromCacheTest | |
| 407 : public AsyncRevalidationDriverTest { | |
| 408 net::URLRequestJobFactory::ProtocolHandler* CreateProtocolHandler() override { | |
| 409 return new FromCacheProtocolHandler(); | |
| 410 } | |
| 411 }; | |
| 412 | |
| 413 TEST_F(AsyncRevalidationDriverFromCacheTest, | |
| 414 CacheNotReadOnSuccessfulRevalidation) { | |
| 415 scoped_ptr<net::URLRequest> request(test_url_request_context_.CreateRequest( | |
| 416 test_url(), net::LOW, nullptr /* delegate */)); | |
| 417 | |
| 418 SetUpAsyncRevalidationDriverWithRequest(request.Pass()); | |
| 419 | |
| 420 driver_->StartRequest(); | |
| 421 base::RunLoop().RunUntilIdle(); | |
| 422 | |
| 423 EXPECT_TRUE(async_revalidation_complete_called()); | |
| 424 } | |
| 425 | |
| 426 } // namespace content | |
| OLD | NEW |