| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/certificate_transparency/log_dns_client.h" | 5 #include "components/certificate_transparency/log_dns_client.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <utility> | 9 #include <utility> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 // Each node is 32 bytes, with each byte having a different value. | 83 // Each node is 32 bytes, with each byte having a different value. |
| 84 for (size_t j = 0; j < crypto::kSHA256Length; ++j) { | 84 for (size_t j = 0; j < crypto::kSHA256Length; ++j) { |
| 85 node[j] = static_cast<char>((-127 + i + j) % 128); | 85 node[j] = static_cast<char>((-127 + i + j) % 128); |
| 86 } | 86 } |
| 87 audit_proof[i].assign(std::move(node)); | 87 audit_proof[i].assign(std::move(node)); |
| 88 } | 88 } |
| 89 | 89 |
| 90 return audit_proof; | 90 return audit_proof; |
| 91 } | 91 } |
| 92 | 92 |
| 93 // MockAuditProofCallback can be used as an AuditProofCallback. | 93 // MockCallback can be used as a base::Callback. |
| 94 // It will record the arguments it is invoked with and provides a helpful | 94 // It will record the arguments it is invoked with, which can be examined by |
| 95 // method for pumping the message loop until it is invoked. | 95 // calling args() or arg<N>(). |
| 96 class MockAuditProofCallback { | 96 // It only expects to be called once, but can be reused by calling Reset(). |
| 97 // Example: |
| 98 // MockCallback<int> mock; |
| 99 // foo.RegisterCallback(mock.AsCallback()); |
| 100 // foo.DoSomething(); |
| 101 // mock.WaitUntilRun(TestTimeouts::action_max_timeout()); |
| 102 // ASSERT_TRUE(mock.called()); |
| 103 // ASSERT_EQ(123, mock.arg<0>()); |
| 104 template <typename... Args> |
| 105 class MockCallback { |
| 97 public: | 106 public: |
| 98 MockAuditProofCallback() : called_(false) {} | 107 MockCallback() : called_(false) {} |
| 99 | 108 |
| 109 // Returns true if the callback has been invoked. |
| 100 bool called() const { return called_; } | 110 bool called() const { return called_; } |
| 101 net::Error result() const { return result_; } | |
| 102 const net::ct::MerkleAuditProof* proof() const { return proof_.get(); } | |
| 103 | 111 |
| 104 // Get this callback as an AuditProofCallback. | 112 // The arguments that the callback was called with. |
| 105 LogDnsClient::AuditProofCallback AsCallback() { | 113 const std::tuple<Args...>& args() const { |
| 106 return base::Bind(&MockAuditProofCallback::Run, base::Unretained(this)); | 114 DCHECK(called_); |
| 115 return args_; |
| 116 } |
| 117 |
| 118 // Gets a particular argument that the callback was invoked with. |
| 119 // For example, to get the first argument: mock_callback.arg<0>(); |
| 120 template <size_t N> |
| 121 const typename std::tuple_element<N, std::tuple<Args...>>::type& arg() const { |
| 122 DCHECK(called_); |
| 123 return std::get<N>(args_); |
| 124 } |
| 125 |
| 126 // Convert to a base::Callback. |
| 127 // TODO(robpercival): Could this reasonably be an implicit conversion? |
| 128 base::Callback<void(Args...)> AsCallback() { |
| 129 return base::Bind(&MockCallback::Run, base::Unretained(this)); |
| 107 } | 130 } |
| 108 | 131 |
| 109 // Wait until either the callback is invoked or the message loop goes idle | 132 // Wait until either the callback is invoked or the message loop goes idle |
| 110 // (after a specified |timeout|). Returns immediately if the callback has | 133 // (after a specified |timeout|). Returns immediately if the callback has |
| 111 // already been invoked. | 134 // already been invoked. |
| 112 void WaitUntilRun(base::TimeDelta timeout) { | 135 void WaitUntilRun(base::TimeDelta timeout) { |
| 113 if (called_) { | 136 if (called_) { |
| 114 return; | 137 return; |
| 115 } | 138 } |
| 116 | 139 |
| 117 // Pump the message loop until the the callback is invoked, which quits the | 140 // Pump the message loop until the the callback is invoked, which quits the |
| 118 // RunLoop, or a timeout expires and the message loop goes idle. | 141 // RunLoop, or a timeout expires and the message loop goes idle. |
| 119 run_loop_.reset(new base::RunLoop()); | 142 run_loop_.reset(new base::RunLoop()); |
| 120 base::Closure quit_closure = run_loop_->QuitWhenIdleClosure(); | 143 base::Closure quit_closure = run_loop_->QuitWhenIdleClosure(); |
| 121 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, | 144 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, |
| 122 quit_closure, timeout); | 145 quit_closure, timeout); |
| 123 run_loop_->Run(); | 146 run_loop_->Run(); |
| 124 run_loop_.reset(); | 147 run_loop_.reset(); |
| 125 } | 148 } |
| 126 | 149 |
| 150 void Reset() { |
| 151 called_ = false; |
| 152 args_ = std::tuple<Args...>(); |
| 153 } |
| 154 |
| 127 private: | 155 private: |
| 128 void Run(net::Error result, | 156 void Run(Args... args) { |
| 129 std::unique_ptr<net::ct::MerkleAuditProof> proof) { | 157 EXPECT_TRUE(!called_) << "Callback invoked more than once"; |
| 130 EXPECT_FALSE(called_) << "Callback invoked more than once"; | |
| 131 called_ = true; | 158 called_ = true; |
| 132 result_ = result; | 159 args_ = std::make_tuple(std::forward<Args>(args)...); |
| 133 proof_ = std::move(proof); | |
| 134 if (run_loop_) { | 160 if (run_loop_) { |
| 135 run_loop_->Quit(); | 161 run_loop_->Quit(); |
| 136 } | 162 } |
| 137 } | 163 } |
| 138 | 164 |
| 139 // True if the callback has been invoked. | 165 // True if the callback has been invoked. |
| 140 bool called_; | 166 bool called_; |
| 141 // The arguments that the callback was invoked with. | 167 // The arguments that the callback was invoked with. |
| 142 net::Error result_; | 168 std::tuple<Args...> args_; |
| 143 std::unique_ptr<net::ct::MerkleAuditProof> proof_; | |
| 144 // The RunLoop currently being used to pump the message loop, as a means to | 169 // The RunLoop currently being used to pump the message loop, as a means to |
| 145 // execute this callback. | 170 // execute this callback. |
| 146 std::unique_ptr<base::RunLoop> run_loop_; | 171 std::unique_ptr<base::RunLoop> run_loop_; |
| 147 }; | 172 }; |
| 148 | 173 |
| 174 class MockAuditProofCallback |
| 175 : public MockCallback<net::Error, |
| 176 std::unique_ptr<net::ct::MerkleAuditProof>> { |
| 177 public: |
| 178 net::Error result() const { return arg<0>(); } |
| 179 const net::ct::MerkleAuditProof* proof() const { return arg<1>().get(); } |
| 180 }; |
| 181 |
| 182 class MockNotThrottledCallback |
| 183 : public MockCallback<base::WeakPtr<LogDnsClient>> { |
| 184 public: |
| 185 const base::WeakPtr<LogDnsClient>& log_dns_client() const { return arg<0>(); } |
| 186 }; |
| 187 |
| 149 class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> { | 188 class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> { |
| 150 protected: | 189 protected: |
| 151 LogDnsClientTest() | 190 LogDnsClientTest() |
| 152 : network_change_notifier_(net::NetworkChangeNotifier::CreateMock()) { | 191 : network_change_notifier_(net::NetworkChangeNotifier::CreateMock()) { |
| 153 mock_dns_.SetSocketReadMode(GetParam()); | 192 mock_dns_.SetSocketReadMode(GetParam()); |
| 154 mock_dns_.InitializeDnsConfig(); | 193 mock_dns_.InitializeDnsConfig(); |
| 155 } | 194 } |
| 156 | 195 |
| 157 std::unique_ptr<LogDnsClient> CreateLogDnsClient( | 196 std::unique_ptr<LogDnsClient> CreateLogDnsClient( |
| 158 size_t kMaxConcurrentQueries) { | 197 size_t kMaxConcurrentQueries) { |
| (...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 803 callback3.WaitUntilRun(TestTimeouts::action_max_timeout()); | 842 callback3.WaitUntilRun(TestTimeouts::action_max_timeout()); |
| 804 ASSERT_TRUE(callback3.called()); | 843 ASSERT_TRUE(callback3.called()); |
| 805 EXPECT_THAT(callback3.result(), IsOk()); | 844 EXPECT_THAT(callback3.result(), IsOk()); |
| 806 ASSERT_THAT(callback3.proof(), NotNull()); | 845 ASSERT_THAT(callback3.proof(), NotNull()); |
| 807 EXPECT_THAT(callback3.proof()->leaf_index, Eq(666u)); | 846 EXPECT_THAT(callback3.proof()->leaf_index, Eq(666u)); |
| 808 // TODO(robpercival): Enable this once MerkleAuditProof has tree_size. | 847 // TODO(robpercival): Enable this once MerkleAuditProof has tree_size. |
| 809 // EXPECT_THAT(callback3.proof()->tree_size, Eq(999999)); | 848 // EXPECT_THAT(callback3.proof()->tree_size, Eq(999999)); |
| 810 EXPECT_THAT(callback3.proof()->nodes, Eq(audit_proof)); | 849 EXPECT_THAT(callback3.proof()->nodes, Eq(audit_proof)); |
| 811 } | 850 } |
| 812 | 851 |
| 852 TEST_P(LogDnsClientTest, NotifiesWhenNoLongerThrottled) { |
| 853 const std::vector<std::string> audit_proof = GetSampleAuditProof(20); |
| 854 |
| 855 mock_dns_.ExpectLeafIndexRequestAndResponse(kLeafIndexQnames[0], "123456"); |
| 856 mock_dns_.ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.", |
| 857 audit_proof.begin(), |
| 858 audit_proof.begin() + 7); |
| 859 mock_dns_.ExpectAuditProofRequestAndResponse("7.123456.999999.tree.ct.test.", |
| 860 audit_proof.begin() + 7, |
| 861 audit_proof.begin() + 14); |
| 862 mock_dns_.ExpectAuditProofRequestAndResponse("14.123456.999999.tree.ct.test.", |
| 863 audit_proof.begin() + 14, |
| 864 audit_proof.end()); |
| 865 |
| 866 const size_t kMaxConcurrentQueries = 1; |
| 867 std::unique_ptr<LogDnsClient> log_client = |
| 868 CreateLogDnsClient(kMaxConcurrentQueries); |
| 869 |
| 870 // Start a query. |
| 871 MockAuditProofCallback proof_callback1; |
| 872 ASSERT_THAT(log_client->QueryAuditProof("ct.test", kLeafHashes[0], 999999, |
| 873 proof_callback1.AsCallback()), |
| 874 IsError(net::ERR_IO_PENDING)); |
| 875 |
| 876 MockNotThrottledCallback not_throttled_callback; |
| 877 log_client->NotifyWhenNotThrottled(not_throttled_callback.AsCallback()); |
| 878 |
| 879 proof_callback1.WaitUntilRun(TestTimeouts::action_max_timeout()); |
| 880 ASSERT_TRUE(proof_callback1.called()); |
| 881 |
| 882 // The |not_throttled_callback| should not have fired quite yet, as the query |
| 883 // only just completed. Wait a little longer and check that it does fire. |
| 884 ASSERT_FALSE(not_throttled_callback.called()); |
| 885 not_throttled_callback.WaitUntilRun(TestTimeouts::action_max_timeout()); |
| 886 ASSERT_TRUE(not_throttled_callback.called()); |
| 887 |
| 888 // Start another query to check |not_throttled_callback| doesn't fire again. |
| 889 not_throttled_callback.Reset(); |
| 890 |
| 891 mock_dns_.ExpectLeafIndexRequestAndResponse(kLeafIndexQnames[1], "666"); |
| 892 mock_dns_.ExpectAuditProofRequestAndResponse("0.666.999999.tree.ct.test.", |
| 893 audit_proof.begin(), |
| 894 audit_proof.begin() + 7); |
| 895 mock_dns_.ExpectAuditProofRequestAndResponse("7.666.999999.tree.ct.test.", |
| 896 audit_proof.begin() + 7, |
| 897 audit_proof.begin() + 14); |
| 898 mock_dns_.ExpectAuditProofRequestAndResponse("14.666.999999.tree.ct.test.", |
| 899 audit_proof.begin() + 14, |
| 900 audit_proof.end()); |
| 901 |
| 902 MockAuditProofCallback proof_callback2; |
| 903 ASSERT_THAT(log_client->QueryAuditProof("ct.test", kLeafHashes[1], 999999, |
| 904 proof_callback2.AsCallback()), |
| 905 IsError(net::ERR_IO_PENDING)); |
| 906 |
| 907 // Give the query a chance to run. |
| 908 proof_callback2.WaitUntilRun(TestTimeouts::action_max_timeout()); |
| 909 |
| 910 ASSERT_TRUE(proof_callback2.called()); |
| 911 ASSERT_FALSE(not_throttled_callback.called()); |
| 912 } |
| 913 |
| 813 INSTANTIATE_TEST_CASE_P(ReadMode, | 914 INSTANTIATE_TEST_CASE_P(ReadMode, |
| 814 LogDnsClientTest, | 915 LogDnsClientTest, |
| 815 ::testing::Values(net::IoMode::ASYNC, | 916 ::testing::Values(net::IoMode::ASYNC, |
| 816 net::IoMode::SYNCHRONOUS)); | 917 net::IoMode::SYNCHRONOUS)); |
| 817 | 918 |
| 818 } // namespace | 919 } // namespace |
| 819 } // namespace certificate_transparency | 920 } // namespace certificate_transparency |
| OLD | NEW |