Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(107)

Unified Diff: components/certificate_transparency/log_dns_client_unittest.cc

Issue 2066553002: Certificate Transparency DNS log client (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mock_dns_responses
Patch Set: Rebase Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « components/certificate_transparency/log_dns_client.cc ('k') | components/components_tests.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: components/certificate_transparency/log_dns_client_unittest.cc
diff --git a/components/certificate_transparency/log_dns_client_unittest.cc b/components/certificate_transparency/log_dns_client_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ebdf757eb656071ee2de1b57b940f641c84d7c81
--- /dev/null
+++ b/components/certificate_transparency/log_dns_client_unittest.cc
@@ -0,0 +1,581 @@
+// 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 "components/certificate_transparency/log_dns_client.h"
+
+#include <algorithm>
+#include <numeric>
+#include <utility>
+#include <vector>
+
+#include "base/big_endian.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/sys_byteorder.h"
+#include "base/test/simple_test_clock.h"
+#include "base/test/test_timeouts.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "crypto/sha2.h"
+#include "net/base/net_errors.h"
+#include "net/cert/merkle_audit_proof.h"
+#include "net/cert/merkle_tree_leaf.h"
+#include "net/cert/signed_certificate_timestamp.h"
+#include "net/dns/dns_client.h"
+#include "net/dns/dns_config_service.h"
+#include "net/dns/dns_protocol.h"
+#include "net/log/test_net_log.h"
+#include "net/socket/socket_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace certificate_transparency {
+namespace {
+
+using ::testing::AllOf;
+using ::testing::DeleteArg;
+using ::testing::IsNull;
+using ::testing::Not;
+using ::testing::Pointee;
+using ::testing::Field;
+using ::testing::SizeIs;
+
+constexpr char kLeafHash[] =
+ "\x1f\x25\xe1\xca\xba\x4f\xf9\xb8\x27\x24\x83\x0f\xca\x60\xe4\xc2\xbe\xa8"
+ "\xc3\xa9\x44\x1c\x27\xb0\xb4\x3e\x6a\x96\x94\xc7\xb8\x04";
+
+MATCHER(IsNetOk, "") {
+ if (arg <= net::OK)
+ *result_listener << net::ErrorToString(arg);
+ return arg == net::OK;
+}
+
+MATCHER_P(IsNetError, expected, "") {
+ if (arg <= net::OK)
+ *result_listener << net::ErrorToString(arg);
+ return arg == expected;
+}
+
+// Always return min, to simplify testing.
+// This should result in the DNS query ID always being 0.
+int FakeRandInt(int min, int max) {
+ return min;
+}
+
+std::vector<char> CreateDnsTxtRequest(base::StringPiece qname) {
+ std::string encoded_qname;
+ EXPECT_TRUE(net::DNSDomainFromDot(qname, &encoded_qname));
+
+ const size_t query_section_size = encoded_qname.size() + 4;
+
+ std::vector<char> request(sizeof(net::dns_protocol::Header) +
+ query_section_size);
+ base::BigEndianWriter writer(request.data(), request.size());
+
+ // Header
+ net::dns_protocol::Header header = {};
+ header.flags = base::HostToNet16(net::dns_protocol::kFlagRD);
+ header.qdcount = base::HostToNet16(1);
+ EXPECT_TRUE(writer.WriteBytes(&header, sizeof(header)));
+ // Query section
+ EXPECT_TRUE(writer.WriteBytes(encoded_qname.data(), encoded_qname.size()));
+ EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kTypeTXT));
+ EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kClassIN));
+ EXPECT_EQ(0, writer.remaining());
+
+ return request;
+}
+
+std::vector<char> CreateDnsTxtResponse(const std::vector<char>& request,
+ base::StringPiece answer) {
+ const size_t answers_section_size = 12 + answer.size();
+ constexpr uint32_t ttl = 86400; // seconds
+
+ std::vector<char> response(request.size() + answers_section_size);
+ std::copy(request.begin(), request.end(), response.begin());
+ // Modify the header
+ net::dns_protocol::Header* header =
+ reinterpret_cast<net::dns_protocol::Header*>(response.data());
+ header->ancount = base::HostToNet16(1);
+ header->flags |= base::HostToNet16(net::dns_protocol::kFlagResponse);
+
+ // Write the answer section
+ base::BigEndianWriter writer(response.data() + request.size(),
+ response.size() - request.size());
+ EXPECT_TRUE(writer.WriteU8(0xc0)); // qname is a pointer
+ EXPECT_TRUE(writer.WriteU8(
+ sizeof(*header))); // address of qname (start of query section)
+ EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kTypeTXT));
+ EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kClassIN));
+ EXPECT_TRUE(writer.WriteU32(ttl));
+ EXPECT_TRUE(writer.WriteU16(answer.size()));
+ EXPECT_TRUE(writer.WriteBytes(answer.data(), answer.size()));
+ EXPECT_EQ(0, writer.remaining());
+
+ return response;
+}
+
+std::vector<char> CreateDnsErrorResponse(const std::vector<char>& request,
+ uint8_t rcode) {
+ std::vector<char> response(request);
+ // Modify the header
+ net::dns_protocol::Header* header =
+ reinterpret_cast<net::dns_protocol::Header*>(response.data());
+ header->ancount = base::HostToNet16(1);
+ header->flags |= base::HostToNet16(net::dns_protocol::kFlagResponse | rcode);
+
+ return response;
+}
+
+std::vector<std::string> GetSampleAuditProof(size_t length) {
+ std::vector<std::string> audit_proof(length);
+ // Makes each node of the audit proof different, so that tests are able to
+ // confirm that the audit proof is reconstructed in the correct order.
+ for (size_t i = 0; i < length; ++i) {
+ std::string node(crypto::kSHA256Length, '\0');
+ // Each node is 32 bytes, with each byte having a different value.
+ for (size_t j = 0; j < crypto::kSHA256Length; ++j) {
+ node[j] = static_cast<char>((-127 + i + j) % 128);
+ }
+ audit_proof[i].assign(std::move(node));
+ }
+
+ return audit_proof;
+}
+
+class MockLeafIndexCallback {
+ public:
+ MOCK_METHOD2(Run, void(int net_error, uint64_t leaf_index));
+};
+
+class MockAuditProofCallback {
+ public:
+ MOCK_METHOD2(Run_, void(int net_error, net::ct::MerkleAuditProof* proof));
+
+ // This proxy function is required because Chromium's GMock is not built with
+ // C++11 support (required for handling std::unique_ptr parameters).
+ // Remove it once this is rectified.
+ void Run(int net_error, std::unique_ptr<net::ct::MerkleAuditProof> proof) {
+ Run_(net_error, proof.release());
+ }
+};
+
+// A container for all of the data we need to keep alive for a mock socket.
+// This is useful because Mock{Read,Write}, SequencedSocketData and
+// MockClientSocketFactory all do not take ownership of or copy their arguments,
+// so we have to manage the lifetime of those arguments ourselves. Wrapping all
+// of that up in a single class simplifies this.
+class MockSocket {
mmenke 2016/06/27 17:01:08 These aren't sockets. Call them MockSocketData or
Rob Percival 2016/06/27 19:01:18 Done.
+ public:
+ // A socket that expects one write and one read operation.
+ MockSocket(const std::vector<char>& write, const std::vector<char>& read)
+ : expected_write_payload_(write),
+ expected_read_payload_(read),
+ expected_write_(net::SYNCHRONOUS,
mmenke 2016/06/27 17:01:08 You should test net::ASYNC as well. For reads, es
Rob Percival 2016/06/27 19:01:18 Isn't that beyond the concern of LogDnsClient? It'
mmenke 2016/06/27 19:26:20 If DnsClient always returns asynchronously, regard
+ expected_write_payload_.data(),
+ expected_write_payload_.size(),
+ 0),
+ expected_read_(net::SYNCHRONOUS,
+ expected_read_payload_.data(),
+ expected_read_payload_.size(),
+ 1),
mmenke 2016/06/27 17:01:07 You can also simulate network errors for both read
Rob Percival 2016/06/28 21:44:54 Done.
+ socket_data_(&expected_read_, 1, &expected_write_, 1) {}
+
+ void AddToFactory(net::MockClientSocketFactory* socket_factory) {
+ socket_factory->AddSocketDataProvider(&socket_data_);
+ }
+
+ private:
+ const std::vector<char> expected_write_payload_;
+ const std::vector<char> expected_read_payload_;
+ net::MockWrite expected_write_;
+ net::MockRead expected_read_;
+ net::SequencedSocketData socket_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockSocket);
+};
+
+class LogDnsClientTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_bundle_.reset(new content::TestBrowserThreadBundle(
+ content::TestBrowserThreadBundle::IO_MAINLOOP));
+ net_log_.reset(new net::BoundTestNetLog());
+ clock_.reset(new base::SimpleTestClock());
+
+ socket_factory_.reset(new net::MockClientSocketFactory());
+ mock_sockets_.clear();
mmenke 2016/06/27 17:01:07 Not needed. For each test, the test fixture is cr
Rob Percival 2016/06/27 19:01:18 Done.
+ }
+
+ std::unique_ptr<net::DnsClient> CreateDnsClient() {
+ net::DnsConfig config;
+ // Use an invalid nameserver address. This prevents the tests accidentally
+ // sending real DNS queries. The mock sockets don't care that the address
+ // is invalid.
+ config.nameservers.push_back(net::IPEndPoint());
+ // Don't attempt retransmissions - just fail.
+ config.attempts = 1;
+ // This ensures timeouts are long enough for memory tests.
+ config.timeout = TestTimeouts::action_timeout();
+ // Simplify testing - don't require random numbers for the source port.
+ // This means our FakeRandInt function should only be called to get query
+ // IDs.
+ config.randomize_ports = false;
+
+ std::unique_ptr<net::DnsClient> client =
+ net::DnsClient::CreateClientForTesting(net_log_->bound().net_log(),
+ socket_factory_.get(),
+ base::Bind(&FakeRandInt));
+ client->SetConfig(config);
+ return client;
+ }
+
+ void ExpectRequestAndResponse(base::StringPiece qname,
+ base::StringPiece answer) {
+ std::vector<char> request = CreateDnsTxtRequest(qname);
+ std::vector<char> response = CreateDnsTxtResponse(request, answer);
+
+ mock_sockets_.emplace_back(new MockSocket(request, response));
+ mock_sockets_.back()->AddToFactory(socket_factory_.get());
+ }
+
+ void ExpectRequestAndErrorResponse(base::StringPiece qname, uint8_t rcode) {
+ std::vector<char> request = CreateDnsTxtRequest(qname);
+ std::vector<char> response = CreateDnsErrorResponse(request, rcode);
+
+ mock_sockets_.emplace_back(new MockSocket(request, response));
+ mock_sockets_.back()->AddToFactory(socket_factory_.get());
+ }
+
+ void ExpectLeafIndexRequestAndResponse(base::StringPiece qname,
+ base::StringPiece leaf_index) {
+ // Prepend size to leaf_index to create the query answer (rdata)
+ ASSERT_LE(leaf_index.size(), 0xFFul); // size must fit into a single byte
+ std::string answer = leaf_index.as_string();
+ answer.insert(answer.begin(), static_cast<char>(leaf_index.size()));
+
+ ExpectRequestAndResponse(qname, answer);
+ }
+
+ void ExpectAuditProofRequestAndResponse(
+ base::StringPiece qname,
+ std::vector<std::string>::const_iterator audit_path_start,
+ std::vector<std::string>::const_iterator audit_path_end) {
+ // Join nodes in the audit path into a single string.
+ std::string proof =
+ std::accumulate(audit_path_start, audit_path_end, std::string());
+
+ // Prepend size to proof to create the query answer (rdata)
+ ASSERT_LE(proof.size(), 0xFFul); // size must fit into a single byte
+ proof.insert(proof.begin(), static_cast<char>(proof.size()));
+
+ ExpectRequestAndResponse(qname, proof);
+ }
+
+ void QueryLeafIndex(base::StringPiece log_domain,
+ base::StringPiece leaf_hash,
+ MockLeafIndexCallback* callback) {
+ std::unique_ptr<net::DnsClient> dns_client = CreateDnsClient();
+ LogDnsClient log_client(std::move(dns_client), net_log_->bound(),
+ clock_.get());
+
+ LogDnsClient::LeafIndexCallback callback_func =
+ base::Bind(&MockLeafIndexCallback::Run, base::Unretained(callback));
+
+ log_client.QueryLeafIndex(log_domain, leaf_hash, callback_func);
+ base::RunLoop().RunUntilIdle();
mmenke 2016/06/27 17:01:08 I don't think it's a great idea, rather than waiti
Rob Percival 2016/06/27 19:01:18 Why's that? With your approach, if a bug causes th
mmenke 2016/06/27 19:26:20 Just because tests do it, doesn't mean they should
Rob Percival 2016/06/27 20:12:11 It's also the way TestBrowserThreadBundle gives as
mmenke 2016/06/27 20:24:45 I think it's unlikely, but remember that the Worke
Rob Percival 2016/06/28 21:44:54 Done.
+ }
+
+ void QueryAuditProof(base::StringPiece log_domain,
+ uint64_t leaf_index,
+ uint64_t tree_size,
+ MockAuditProofCallback* callback) {
+ std::unique_ptr<net::DnsClient> dns_client = CreateDnsClient();
+ LogDnsClient log_client(std::move(dns_client), net_log_->bound(),
+ clock_.get());
+
+ LogDnsClient::AuditProofCallback callback_func =
+ base::Bind(&MockAuditProofCallback::Run, base::Unretained(callback));
+
+ log_client.QueryAuditProof(log_domain, leaf_index, tree_size,
+ callback_func);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ std::unique_ptr<content::TestBrowserThreadBundle> thread_bundle_;
+ std::unique_ptr<net::BoundTestNetLog> net_log_;
mmenke 2016/06/27 17:04:09 Also, you don't need this - just pass in a net::Bo
mmenke 2016/06/27 17:05:02 (Also, pass in nullptr when you need a NetLog inst
Rob Percival 2016/06/27 19:01:18 Done.
+ std::unique_ptr<base::SimpleTestClock> clock_;
+ std::vector<std::unique_ptr<MockSocket>> mock_sockets_;
+ std::unique_ptr<net::MockClientSocketFactory> socket_factory_;
+};
+
+TEST_F(LogDnsClientTest, QueryLeafIndex) {
+ ExpectLeafIndexRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ "123456");
+
+ MockLeafIndexCallback callback;
mmenke 2016/06/27 17:01:08 The chrome wide preference is not to use gmock, to
Rob Percival 2016/06/27 19:01:18 As it happens, I used to have some hand-rolled moc
mmenke 2016/06/27 19:26:20 Clarity is generally better than being concise. H
Rob Percival 2016/06/27 20:12:11 That lack of support for unique_ptrs is indeed unf
Rob Percival 2016/06/28 21:44:54 Done.
+ EXPECT_CALL(callback, Run(IsNetOk(), 123456));
+
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+}
+
+TEST_F(LogDnsClientTest, QueryLeafIndexReportsThatLogDomainDoesNotExist) {
+ ExpectRequestAndErrorResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ net::dns_protocol::kRcodeNXDOMAIN);
+
+ MockLeafIndexCallback callback;
+ EXPECT_CALL(callback, Run(IsNetError(net::ERR_NAME_NOT_RESOLVED), 0));
+
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+}
+
+TEST_F(LogDnsClientTest, QueryLeafIndexReportsServerFailure) {
+ ExpectRequestAndErrorResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ net::dns_protocol::kRcodeSERVFAIL);
+
+ MockLeafIndexCallback callback;
+ EXPECT_CALL(callback, Run(IsNetError(net::ERR_DNS_SERVER_FAILED), 0));
+
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+}
+
+TEST_F(LogDnsClientTest, QueryLeafIndexReportsServerRefusal) {
+ ExpectRequestAndErrorResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ net::dns_protocol::kRcodeREFUSED);
+
+ MockLeafIndexCallback callback;
+ EXPECT_CALL(callback, Run(IsNetError(net::ERR_DNS_SERVER_FAILED), 0));
+
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+}
+
+TEST_F(LogDnsClientTest,
+ QueryLeafIndexReportsMalformedResponseIfLeafIndexIsNotNumeric) {
+ ExpectLeafIndexRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ "foo");
+
+ MockLeafIndexCallback callback;
+ EXPECT_CALL(callback, Run(IsNetError(net::ERR_DNS_MALFORMED_RESPONSE), 0));
+
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+}
+
+TEST_F(LogDnsClientTest,
+ QueryLeafIndexReportsMalformedResponseIfLeafIndexIsFloatingPoint) {
+ ExpectLeafIndexRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ "123456.0");
+
+ MockLeafIndexCallback callback;
+ EXPECT_CALL(callback, Run(IsNetError(net::ERR_DNS_MALFORMED_RESPONSE), 0));
+
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+}
+
+TEST_F(LogDnsClientTest,
+ QueryLeafIndexReportsMalformedResponseIfLeafIndexIsEmpty) {
+ ExpectLeafIndexRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.", "");
+
+ MockLeafIndexCallback callback;
+ EXPECT_CALL(callback, Run(IsNetError(net::ERR_DNS_MALFORMED_RESPONSE), 0));
+
+ QueryLeafIndex("ct.test", kLeafHash, &callback);
+}
+
+TEST_F(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLogDomainIsEmpty) {
+ MockLeafIndexCallback callback;
+ EXPECT_CALL(callback, Run(IsNetError(net::ERR_INVALID_ARGUMENT), 0));
+
+ QueryLeafIndex("", kLeafHash, &callback);
+}
+
+TEST_F(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLogDomainIsNull) {
+ MockLeafIndexCallback callback;
+ EXPECT_CALL(callback, Run(IsNetError(net::ERR_INVALID_ARGUMENT), 0));
+
+ QueryLeafIndex(nullptr, kLeafHash, &callback);
+}
+
+TEST_F(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsInvalid) {
+ MockLeafIndexCallback callback;
+ EXPECT_CALL(callback, Run(IsNetError(net::ERR_INVALID_ARGUMENT), 0));
+
+ QueryLeafIndex("ct.test", "foo", &callback);
+}
+
+TEST_F(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsEmpty) {
+ MockLeafIndexCallback callback;
+ EXPECT_CALL(callback, Run(IsNetError(net::ERR_INVALID_ARGUMENT), 0));
+
+ QueryLeafIndex("ct.test", "", &callback);
+}
+
+TEST_F(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsNull) {
+ MockLeafIndexCallback callback;
+ EXPECT_CALL(callback, Run(IsNetError(net::ERR_INVALID_ARGUMENT), 0));
+
+ QueryLeafIndex("ct.test", nullptr, &callback);
+}
+
+TEST_F(LogDnsClientTest, QueryAuditProof) {
+ const std::vector<std::string> audit_proof = GetSampleAuditProof(20);
+
+ // It should require 3 queries to collect the entire audit proof, as there is
+ // only space for 7 nodes per UDP packet.
+ ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
+ audit_proof.begin(),
+ audit_proof.begin() + 7);
+ ExpectAuditProofRequestAndResponse("7.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 7,
+ audit_proof.begin() + 14);
+ ExpectAuditProofRequestAndResponse("14.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 14,
+ audit_proof.end());
+
+ MockAuditProofCallback callback;
+ EXPECT_CALL(callback,
+ Run_(IsNetOk(),
+ Pointee(AllOf(
+ Field(&net::ct::MerkleAuditProof::nodes, audit_proof),
+ Field(&net::ct::MerkleAuditProof::leaf_index, 123456)))))
+ .WillOnce(DeleteArg<1>());
+
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+}
+
+TEST_F(LogDnsClientTest,
+ QueryAuditProofHandlesResponsesWithEmptyAndShortAuditPaths) {
+ const std::vector<std::string> audit_proof = GetSampleAuditProof(20);
+
+ // Make some of the responses empty or contain fewer audit proof nodes than
+ // they can hold.
+ ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
+ audit_proof.begin(), audit_proof.begin());
+ ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
+ audit_proof.begin(),
+ audit_proof.begin() + 1);
+ ExpectAuditProofRequestAndResponse("1.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 1,
+ audit_proof.begin() + 3);
+ ExpectAuditProofRequestAndResponse("3.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 3,
+ audit_proof.begin() + 6);
+ ExpectAuditProofRequestAndResponse("6.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 6,
+ audit_proof.begin() + 10);
+ ExpectAuditProofRequestAndResponse("10.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 10,
+ audit_proof.begin() + 13);
+ ExpectAuditProofRequestAndResponse("13.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 13,
+ audit_proof.end());
+
+ MockAuditProofCallback callback;
+ EXPECT_CALL(callback,
+ Run_(IsNetOk(),
+ Pointee(AllOf(
+ Field(&net::ct::MerkleAuditProof::nodes, audit_proof),
+ Field(&net::ct::MerkleAuditProof::leaf_index, 123456)))))
+ .WillOnce(DeleteArg<1>());
+
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+}
+
+TEST_F(LogDnsClientTest, QueryAuditProofReportsThatLogDomainDoesNotExist) {
+ ExpectRequestAndErrorResponse("0.123456.999999.tree.ct.test.",
+ net::dns_protocol::kRcodeNXDOMAIN);
+
+ MockAuditProofCallback callback;
+ EXPECT_CALL(callback, Run_(IsNetError(net::ERR_NAME_NOT_RESOLVED), nullptr));
+
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+}
+
+TEST_F(LogDnsClientTest, QueryAuditProofReportsServerFailure) {
+ ExpectRequestAndErrorResponse("0.123456.999999.tree.ct.test.",
+ net::dns_protocol::kRcodeSERVFAIL);
+
+ MockAuditProofCallback callback;
+ EXPECT_CALL(callback, Run_(IsNetError(net::ERR_DNS_SERVER_FAILED), nullptr));
+
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+}
+
+TEST_F(LogDnsClientTest, QueryAuditProofReportsServerRefusal) {
+ ExpectRequestAndErrorResponse("0.123456.999999.tree.ct.test.",
+ net::dns_protocol::kRcodeREFUSED);
+
+ MockAuditProofCallback callback;
+ EXPECT_CALL(callback, Run_(IsNetError(net::ERR_DNS_SERVER_FAILED), nullptr));
+
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+}
+
+TEST_F(LogDnsClientTest,
+ QueryAuditProofReportsResponseMalformedIfNodeTooShort) {
+ // node is shorter than a SHA-256 hash (31 vs 32 bytes)
+ const std::vector<std::string> audit_proof(1, std::string(31, 'a'));
+
+ ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
+ audit_proof.begin(), audit_proof.end());
+
+ MockAuditProofCallback callback;
+ EXPECT_CALL(callback,
+ Run_(IsNetError(net::ERR_DNS_MALFORMED_RESPONSE), nullptr));
+
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+}
+
+TEST_F(LogDnsClientTest, QueryAuditProofReportsResponseMalformedIfNodeTooLong) {
+ // node is longer than a SHA-256 hash (33 vs 32 bytes)
+ const std::vector<std::string> audit_proof(1, std::string(33, 'a'));
+
+ ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
+ audit_proof.begin(), audit_proof.end());
+
+ MockAuditProofCallback callback;
+ EXPECT_CALL(callback,
+ Run_(IsNetError(net::ERR_DNS_MALFORMED_RESPONSE), nullptr));
+
+ QueryAuditProof("ct.test", 123456, 999999, &callback);
+}
+
+TEST_F(LogDnsClientTest, QueryAuditProofReportsInvalidArgIfLogDomainIsEmpty) {
+ MockAuditProofCallback callback;
+ EXPECT_CALL(callback, Run_(IsNetError(net::ERR_INVALID_ARGUMENT), nullptr));
+
+ QueryAuditProof("", 123456, 999999, &callback);
+}
+
+TEST_F(LogDnsClientTest, QueryAuditProofReportsInvalidArgIfLogDomainIsNull) {
+ MockAuditProofCallback callback;
+ EXPECT_CALL(callback, Run_(IsNetError(net::ERR_INVALID_ARGUMENT), nullptr));
+
+ QueryAuditProof(nullptr, 123456, 999999, &callback);
+}
+
+TEST_F(LogDnsClientTest,
+ QueryAuditProofReportInvalidArgIfLeafIndexEqualToTreeSize) {
+ MockAuditProofCallback callback;
+ EXPECT_CALL(callback, Run_(IsNetError(net::ERR_INVALID_ARGUMENT), nullptr));
+
+ QueryAuditProof("ct.test", 123456, 123456, &callback);
+}
+
+TEST_F(LogDnsClientTest,
+ QueryAuditProofReportInvalidArgIfLeafIndexGreaterThanTreeSize) {
+ MockAuditProofCallback callback;
+ EXPECT_CALL(callback, Run_(IsNetError(net::ERR_INVALID_ARGUMENT), nullptr));
+
+ QueryAuditProof("ct.test", 999999, 123456, &callback);
+}
+
+} // namespace
+} // namespace certificate_transparency
« no previous file with comments | « components/certificate_transparency/log_dns_client.cc ('k') | components/components_tests.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698