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 2331923003: Allow LogDnsClient queries to be rate-limited (Closed)
Patch Set: Use Eq matcher with EXPECT_THAT Created 4 years, 3 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
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
index 64223ef51757768878acef01f6fd8431449782c9..4875d9df90da3d6b9aa29af9b40825de3c18cffa 100644
--- a/components/certificate_transparency/log_dns_client_unittest.cc
+++ b/components/certificate_transparency/log_dns_client_unittest.cc
@@ -9,6 +9,7 @@
#include <utility>
#include <vector>
+#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "components/certificate_transparency/mock_log_dns_traffic.h"
@@ -27,6 +28,7 @@
namespace certificate_transparency {
namespace {
+using ::testing::Eq;
using ::testing::IsEmpty;
using ::testing::IsNull;
using ::testing::Not;
@@ -120,21 +122,46 @@ class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> {
mock_dns_.InitializeDnsConfig();
}
+ std::unique_ptr<LogDnsClient> CreateLogDnsClient(
+ size_t max_concurrent_queries) {
+ return base::MakeUnique<LogDnsClient>(mock_dns_.CreateDnsClient(),
+ net::BoundNetLog(),
+ max_concurrent_queries);
+ }
+
+ void QueryLeafIndexAsync(LogDnsClient* log_client,
+ base::StringPiece log_domain,
+ base::StringPiece leaf_hash,
+ const LogDnsClient::LeafIndexCallback& callback) {
+ log_client->QueryLeafIndex(log_domain, leaf_hash, callback);
+ }
+
+ // Convenience function for calling QueryLeafIndexAsync synchronously.
void QueryLeafIndex(base::StringPiece log_domain,
base::StringPiece leaf_hash,
MockLeafIndexCallback* callback) {
- LogDnsClient log_client(mock_dns_.CreateDnsClient(), net::BoundNetLog());
- log_client.QueryLeafIndex(log_domain, leaf_hash, callback->AsCallback());
+ std::unique_ptr<LogDnsClient> log_client = CreateLogDnsClient(0);
+ QueryLeafIndexAsync(log_client.get(), log_domain, leaf_hash,
+ callback->AsCallback());
callback->WaitUntilRun();
}
+ void QueryAuditProofAsync(LogDnsClient* log_client,
+ base::StringPiece log_domain,
+ uint64_t leaf_index,
+ uint64_t tree_size,
+ const LogDnsClient::AuditProofCallback& callback) {
+ log_client->QueryAuditProof(log_domain, leaf_index, tree_size, callback);
+ }
+
+ // Convenience function for calling QueryAuditProofAsync synchronously.
void QueryAuditProof(base::StringPiece log_domain,
uint64_t leaf_index,
uint64_t tree_size,
MockAuditProofCallback* callback) {
- LogDnsClient log_client(mock_dns_.CreateDnsClient(), net::BoundNetLog());
- log_client.QueryAuditProof(log_domain, leaf_index, tree_size,
- callback->AsCallback());
+ std::unique_ptr<LogDnsClient> log_client = CreateLogDnsClient(0);
+ QueryAuditProofAsync(log_client.get(), log_domain, leaf_index, tree_size,
+ callback->AsCallback());
callback->WaitUntilRun();
}
@@ -157,7 +184,7 @@ TEST_P(LogDnsClientTest, QueryLeafIndex) {
QueryLeafIndex("ct.test", kLeafHash, &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsOk());
- EXPECT_THAT(callback.leaf_index(), 123456);
+ EXPECT_THAT(callback.leaf_index(), Eq(123456u));
}
TEST_P(LogDnsClientTest, QueryLeafIndexReportsThatLogDomainDoesNotExist) {
@@ -169,7 +196,7 @@ TEST_P(LogDnsClientTest, QueryLeafIndexReportsThatLogDomainDoesNotExist) {
QueryLeafIndex("ct.test", kLeafHash, &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsError(net::ERR_NAME_NOT_RESOLVED));
- EXPECT_THAT(callback.leaf_index(), 0);
+ EXPECT_THAT(callback.leaf_index(), Eq(0u));
}
TEST_P(LogDnsClientTest, QueryLeafIndexReportsServerFailure) {
@@ -181,7 +208,7 @@ TEST_P(LogDnsClientTest, QueryLeafIndexReportsServerFailure) {
QueryLeafIndex("ct.test", kLeafHash, &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_SERVER_FAILED));
- EXPECT_THAT(callback.leaf_index(), 0);
+ EXPECT_THAT(callback.leaf_index(), Eq(0u));
}
TEST_P(LogDnsClientTest, QueryLeafIndexReportsServerRefusal) {
@@ -193,7 +220,7 @@ TEST_P(LogDnsClientTest, QueryLeafIndexReportsServerRefusal) {
QueryLeafIndex("ct.test", kLeafHash, &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_SERVER_FAILED));
- EXPECT_THAT(callback.leaf_index(), 0);
+ EXPECT_THAT(callback.leaf_index(), Eq(0u));
}
TEST_P(LogDnsClientTest,
@@ -206,7 +233,7 @@ TEST_P(LogDnsClientTest,
QueryLeafIndex("ct.test", kLeafHash, &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
- EXPECT_THAT(callback.leaf_index(), 0);
+ EXPECT_THAT(callback.leaf_index(), Eq(0u));
}
TEST_P(LogDnsClientTest,
@@ -219,7 +246,7 @@ TEST_P(LogDnsClientTest,
QueryLeafIndex("ct.test", kLeafHash, &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
- EXPECT_THAT(callback.leaf_index(), 0);
+ EXPECT_THAT(callback.leaf_index(), Eq(0u));
}
TEST_P(LogDnsClientTest,
@@ -231,7 +258,7 @@ TEST_P(LogDnsClientTest,
QueryLeafIndex("ct.test", kLeafHash, &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
- EXPECT_THAT(callback.leaf_index(), 0);
+ EXPECT_THAT(callback.leaf_index(), Eq(0u));
}
TEST_P(LogDnsClientTest,
@@ -244,7 +271,7 @@ TEST_P(LogDnsClientTest,
QueryLeafIndex("ct.test", kLeafHash, &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
- EXPECT_THAT(callback.leaf_index(), 0);
+ EXPECT_THAT(callback.leaf_index(), Eq(0u));
}
TEST_P(LogDnsClientTest,
@@ -257,7 +284,7 @@ TEST_P(LogDnsClientTest,
QueryLeafIndex("ct.test", kLeafHash, &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
- EXPECT_THAT(callback.leaf_index(), 0);
+ EXPECT_THAT(callback.leaf_index(), Eq(0u));
}
TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLogDomainIsEmpty) {
@@ -265,7 +292,7 @@ TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLogDomainIsEmpty) {
QueryLeafIndex("", kLeafHash, &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
- EXPECT_THAT(callback.leaf_index(), 0);
+ EXPECT_THAT(callback.leaf_index(), Eq(0u));
}
TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLogDomainIsNull) {
@@ -273,7 +300,7 @@ TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLogDomainIsNull) {
QueryLeafIndex(nullptr, kLeafHash, &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
- EXPECT_THAT(callback.leaf_index(), 0);
+ EXPECT_THAT(callback.leaf_index(), Eq(0u));
}
TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsInvalid) {
@@ -281,7 +308,7 @@ TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsInvalid) {
QueryLeafIndex("ct.test", "foo", &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
- EXPECT_THAT(callback.leaf_index(), 0);
+ EXPECT_THAT(callback.leaf_index(), Eq(0u));
}
TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsEmpty) {
@@ -289,7 +316,7 @@ TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsEmpty) {
QueryLeafIndex("ct.test", "", &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
- EXPECT_THAT(callback.leaf_index(), 0);
+ EXPECT_THAT(callback.leaf_index(), Eq(0u));
}
TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsNull) {
@@ -297,7 +324,7 @@ TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsNull) {
QueryLeafIndex("ct.test", nullptr, &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
- EXPECT_THAT(callback.leaf_index(), 0);
+ EXPECT_THAT(callback.leaf_index(), Eq(0u));
}
TEST_P(LogDnsClientTest, QueryLeafIndexReportsSocketError) {
@@ -309,7 +336,7 @@ TEST_P(LogDnsClientTest, QueryLeafIndexReportsSocketError) {
QueryLeafIndex("ct.test", kLeafHash, &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsError(net::ERR_CONNECTION_REFUSED));
- EXPECT_THAT(callback.leaf_index(), 0);
+ EXPECT_THAT(callback.leaf_index(), Eq(0u));
}
TEST_P(LogDnsClientTest, QueryLeafIndexReportsTimeout) {
@@ -320,14 +347,15 @@ TEST_P(LogDnsClientTest, QueryLeafIndexReportsTimeout) {
QueryLeafIndex("ct.test", kLeafHash, &callback);
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_TIMED_OUT));
- EXPECT_THAT(callback.leaf_index(), 0);
+ EXPECT_THAT(callback.leaf_index(), Eq(0u));
}
TEST_P(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.
+ // It should require 3 requests to collect the entire audit proof, as there is
+ // only space for 7 nodes per TXT record. One node is 32 bytes long and the
+ // TXT RDATA can have a maximum length of 255 bytes (255 / 32).
mock_dns_.ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
audit_proof.begin(),
audit_proof.begin() + 7);
@@ -343,9 +371,10 @@ TEST_P(LogDnsClientTest, QueryAuditProof) {
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsOk());
ASSERT_THAT(callback.proof(), NotNull());
- EXPECT_THAT(callback.proof()->leaf_index, 123456);
- // EXPECT_THAT(callback.proof()->tree_size, 999999);
- EXPECT_THAT(callback.proof()->nodes, audit_proof);
+ EXPECT_THAT(callback.proof()->leaf_index, Eq(123456u));
+ // TODO(robpercival): Enable this once MerkleAuditProof has tree_size.
+ // EXPECT_THAT(callback.proof()->tree_size, Eq(999999));
+ EXPECT_THAT(callback.proof()->nodes, Eq(audit_proof));
}
TEST_P(LogDnsClientTest, QueryAuditProofHandlesResponsesWithShortAuditPaths) {
@@ -376,9 +405,10 @@ TEST_P(LogDnsClientTest, QueryAuditProofHandlesResponsesWithShortAuditPaths) {
ASSERT_TRUE(callback.called());
EXPECT_THAT(callback.net_error(), IsOk());
ASSERT_THAT(callback.proof(), NotNull());
- EXPECT_THAT(callback.proof()->leaf_index, 123456);
- // EXPECT_THAT(callback.proof()->tree_size, 999999);
- EXPECT_THAT(callback.proof()->nodes, audit_proof);
+ EXPECT_THAT(callback.proof()->leaf_index, Eq(123456u));
+ // TODO(robpercival): Enable this once MerkleAuditProof has tree_size.
+ // EXPECT_THAT(callback.proof()->tree_size, Eq(999999));
+ EXPECT_THAT(callback.proof()->nodes, Eq(audit_proof));
}
TEST_P(LogDnsClientTest, QueryAuditProofReportsThatLogDomainDoesNotExist) {
@@ -514,7 +544,7 @@ TEST_P(LogDnsClientTest, QueryAuditProofReportsTimeout) {
TEST_P(LogDnsClientTest, AdoptsLatestDnsConfigIfValid) {
std::unique_ptr<net::DnsClient> tmp = mock_dns_.CreateDnsClient();
net::DnsClient* dns_client = tmp.get();
- LogDnsClient log_client(std::move(tmp), net::BoundNetLog());
+ LogDnsClient log_client(std::move(tmp), net::BoundNetLog(), 0);
// Get the current DNS config, modify it and broadcast the update.
net::DnsConfig config(*dns_client->GetConfig());
@@ -530,7 +560,7 @@ TEST_P(LogDnsClientTest, AdoptsLatestDnsConfigIfValid) {
TEST_P(LogDnsClientTest, IgnoresLatestDnsConfigIfInvalid) {
std::unique_ptr<net::DnsClient> tmp = mock_dns_.CreateDnsClient();
net::DnsClient* dns_client = tmp.get();
- LogDnsClient log_client(std::move(tmp), net::BoundNetLog());
+ LogDnsClient log_client(std::move(tmp), net::BoundNetLog(), 0);
// Get the current DNS config, modify it and broadcast the update.
net::DnsConfig config(*dns_client->GetConfig());
@@ -543,6 +573,283 @@ TEST_P(LogDnsClientTest, IgnoresLatestDnsConfigIfInvalid) {
EXPECT_THAT(dns_client->GetConfig()->nameservers, Not(IsEmpty()));
}
+TEST_P(LogDnsClientTest, CanPerformLeafIndexQueriesInParallel) {
+ // Test that 3 leaf index queries can be performed in parallel.
+ constexpr size_t kNumOfParallelQueries = 3;
+ std::unique_ptr<LogDnsClient> log_client =
+ CreateLogDnsClient(kNumOfParallelQueries);
+ MockLeafIndexCallback callbacks[kNumOfParallelQueries];
+
+ // Expect 3 requests.
+ for (size_t i = 0; i < kNumOfParallelQueries; ++i) {
+ mock_dns_.ExpectLeafIndexRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ "123456");
Ryan Sleevi 2016/09/16 02:11:03 Is this value necessary as part of the test? The s
Rob Percival 2016/09/16 16:28:19 They're required to test that nothing goes quietly
Ryan Sleevi 2016/09/17 01:51:52 Right, with the current structure (using the same
Rob Percival 2016/09/20 18:54:42 Done.
+ }
+
+ // Start the queries.
+ for (size_t i = 0; i < kNumOfParallelQueries; ++i) {
+ QueryLeafIndexAsync(log_client.get(), "ct.test", kLeafHash,
+ callbacks[i].AsCallback());
+ }
+
+ // Wait for each query to complete and check its results.
+ for (size_t i = 0; i < kNumOfParallelQueries; ++i) {
+ MockLeafIndexCallback& callback = callbacks[i];
+ callback.WaitUntilRun();
+
+ SCOPED_TRACE(i);
+ EXPECT_TRUE(callback.called());
+ if (callback.called()) {
+ EXPECT_THAT(callback.net_error(), IsOk());
+ EXPECT_THAT(callback.leaf_index(), Eq(123456u));
+ }
+ }
Ryan Sleevi 2016/09/16 02:11:03 For what it's worth, I spent 20 minutes digging th
Rob Percival 2016/09/16 16:28:19 This is another thing that was only added as a res
Ryan Sleevi 2016/09/17 01:51:52 Link to previous CL?
Rob Percival 2016/09/20 18:54:42 https://codereview.chromium.org/2066553002/#ps1800
Ryan Sleevi 2016/09/22 04:37:07 Thanks. I think there was a breakdown in communica
Rob Percival 2016/09/22 11:33:23 Ah I see, TestCompletionCallback has a unique_ptr<
+}
+
+TEST_P(LogDnsClientTest, CanPerformAuditProofQueriesInParallel) {
+ // Check that 3 audit proof queries can be performed in parallel.
+ constexpr size_t kNumOfParallelQueries = 3;
+ std::unique_ptr<LogDnsClient> log_client =
+ CreateLogDnsClient(kNumOfParallelQueries);
+ MockAuditProofCallback callbacks[kNumOfParallelQueries];
+ const std::vector<std::string> audit_proof = GetSampleAuditProof(20);
+
+ // It should require 3 requests to collect the entire audit proof, as there is
+ // only space for 7 nodes per TXT record. One node is 32 bytes long and the
+ // TXT RDATA can have a maximum length of 255 bytes (255 / 32). Expect each of
+ // these queries to occur once for each call to QueryAuditProof.
+
+ for (size_t i = 0; i < kNumOfParallelQueries; ++i) {
+ mock_dns_.ExpectAuditProofRequestAndResponse(
+ "0.123456.999999.tree.ct.test.", audit_proof.begin(),
+ audit_proof.begin() + 7);
+ }
+
+ for (size_t i = 0; i < kNumOfParallelQueries; ++i) {
+ mock_dns_.ExpectAuditProofRequestAndResponse(
+ "7.123456.999999.tree.ct.test.", audit_proof.begin() + 7,
+ audit_proof.begin() + 14);
+ }
+
+ for (size_t i = 0; i < kNumOfParallelQueries; ++i) {
+ mock_dns_.ExpectAuditProofRequestAndResponse(
+ "14.123456.999999.tree.ct.test.", audit_proof.begin() + 14,
+ audit_proof.end());
+ }
+
+ // Start the queries.
+ for (size_t i = 0; i < kNumOfParallelQueries; ++i) {
+ QueryAuditProofAsync(log_client.get(), "ct.test", 123456, 999999,
+ callbacks[i].AsCallback());
+ }
+
+ // Wait for each query to complete and check its results.
+ for (size_t i = 0; i < kNumOfParallelQueries; ++i) {
+ MockAuditProofCallback& callback = callbacks[i];
+ callbacks[i].WaitUntilRun();
+
+ SCOPED_TRACE(i);
+ EXPECT_TRUE(callback.called());
+ if (callback.called()) {
+ EXPECT_THAT(callback.net_error(), IsOk());
+ EXPECT_THAT(callback.proof(), NotNull());
+ if (callback.proof() != nullptr) {
+ EXPECT_THAT(callback.proof()->leaf_index, Eq(123456u));
+ // TODO(robpercival): Enable this once MerkleAuditProof has tree_size.
+ // EXPECT_THAT(callback.proof()->tree_size, Eq(999999));
+ EXPECT_THAT(callback.proof()->nodes, Eq(audit_proof));
+ }
+ }
+ }
+}
+
+TEST_P(LogDnsClientTest, CanPerformLeafIndexAndAuditProofQueriesInParallel) {
+ // Check that a leaf index and audit proof query can be performed in parallel.
+ constexpr size_t kNumOfParallelQueries = 2;
+ std::unique_ptr<LogDnsClient> log_client =
+ CreateLogDnsClient(kNumOfParallelQueries);
+ MockLeafIndexCallback leaf_index_callback;
+ MockAuditProofCallback audit_proof_callback;
+ const std::vector<std::string> audit_proof = GetSampleAuditProof(20);
+
+ mock_dns_.ExpectLeafIndexRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ "123456");
+
+ // It should require 3 requests to collect the entire audit proof, as there is
+ // only space for 7 nodes per TXT record. One node is 32 bytes long and the
+ // TXT RDATA can have a maximum length of 255 bytes (255 / 32).
+ mock_dns_.ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
+ audit_proof.begin(),
+ audit_proof.begin() + 7);
+ mock_dns_.ExpectAuditProofRequestAndResponse("7.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 7,
+ audit_proof.begin() + 14);
+ mock_dns_.ExpectAuditProofRequestAndResponse("14.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 14,
+ audit_proof.end());
+
+ // Start the queries.
+ QueryLeafIndexAsync(log_client.get(), "ct.test", kLeafHash,
+ leaf_index_callback.AsCallback());
+ QueryAuditProofAsync(log_client.get(), "ct.test", 123456, 999999,
+ audit_proof_callback.AsCallback());
+
+ // Wait for the queries to complete, then check their results.
+ leaf_index_callback.WaitUntilRun();
+ audit_proof_callback.WaitUntilRun();
+
+ EXPECT_TRUE(leaf_index_callback.called());
+ if (leaf_index_callback.called()) {
+ EXPECT_THAT(leaf_index_callback.net_error(), IsOk());
+ EXPECT_THAT(leaf_index_callback.leaf_index(), Eq(123456u));
+ }
+
+ EXPECT_TRUE(audit_proof_callback.called());
+ if (audit_proof_callback.called()) {
+ EXPECT_THAT(audit_proof_callback.net_error(), IsOk());
+ EXPECT_THAT(audit_proof_callback.proof(), NotNull());
+ if (audit_proof_callback.proof() != nullptr) {
+ EXPECT_THAT(audit_proof_callback.proof()->leaf_index, Eq(123456u));
+ // TODO(robpercival): Enable this once MerkleAuditProof has tree_size.
+ // EXPECT_THAT(audit_proof_callback.proof()->tree_size, Eq(999999));
+ EXPECT_THAT(audit_proof_callback.proof()->nodes, Eq(audit_proof));
+ }
+ }
+}
+
+TEST_P(LogDnsClientTest, CanBeThrottledToOneLeafIndexQueryAtATime) {
+ // Check that leaf index queries can be rate-limited to one at a time.
+ // The second query, initiated while the first is in progress, should fail.
+ mock_dns_.ExpectLeafIndexRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ "123456");
+
+ const size_t max_concurrent_queries = 1;
+ std::unique_ptr<LogDnsClient> log_client =
+ CreateLogDnsClient(max_concurrent_queries);
+
+ // Start the queries.
+ MockLeafIndexCallback callback1;
+ QueryLeafIndexAsync(log_client.get(), "ct.test", kLeafHash,
+ callback1.AsCallback());
+ MockLeafIndexCallback callback2;
+ QueryLeafIndexAsync(log_client.get(), "ct.test", kLeafHash,
+ callback2.AsCallback());
+
+ callback1.WaitUntilRun();
+ callback2.WaitUntilRun();
+
+ // Check that the first query succeeded.
+ EXPECT_TRUE(callback1.called());
+ if (callback1.called()) {
Ryan Sleevi 2016/09/16 02:11:03 This is non-obvious to me why you have an EXPECT_T
Rob Percival 2016/09/16 16:28:19 It's actually "Expect that this code will be calle
Ryan Sleevi 2016/09/17 01:51:52 Why? In the face of failure, what new and additio
Rob Percival 2016/09/20 18:54:42 As discussed in https://testing.googleblog.com/200
Ryan Sleevi 2016/09/22 04:37:07 Apologies that I worded the question poorly, and p
Rob Percival 2016/09/22 11:33:23 Very well. I'm not entirely convinced, but I'll de
+ EXPECT_THAT(callback1.net_error(), IsOk());
+ EXPECT_THAT(callback1.leaf_index(), Eq(123456u));
+ }
+
+ // Check that the second query failed.
+ EXPECT_TRUE(callback2.called());
+ if (callback2.called()) {
+ EXPECT_THAT(callback2.net_error(), IsError(net::ERR_TEMPORARILY_THROTTLED));
+ EXPECT_THAT(callback2.leaf_index(), Eq(0u));
+ }
+}
+
+TEST_P(LogDnsClientTest, CanBeThrottledToOneAuditProofQueryAtATime) {
+ // Check that audit proof queries can be rate-limited to one at a time.
+ // The second query, initiated while the first is in progress, should fail.
+ const std::vector<std::string> audit_proof = GetSampleAuditProof(20);
+
+ // It should require 3 requests to collect the entire audit proof, as there is
+ // only space for 7 nodes per TXT record. One node is 32 bytes long and the
+ // TXT RDATA can have a maximum length of 255 bytes (255 / 32).
+ // Rate limiting should not interfere with these requests.
+ mock_dns_.ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
+ audit_proof.begin(),
+ audit_proof.begin() + 7);
+ mock_dns_.ExpectAuditProofRequestAndResponse("7.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 7,
+ audit_proof.begin() + 14);
+ mock_dns_.ExpectAuditProofRequestAndResponse("14.123456.999999.tree.ct.test.",
+ audit_proof.begin() + 14,
+ audit_proof.end());
+
+ const size_t max_concurrent_queries = 1;
+ std::unique_ptr<LogDnsClient> log_client =
+ CreateLogDnsClient(max_concurrent_queries);
+
+ // Start the queries.
+ MockAuditProofCallback callback1;
+ QueryAuditProofAsync(log_client.get(), "ct.test", 123456, 999999,
+ callback1.AsCallback());
+ MockAuditProofCallback callback2;
+ QueryAuditProofAsync(log_client.get(), "ct.test", 123456, 999999,
+ callback2.AsCallback());
+
+ callback1.WaitUntilRun();
+ callback2.WaitUntilRun();
+
+ // Check that the first query succeeded.
+ EXPECT_TRUE(callback1.called());
+ if (callback1.called()) {
+ EXPECT_THAT(callback1.net_error(), IsOk());
+ EXPECT_THAT(callback1.proof(), NotNull());
+ if (callback1.proof() != nullptr) {
+ EXPECT_THAT(callback1.proof()->leaf_index, Eq(123456u));
+ // TODO(robpercival): Enable this once MerkleAuditProof has tree_size.
+ // EXPECT_THAT(callback1.proof()->tree_size, Eq(999999));
+ EXPECT_THAT(callback1.proof()->nodes, Eq(audit_proof));
+ }
+ }
+
+ // Check that the second query failed.
+ EXPECT_TRUE(callback2.called());
+ if (callback2.called()) {
+ EXPECT_THAT(callback2.net_error(), IsError(net::ERR_TEMPORARILY_THROTTLED));
+ EXPECT_THAT(callback2.proof(), IsNull());
+ }
+}
+
+TEST_P(LogDnsClientTest, ThrottlingAppliesAcrossQueryTypes) {
+ // Check that queries can be rate-limited to one at a time, regardless of the
+ // type of query. The second query, initiated while the first is in progress,
+ // should fail.
+ mock_dns_.ExpectLeafIndexRequestAndResponse(
+ "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+ "123456");
+
+ const size_t max_concurrent_queries = 1;
+ std::unique_ptr<LogDnsClient> log_client =
+ CreateLogDnsClient(max_concurrent_queries);
+
+ // Start the queries.
+ MockLeafIndexCallback leaf_index_callback;
+ QueryLeafIndexAsync(log_client.get(), "ct.test", kLeafHash,
+ leaf_index_callback.AsCallback());
+ MockAuditProofCallback audit_proof_callback;
+ QueryAuditProofAsync(log_client.get(), "ct.test", 123456, 999999,
+ audit_proof_callback.AsCallback());
+
+ leaf_index_callback.WaitUntilRun();
+ audit_proof_callback.WaitUntilRun();
+
+ // Check that the first query succeeded.
+ EXPECT_TRUE(leaf_index_callback.called());
+ if (leaf_index_callback.called()) {
+ EXPECT_THAT(leaf_index_callback.net_error(), IsOk());
+ EXPECT_THAT(leaf_index_callback.leaf_index(), Eq(123456u));
+ }
+
+ // Check that the second query failed.
+ EXPECT_TRUE(audit_proof_callback.called());
+ if (audit_proof_callback.called()) {
+ EXPECT_THAT(audit_proof_callback.net_error(),
+ IsError(net::ERR_TEMPORARILY_THROTTLED));
+ EXPECT_THAT(audit_proof_callback.proof(), IsNull());
+ }
+}
+
INSTANTIATE_TEST_CASE_P(ReadMode,
LogDnsClientTest,
::testing::Values(net::IoMode::ASYNC,

Powered by Google App Engine
This is Rietveld 408576698