disk_based_cert_cache_unittest.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
1// Copyright (c) 2014 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 "net/http/disk_based_cert_cache.h" 6 7#include "base/bind.h" 8#include "base/callback_helpers.h" 9#include "net/base/completion_callback.h" 10#include "net/base/io_buffer.h" 11#include "net/base/net_errors.h" 12#include "net/base/test_completion_callback.h" 13#include "net/base/test_data_directory.h" 14#include "net/disk_cache/memory/mem_backend_impl.h" 15#include "net/http/mock_http_cache.h" 16#include "net/test/cert_test_util.h" 17#include "testing/gtest/include/gtest/gtest.h" 18 19namespace net { 20 21namespace { 22 23// Testing the DiskBasedCertCache requires constant use of the 24// certificates in GetTestCertsDirectory(). The TestCertMetaData 25// struct stores metadata relevant to the DiskBasedCertCache for 26// each used test certificate. 27struct TestCertMetaData { 28 const char* file_name; 29 const char* cache_key; 30}; 31 32const TestCertMetaData kCert1 = { 33 "root_ca_cert.pem", "cert:4C005EF1CF45F80D4A5A2BCFB00D4F198121E8D4"}; 34 35const TestCertMetaData kCert2 = { 36 "ok_cert.pem", "cert:9174C7CB9E4919604E7B1BFC430E4929DA45F65F"}; 37 38// MockTransactions are required to use the MockDiskCache backend. 39// |key| is a cache key, and is equivalent to the key that will be 40// used to store or retrieve certificates in the cache. |test_mode| 41// is an integer that is used to indicate properties of the test 42// transaction, mostly whether or not it is synchronous. 43// For testing the DiskBasedCertCache, other data members of the struct 44// are irrelevant. Only one MockTransaction per certificate can be used 45// at a time. 46MockTransaction CreateMockTransaction(const char* key, int test_mode) { 47 MockTransaction transaction = {key, "", base::Time(), "", LOAD_NORMAL, 48 "", "", base::Time(), "", test_mode, 49 NULL, 0, OK}; 50 51 return transaction; 52} 53 54// Helper class, for use with DiskBasedCertCache::GetCertificate, that will 55// store the returned certificate handle and allow users to WaitForResult of 56// DiskBasedCertCache::GetCertificate. 57class TestGetCallback { 58 public: 59 TestGetCallback() : cert_handle_(NULL) {} 60 ~TestGetCallback() { 61 if (cert_handle_) 62 X509Certificate::FreeOSCertHandle(cert_handle_); 63 } 64 65 // Blocks until the underlying GetCertificate() operation has succeeded. 66 void WaitForResult() { cb_.WaitForResult(); } 67 68 // Returns a Callback suitable for use with 69 // DiskBasedCertCache::GetCertificate(). The returned callback is only valid 70 // while the TestGetCallback object is still valid. 71 DiskBasedCertCache::GetCallback callback() { 72 return base::Bind(&TestGetCallback::OnGetComplete, base::Unretained(this)); 73 } 74 75 // Returns the associated certificate handle. 76 const X509Certificate::OSCertHandle& cert_handle() const { 77 return cert_handle_; 78 } 79 80 private: 81 void OnGetComplete(const X509Certificate::OSCertHandle handle) { 82 if (handle) 83 cert_handle_ = X509Certificate::DupOSCertHandle(handle); 84 cb_.callback().Run(OK); 85 } 86 87 TestCompletionCallback cb_; 88 X509Certificate::OSCertHandle cert_handle_; 89}; 90 91// Helper class, for use with DiskBasedCertCache::SetCertificate, that will 92// store the returned key and allow a user to WaitForResult of 93// DiskBasedCertCache::SetCertificate. 94class TestSetCallback { 95 public: 96 TestSetCallback() {} 97 ~TestSetCallback() {} 98 99 // Blocks until the underlying SetCertificate() operation has succeeded. 100 void WaitForResult() { cb_.WaitForResult(); } 101 102 // Returns a Callback suitable for use with 103 // DiskBasedCertCache::SetCertificate(). The returned callback is only valid 104 // while the TestSetCallback object is still valid. 105 DiskBasedCertCache::SetCallback callback() { 106 return base::Bind(&TestSetCallback::OnSetComplete, base::Unretained(this)); 107 } 108 109 // Returns the associated certificate handle. 110 const std::string& key() const { return key_; } 111 112 private: 113 void OnSetComplete(const std::string& key) { 114 key_ = key; 115 cb_.callback().Run(OK); 116 } 117 118 TestCompletionCallback cb_; 119 std::string key_; 120}; 121 122// Stores the certificate corresponding to |cert_data| in |backend|. If 123// |corrupt_data| is true, the certificate will be imported with errors 124// so as to mimic a corrupted file on disk. 125void ImportCert(disk_cache::Backend* backend, 126 const TestCertMetaData& cert_data, 127 bool corrupt_data) { 128 disk_cache::Entry* entry; 129 TestCompletionCallback callback; 130 int rv = 131 backend->CreateEntry(cert_data.cache_key, &entry, callback.callback()); 132 EXPECT_EQ(OK, callback.GetResult(rv)); 133 scoped_refptr<X509Certificate> cert( 134 ImportCertFromFile(GetTestCertsDirectory(), cert_data.file_name)); 135 std::string write_data; 136 bool encoded = 137 X509Certificate::GetDEREncoded(cert->os_cert_handle(), &write_data); 138 ASSERT_TRUE(encoded); 139 if (corrupt_data) { 140 for (size_t i = 0; i < write_data.size(); i += 20) 141 ++write_data[i]; 142 } 143 scoped_refptr<IOBuffer> buffer(new IOBuffer(write_data.size())); 144 memcpy(buffer->data(), write_data.data(), write_data.size()); 145 rv = entry->WriteData(0 /* index */, 146 0 /* offset */, 147 buffer, 148 write_data.size(), 149 callback.callback(), 150 true /* truncate */); 151 ASSERT_EQ(static_cast<int>(write_data.size()), callback.GetResult(rv)); 152 entry->Close(); 153} 154 155// Checks that the the certificate corresponding to |cert_data| is an existing, 156// correctly cached entry in |backend|. 157void CheckCertCached(disk_cache::Backend* backend, 158 const TestCertMetaData& cert_data) { 159 disk_cache::Entry* entry; 160 TestCompletionCallback callback; 161 int rv = backend->OpenEntry(cert_data.cache_key, &entry, callback.callback()); 162 EXPECT_EQ(OK, callback.GetResult(rv)); 163 scoped_refptr<X509Certificate> cert( 164 ImportCertFromFile(GetTestCertsDirectory(), cert_data.file_name)); 165 std::string write_data; 166 bool encoded = 167 X509Certificate::GetDEREncoded(cert->os_cert_handle(), &write_data); 168 ASSERT_TRUE(encoded); 169 int entry_size = entry->GetDataSize(0 /* index */); 170 scoped_refptr<IOBuffer> buffer(new IOBuffer(entry_size)); 171 rv = entry->ReadData( 172 0 /* index */, 0 /* offset */, buffer, entry_size, callback.callback()); 173 EXPECT_EQ(entry_size, callback.GetResult(rv)); 174 entry->Close(); 175 X509Certificate::OSCertHandle cached_cert_handle = 176 X509Certificate::CreateOSCertHandleFromBytes(buffer->data(), entry_size); 177 EXPECT_TRUE(X509Certificate::IsSameOSCert(cached_cert_handle, 178 cert->os_cert_handle())); 179 X509Certificate::FreeOSCertHandle(cached_cert_handle); 180} 181 182} // namespace 183 184// ---------------------------------------------------------------------------- 185 186// Tests that a certificate can be stored in the cache. 187TEST(DiskBasedCertCache, SetCert) { 188 ScopedMockTransaction trans1( 189 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 190 MockDiskCache backend; 191 DiskBasedCertCache cache(&backend); 192 scoped_refptr<X509Certificate> cert( 193 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 194 ASSERT_TRUE(cert.get()); 195 TestSetCallback set_callback; 196 197 cache.SetCertificate(cert->os_cert_handle(), set_callback.callback()); 198 set_callback.WaitForResult(); 199 EXPECT_EQ(kCert1.cache_key, set_callback.key()); 200 ASSERT_NO_FATAL_FAILURE(CheckCertCached(&backend, kCert1)); 201} 202 203// Tests that a certificate can be retrieved from the cache. 204TEST(DiskBasedCertCache, GetCert) { 205 ScopedMockTransaction trans1( 206 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 207 MockDiskCache backend; 208 ASSERT_NO_FATAL_FAILURE( 209 ImportCert(&backend, kCert1, false /* not corrupted */)); 210 DiskBasedCertCache cache(&backend); 211 TestGetCallback get_callback; 212 213 cache.GetCertificate(kCert1.cache_key, get_callback.callback()); 214 get_callback.WaitForResult(); 215 216 scoped_refptr<X509Certificate> cert( 217 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 218 EXPECT_TRUE(X509Certificate::IsSameOSCert(get_callback.cert_handle(), 219 cert->os_cert_handle())); 220} 221 222// Tests that the DiskBasedCertCache successfully writes to the cache 223// if the cache acts synchronously 224TEST(DiskBasedCertCache, SyncSet) { 225 ScopedMockTransaction trans1( 226 CreateMockTransaction(kCert1.cache_key, TEST_MODE_SYNC_ALL)); 227 MockDiskCache backend; 228 DiskBasedCertCache cache(&backend); 229 scoped_refptr<X509Certificate> cert( 230 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 231 ASSERT_TRUE(cert.get()); 232 233 TestSetCallback set_callback; 234 cache.SetCertificate(cert->os_cert_handle(), set_callback.callback()); 235 set_callback.WaitForResult(); 236 EXPECT_EQ(kCert1.cache_key, set_callback.key()); 237 ASSERT_NO_FATAL_FAILURE(CheckCertCached(&backend, kCert1)); 238} 239 240// Tests that the DiskBasedCertCache successfully reads from the cache 241// if the cache acts synchronously 242TEST(DiskBasedCertCache, SyncGet) { 243 ScopedMockTransaction trans1( 244 CreateMockTransaction(kCert1.cache_key, TEST_MODE_SYNC_ALL)); 245 MockDiskCache backend; 246 ASSERT_NO_FATAL_FAILURE( 247 (ImportCert(&backend, kCert1, false /* not corrupted */))); 248 DiskBasedCertCache cache(&backend); 249 scoped_refptr<X509Certificate> cert( 250 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 251 ASSERT_TRUE(cert.get()); 252 253 TestGetCallback get_callback; 254 cache.GetCertificate(kCert1.cache_key, get_callback.callback()); 255 get_callback.WaitForResult(); 256 EXPECT_TRUE(X509Certificate::IsSameOSCert(get_callback.cert_handle(), 257 cert->os_cert_handle())); 258} 259 260// Tests that GetCertificate will fail on a corrupted certificate. 261TEST(DiskBasedCertCache, GetBrokenCert) { 262 ScopedMockTransaction trans1( 263 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 264 MockDiskCache backend; 265 ASSERT_NO_FATAL_FAILURE(ImportCert(&backend, kCert1, true /* corrupted */)); 266 DiskBasedCertCache cache(&backend); 267 TestGetCallback get_callback; 268 269 cache.GetCertificate(kCert1.cache_key, get_callback.callback()); 270 get_callback.WaitForResult(); 271 272 EXPECT_FALSE(get_callback.cert_handle()); 273} 274 275// Tests that attempting to retrieve a cert that is not in the cache will 276// return NULL. 277TEST(DiskBasedCertCache, GetUncachedCert) { 278 ScopedMockTransaction trans1( 279 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 280 MockDiskCache backend; 281 DiskBasedCertCache cache(&backend); 282 TestGetCallback get_callback; 283 284 cache.GetCertificate(kCert1.cache_key, get_callback.callback()); 285 get_callback.WaitForResult(); 286 EXPECT_EQ(NULL, get_callback.cert_handle()); 287} 288 289// Issues two requests to store a certificate in the cache 290// (simultaneously), and checks that the DiskBasedCertCache stores the 291// certificate to the cache (in one write rather than two). 292TEST(DiskBasedCertCache, SetMultiple) { 293 ScopedMockTransaction trans1( 294 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 295 MockDiskCache backend; 296 DiskBasedCertCache cache(&backend); 297 scoped_refptr<X509Certificate> cert( 298 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 299 ASSERT_TRUE(cert.get()); 300 TestSetCallback set_callback1, set_callback2; 301 302 // Behind the scenes, these two operations will be combined 303 // into one operation. IgnoreCallbacks guarantees that the 304 // first SetCertificate operation is not yet complete when the second 305 // SetCertificate is called, and then IgnoreCallbacks(false) continues the 306 // (combined) operation in the |cache|. 307 MockDiskEntry::IgnoreCallbacks(true); 308 cache.SetCertificate(cert->os_cert_handle(), set_callback1.callback()); 309 cache.SetCertificate(cert->os_cert_handle(), set_callback2.callback()); 310 MockDiskEntry::IgnoreCallbacks(false); 311 312 set_callback1.WaitForResult(); 313 set_callback2.WaitForResult(); 314 EXPECT_EQ(set_callback1.key(), set_callback2.key()); 315 ASSERT_NO_FATAL_FAILURE(CheckCertCached(&backend, kCert1)); 316} 317 318// Issues two requests to store a certificate in the cache 319// because the first transaction finishes before the second 320// one is issued, the first cache write is overwritten. 321TEST(DiskBasedCertCache, SetOverwrite) { 322 ScopedMockTransaction trans1( 323 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 324 MockDiskCache backend; 325 backend.set_double_create_check(false); 326 DiskBasedCertCache cache(&backend); 327 scoped_refptr<X509Certificate> cert( 328 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 329 ASSERT_TRUE(cert.get()); 330 TestSetCallback set_callback1, set_callback2; 331 332 cache.SetCertificate(cert->os_cert_handle(), set_callback1.callback()); 333 set_callback1.WaitForResult(); 334 cache.SetCertificate(cert->os_cert_handle(), set_callback2.callback()); 335 set_callback2.WaitForResult(); 336 337 EXPECT_EQ(set_callback1.key(), set_callback2.key()); 338 ASSERT_NO_FATAL_FAILURE(CheckCertCached(&backend, kCert1)); 339} 340 341// Stores a certificate in the DiskBasedCertCache, then retrieves it 342// and makes sure it was retrieved successfully. 343TEST(DiskBasedCertCache, SimpleSetAndGet) { 344 ScopedMockTransaction trans1( 345 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 346 MockDiskCache backend; 347 DiskBasedCertCache cache(&backend); 348 scoped_refptr<X509Certificate> cert( 349 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 350 ASSERT_TRUE(cert.get()); 351 TestSetCallback set_callback; 352 TestGetCallback get_callback; 353 354 cache.SetCertificate(cert->os_cert_handle(), set_callback.callback()); 355 set_callback.WaitForResult(); 356 cache.GetCertificate(set_callback.key(), get_callback.callback()); 357 get_callback.WaitForResult(); 358 EXPECT_TRUE(X509Certificate::IsSameOSCert(get_callback.cert_handle(), 359 cert->os_cert_handle())); 360} 361 362// Tests some basic functionality of the DiskBasedCertCache, with multiple 363// set and get operations. 364TEST(DiskBasedCertCache, BasicUsage) { 365 ScopedMockTransaction trans1( 366 CreateMockTransaction(kCert1.cache_key, TEST_MODE_SYNC_CACHE_START)); 367 ScopedMockTransaction trans2( 368 CreateMockTransaction(kCert2.cache_key, TEST_MODE_NORMAL)); 369 MockDiskCache backend; 370 DiskBasedCertCache cache(&backend); 371 scoped_refptr<X509Certificate> cert1( 372 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 373 scoped_refptr<X509Certificate> cert2( 374 ImportCertFromFile(GetTestCertsDirectory(), kCert2.file_name)); 375 ASSERT_TRUE(cert1.get()); 376 ASSERT_TRUE(cert2.get()); 377 ASSERT_FALSE(X509Certificate::IsSameOSCert(cert1->os_cert_handle(), 378 cert2->os_cert_handle())); 379 TestSetCallback set_callback1, set_callback2; 380 381 // Callbacks are temporarily ignored here to guarantee the asynchronous 382 // operations of the DiskBasedCertCache are always executed in the same 383 // order. 384 MockDiskEntry::IgnoreCallbacks(true); 385 cache.SetCertificate(cert1->os_cert_handle(), set_callback1.callback()); 386 cache.SetCertificate(cert2->os_cert_handle(), set_callback2.callback()); 387 MockDiskEntry::IgnoreCallbacks(false); 388 set_callback1.WaitForResult(); 389 set_callback2.WaitForResult(); 390 391 TestGetCallback get_callback1, get_callback2; 392 393 MockDiskEntry::IgnoreCallbacks(true); 394 cache.GetCertificate(set_callback1.key(), get_callback1.callback()); 395 cache.GetCertificate(set_callback2.key(), get_callback2.callback()); 396 MockDiskEntry::IgnoreCallbacks(false); 397 get_callback1.WaitForResult(); 398 get_callback2.WaitForResult(); 399 400 EXPECT_TRUE(X509Certificate::IsSameOSCert(cert1->os_cert_handle(), 401 get_callback1.cert_handle())); 402 EXPECT_TRUE(X509Certificate::IsSameOSCert(cert2->os_cert_handle(), 403 get_callback2.cert_handle())); 404} 405 406// Test the result of simultaneous requests to store and retrieve a 407// certificate from the cache, with the get operation attempting to 408// open the cache first and therefore failing to open the entry. 409TEST(DiskBasedCertCache, SimultaneousGetSet) { 410 ScopedMockTransaction trans1( 411 CreateMockTransaction(kCert1.cache_key, TEST_MODE_SYNC_CACHE_START)); 412 MockDiskCache backend; 413 DiskBasedCertCache cache(&backend); 414 scoped_refptr<X509Certificate> cert( 415 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 416 ASSERT_TRUE(cert.get()); 417 418 TestGetCallback get_callback; 419 TestSetCallback set_callback; 420 421 MockDiskEntry::IgnoreCallbacks(true); 422 cache.GetCertificate(kCert1.cache_key, get_callback.callback()); 423 cache.SetCertificate(cert->os_cert_handle(), set_callback.callback()); 424 MockDiskEntry::IgnoreCallbacks(false); 425 get_callback.WaitForResult(); 426 set_callback.WaitForResult(); 427 428 EXPECT_EQ(NULL, get_callback.cert_handle()); 429 EXPECT_EQ(kCert1.cache_key, set_callback.key()); 430} 431 432// Test the result of simultaneous requests to store and retrieve a 433// certificate from the cache, with the get operation opening the cache 434// after the set operation, leading to a successful read. 435TEST(DiskBasedCertCache, SimultaneousSetGet) { 436 ScopedMockTransaction trans1( 437 CreateMockTransaction(kCert1.cache_key, TEST_MODE_SYNC_CACHE_START)); 438 MockDiskCache backend; 439 DiskBasedCertCache cache(&backend); 440 scoped_refptr<X509Certificate> cert( 441 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 442 ASSERT_TRUE(cert.get()); 443 444 TestSetCallback set_callback; 445 TestGetCallback get_callback; 446 447 MockDiskEntry::IgnoreCallbacks(true); 448 cache.SetCertificate(cert->os_cert_handle(), set_callback.callback()); 449 cache.GetCertificate(kCert1.cache_key, get_callback.callback()); 450 MockDiskEntry::IgnoreCallbacks(false); 451 set_callback.WaitForResult(); 452 get_callback.WaitForResult(); 453 454 EXPECT_EQ(kCert1.cache_key, set_callback.key()); 455 EXPECT_TRUE(X509Certificate::IsSameOSCert(cert->os_cert_handle(), 456 get_callback.cert_handle())); 457} 458 459// Tests that the DiskBasedCertCache can be deleted without issues when 460// there are pending operations in the disk cache. 461TEST(DiskBasedCertCache, DeletedCertCache) { 462 ScopedMockTransaction trans1( 463 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 464 MockDiskCache backend; 465 scoped_ptr<DiskBasedCertCache> cache(new DiskBasedCertCache(&backend)); 466 scoped_refptr<X509Certificate> cert( 467 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 468 ASSERT_TRUE(cert.get()); 469 TestSetCallback set_callback; 470 471 cache->SetCertificate(cert->os_cert_handle(), set_callback.callback()); 472 cache.reset(); 473 set_callback.WaitForResult(); 474 EXPECT_EQ(std::string(), set_callback.key()); 475} 476 477// Issues two successive read requests for a certificate, and then 478// checks that the DiskBasedCertCache correctly read and recorded 479// reading through the in-memory MRU cache. 480TEST(DiskBasedCertCache, MemCacheGet) { 481 ScopedMockTransaction trans1( 482 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 483 MockDiskCache backend; 484 ASSERT_NO_FATAL_FAILURE( 485 ImportCert(&backend, kCert1, false /* not corrupted */)); 486 DiskBasedCertCache cache(&backend); 487 488 TestGetCallback get_callback1, get_callback2; 489 cache.GetCertificate(kCert1.cache_key, get_callback1.callback()); 490 get_callback1.WaitForResult(); 491 EXPECT_EQ(0U, cache.mem_cache_hits_for_testing()); 492 cache.GetCertificate(kCert1.cache_key, get_callback2.callback()); 493 get_callback2.WaitForResult(); 494 EXPECT_EQ(1U, cache.mem_cache_hits_for_testing()); 495 EXPECT_TRUE(X509Certificate::IsSameOSCert(get_callback1.cert_handle(), 496 get_callback2.cert_handle())); 497} 498 499// Reads a corrupted certificate from the disk cache, and then overwrites 500// it and checks that the uncorrupted version was stored in the in-memory 501// cache. 502TEST(DiskBasedCertCache, CorruptOverwrite) { 503 ScopedMockTransaction trans1( 504 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 505 MockDiskCache backend; 506 backend.set_double_create_check(false); 507 ASSERT_NO_FATAL_FAILURE(ImportCert(&backend, kCert1, true /* corrupted */)); 508 DiskBasedCertCache cache(&backend); 509 TestGetCallback get_callback1, get_callback2; 510 511 cache.GetCertificate(kCert1.cache_key, get_callback1.callback()); 512 get_callback1.WaitForResult(); 513 EXPECT_FALSE(get_callback2.cert_handle()); 514 515 scoped_refptr<X509Certificate> cert( 516 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 517 TestSetCallback set_callback; 518 519 cache.SetCertificate(cert->os_cert_handle(), set_callback.callback()); 520 set_callback.WaitForResult(); 521 EXPECT_EQ(kCert1.cache_key, set_callback.key()); 522 EXPECT_EQ(0U, cache.mem_cache_hits_for_testing()); 523 524 cache.GetCertificate(kCert1.cache_key, get_callback2.callback()); 525 get_callback2.WaitForResult(); 526 EXPECT_TRUE(X509Certificate::IsSameOSCert(get_callback2.cert_handle(), 527 cert->os_cert_handle())); 528 EXPECT_EQ(1U, cache.mem_cache_hits_for_testing()); 529 ASSERT_NO_FATAL_FAILURE(CheckCertCached(&backend, kCert1)); 530} 531 532} // namespace net 533