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 |