Index: net/cert/internal/trust_store_collection_unittest.cc |
diff --git a/net/cert/internal/trust_store_collection_unittest.cc b/net/cert/internal/trust_store_collection_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4b19bf10d03a6d52a7461d23662c448296d5c172 |
--- /dev/null |
+++ b/net/cert/internal/trust_store_collection_unittest.cc |
@@ -0,0 +1,261 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "net/cert/internal/trust_store_collection.h" |
+ |
+#include "base/bind.h" |
+#include "base/run_loop.h" |
+#include "net/cert/internal/parsed_certificate.h" |
+#include "net/cert/internal/test_helpers.h" |
+#include "net/cert/internal/trust_store_static.h" |
+#include "net/cert/internal/trust_store_test_helpers.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace net { |
+ |
+namespace { |
+ |
+::testing::AssertionResult ReadTestPem(const std::string& file_name, |
+ const std::string& block_name, |
+ std::string* result) { |
+ const PemBlockMapping mappings[] = { |
+ {block_name.c_str(), result}, |
+ }; |
+ |
+ return ReadTestDataFromPemFile(file_name, mappings); |
+} |
+ |
+::testing::AssertionResult ReadTestCert( |
+ const std::string& file_name, |
+ scoped_refptr<ParsedCertificate>* result) { |
+ std::string der; |
+ ::testing::AssertionResult r = ReadTestPem( |
+ "net/data/ssl/certificates/" + file_name, "CERTIFICATE", &der); |
+ if (!r) |
+ return r; |
+ *result = ParsedCertificate::CreateFromCertificateCopy(der, {}); |
+ if (!*result) |
+ return ::testing::AssertionFailure() << "CreateFromCertificateCopy failed"; |
+ return ::testing::AssertionSuccess(); |
+} |
+ |
+void NotCalled(bool) { |
+ FAIL(); |
+} |
+ |
+// If all the stores in the collection return trust results synchronously, the |
+// TrustStoreCollection itself should also return synchronously. |
+TEST(TrustStoreCollection, StaticResultTrusted) { |
+ scoped_refptr<ParsedCertificate> cert; |
+ ASSERT_TRUE(ReadTestCert("root_ca_cert.pem", &cert)); |
+ |
+ TrustStoreCollection trust_store_collection; |
+ TrustStoreStatic trust_store1; |
+ TrustStoreStatic trust_store2; |
+ trust_store1.AddTrustedCertificate(cert); |
+ trust_store2.AddTrustedCertificate(cert); |
+ trust_store_collection.AddStore(&trust_store1); |
+ trust_store_collection.AddStore(&trust_store2); |
+ |
+ bool trusted = false; |
+ std::unique_ptr<TrustStore::Request> request; |
+ trust_store_collection.IsTrustedCertificate(cert, base::Bind(&NotCalled), |
+ &trusted, &request); |
+ EXPECT_FALSE(request); |
+ EXPECT_TRUE(trusted); |
+} |
+ |
+// If all the stores in the collection return trust results synchronously, the |
+// TrustStoreCollection itself should also return synchronously. |
+TEST(TrustStoreCollection, StaticResultNotTrusted) { |
+ scoped_refptr<ParsedCertificate> cert; |
+ ASSERT_TRUE(ReadTestCert("root_ca_cert.pem", &cert)); |
+ |
+ TrustStoreCollection trust_store_collection; |
+ TrustStoreStatic trust_store1; |
+ TrustStoreStatic trust_store2; |
+ trust_store_collection.AddStore(&trust_store1); |
+ trust_store_collection.AddStore(&trust_store2); |
+ |
+ bool trusted = true; |
+ std::unique_ptr<TrustStore::Request> request; |
+ trust_store_collection.IsTrustedCertificate(cert, base::Bind(&NotCalled), |
+ &trusted, &request); |
+ EXPECT_FALSE(request); |
+ EXPECT_FALSE(trusted); |
+} |
+ |
+// If a store returns a synchronous trusted result, result should be |
+// synchronous even if there were already async requests started. |
+TEST(TrustStoreCollection, SynchronousTrustedResultTakesPrecedenceOverAsync) { |
+ scoped_refptr<ParsedCertificate> cert; |
+ ASSERT_TRUE(ReadTestCert("root_ca_cert.pem", &cert)); |
+ |
+ TrustStoreCollection trust_store_collection; |
+ AsyncTrustStoreStatic trust_store1; |
+ TrustStoreStatic trust_store2; |
+ trust_store1.AddTrustedCertificate(cert); |
+ trust_store2.AddTrustedCertificate(cert); |
+ trust_store_collection.AddStore(&trust_store1); |
+ trust_store_collection.AddStore(&trust_store2); |
+ |
+ bool trusted = false; |
+ std::unique_ptr<TrustStore::Request> request; |
+ trust_store_collection.IsTrustedCertificate(cert, base::Bind(&NotCalled), |
+ &trusted, &request); |
+ EXPECT_FALSE(request); |
+ EXPECT_TRUE(trusted); |
+} |
+ |
+// If a store returns a synchronous not trusted result and there are other |
+// stores that are async, the result should wait for the async result. |
+TEST(TrustStoreCollection, SynchronousUntrustedResultFallsBackToAsync) { |
+ scoped_refptr<ParsedCertificate> cert; |
+ ASSERT_TRUE(ReadTestCert("root_ca_cert.pem", &cert)); |
+ |
+ TrustStoreCollection trust_store_collection; |
+ AsyncTrustStoreStatic trust_store1; |
+ TrustStoreStatic trust_store2; |
+ trust_store1.AddTrustedCertificate(cert); |
+ trust_store_collection.AddStore(&trust_store1); |
+ trust_store_collection.AddStore(&trust_store2); |
+ |
+ TrustResultRecorder result_recorder; |
+ bool unused_trusted = false; |
+ std::unique_ptr<TrustStore::Request> request; |
+ trust_store_collection.IsTrustedCertificate(cert, result_recorder.Callback(), |
+ &unused_trusted, &request); |
+ EXPECT_FALSE(unused_trusted); |
+ ASSERT_TRUE(request); |
+ EXPECT_TRUE(result_recorder.results().empty()); |
+ result_recorder.Run(); |
+ ASSERT_EQ(1U, result_recorder.results().size()); |
+ EXPECT_TRUE(result_recorder.results()[0]); |
+} |
+ |
+// The callback passed into TrustStoreCollection::IsTrustedCertificate should |
+// only be called once, even if the collection itself issues multiple requests |
+// that would each generate a callback. |
+TEST(TrustStoreCollection, CallbackCalledOnlyOnce) { |
+ scoped_refptr<ParsedCertificate> cert; |
+ ASSERT_TRUE(ReadTestCert("root_ca_cert.pem", &cert)); |
+ |
+ TrustStoreCollection trust_store_collection; |
+ AsyncTrustStoreStatic trust_store1; |
+ AsyncTrustStoreStatic trust_store2; |
+ trust_store1.AddTrustedCertificate(cert); |
+ trust_store2.AddTrustedCertificate(cert); |
+ trust_store_collection.AddStore(&trust_store1); |
+ trust_store_collection.AddStore(&trust_store2); |
+ |
+ TrustResultRecorder result_recorder; |
+ bool unused_trusted = false; |
+ std::unique_ptr<TrustStore::Request> request; |
+ trust_store_collection.IsTrustedCertificate(cert, result_recorder.Callback(), |
+ &unused_trusted, &request); |
+ ASSERT_TRUE(request); |
+ EXPECT_FALSE(unused_trusted); |
+ EXPECT_TRUE(result_recorder.results().empty()); |
+ result_recorder.Run(); |
+ ASSERT_EQ(1U, result_recorder.results().size()); |
+ EXPECT_TRUE(result_recorder.results()[0]); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ ASSERT_EQ(1U, result_recorder.results().size()); |
+} |
+ |
+// If the Request is cancelled, the callback should not be called. |
+TEST(TrustStoreCollection, RequestDeletedBeforeCallback) { |
+ scoped_refptr<ParsedCertificate> cert; |
+ ASSERT_TRUE(ReadTestCert("root_ca_cert.pem", &cert)); |
+ |
+ TrustStoreCollection trust_store_collection; |
+ AsyncTrustStoreStatic trust_store1; |
+ AsyncTrustStoreStatic trust_store2; |
+ trust_store1.AddTrustedCertificate(cert); |
+ trust_store2.AddTrustedCertificate(cert); |
+ trust_store_collection.AddStore(&trust_store1); |
+ trust_store_collection.AddStore(&trust_store2); |
+ |
+ TrustResultRecorder result_recorder; |
+ bool unused_trusted = false; |
+ std::unique_ptr<TrustStore::Request> request; |
+ trust_store_collection.IsTrustedCertificate( |
+ cert, base::Bind(&TrustResultRecorder::HandleResult, |
+ base::Unretained(&result_recorder)), |
+ &unused_trusted, &request); |
+ ASSERT_TRUE(request); |
+ EXPECT_FALSE(unused_trusted); |
+ EXPECT_TRUE(result_recorder.results().empty()); |
+ |
+ request.reset(); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ EXPECT_TRUE(result_recorder.results().empty()); |
+} |
+ |
+// If the Request is cancelled after receiving the result, but while there could |
+// still be sub-Requests pending, make sure nothing crashes. |
+TEST(TrustStoreCollection, RequestDeletedAfterFirstSubCallback) { |
+ scoped_refptr<ParsedCertificate> cert; |
+ ASSERT_TRUE(ReadTestCert("root_ca_cert.pem", &cert)); |
+ |
+ TrustStoreCollection trust_store_collection; |
+ AsyncTrustStoreStatic trust_store1; |
+ AsyncTrustStoreStatic trust_store2; |
+ trust_store1.AddTrustedCertificate(cert); |
+ trust_store2.AddTrustedCertificate(cert); |
+ trust_store_collection.AddStore(&trust_store1); |
+ trust_store_collection.AddStore(&trust_store2); |
+ |
+ TrustResultRecorder result_recorder; |
+ bool unused_trusted = false; |
+ std::unique_ptr<TrustStore::Request> request; |
+ trust_store_collection.IsTrustedCertificate( |
+ cert, base::Bind(&TrustResultRecorder::HandleResult, |
+ base::Unretained(&result_recorder)), |
+ &unused_trusted, &request); |
+ ASSERT_TRUE(request); |
+ EXPECT_FALSE(unused_trusted); |
+ EXPECT_TRUE(result_recorder.results().empty()); |
+ result_recorder.Run(); |
+ ASSERT_EQ(1U, result_recorder.results().size()); |
+ EXPECT_TRUE(result_recorder.results()[0]); |
+ |
+ request.reset(); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ ASSERT_EQ(1U, result_recorder.results().size()); |
+} |
+ |
+// If the Request is cancelled during the callback, shouldn't crash. |
+TEST(TrustStoreCollection, RequestDeletedDuringCallback) { |
+ scoped_refptr<ParsedCertificate> cert; |
+ ASSERT_TRUE(ReadTestCert("root_ca_cert.pem", &cert)); |
+ |
+ TrustStoreCollection trust_store_collection; |
+ AsyncTrustStoreStatic trust_store1; |
+ AsyncTrustStoreStatic trust_store2; |
+ trust_store1.AddTrustedCertificate(cert); |
+ trust_store2.AddTrustedCertificate(cert); |
+ trust_store_collection.AddStore(&trust_store1); |
+ trust_store_collection.AddStore(&trust_store2); |
+ |
+ bool unused_trusted = false; |
+ base::RunLoop run_loop; |
+ std::unique_ptr<TrustStore::Request> request; |
+ trust_store_collection.IsTrustedCertificate( |
+ cert, base::Bind(&TrustRequestDeleter, &request, run_loop.QuitClosure()), |
+ &unused_trusted, &request); |
+ ASSERT_TRUE(request); |
+ run_loop.Run(); |
+ ASSERT_FALSE(request); |
+ base::RunLoop().RunUntilIdle(); |
+} |
+ |
+ |
+} // namespace |
+ |
+} // namespace net |