1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "components/domain_reliability/monitor.h" 6 7 #include <map> 8 #include <string> 9 #include <vector> 10 11 #include "base/bind.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "base/message_loop/message_loop_proxy.h" 14 #include "base/test/test_simple_task_runner.h" 15 #include "components/domain_reliability/baked_in_configs.h" 16 #include "components/domain_reliability/beacon.h" 17 #include "components/domain_reliability/config.h" 18 #include "components/domain_reliability/test_util.h" 19 #include "net/base/host_port_pair.h" 20 #include "net/base/load_flags.h" 21 #include "net/http/http_response_headers.h" 22 #include "net/http/http_util.h" 23 #include "net/url_request/url_request_context_getter.h" 24 #include "net/url_request/url_request_status.h" 25 #include "net/url_request/url_request_test_util.h" 26 #include "testing/gtest/include/gtest/gtest.h" 27 28 namespace domain_reliability { 29 30 namespace { 31 32 typedef std::vector<DomainReliabilityBeacon> BeaconVector; 33 34 static const size_t kAlwaysReportIndex = 0u; 35 static const size_t kNeverReportIndex = 1u; 36 37 scoped_refptr<net::HttpResponseHeaders> MakeHttpResponseHeaders( 38 const std::string& headers) { 39 return scoped_refptr<net::HttpResponseHeaders>( 40 new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( 41 headers.c_str(), headers.length()))); 42 } 43 44 } // namespace 45 46 class DomainReliabilityMonitorTest : public testing::Test { 47 protected: 48 typedef DomainReliabilityMonitor::RequestInfo RequestInfo; 49 50 DomainReliabilityMonitorTest() 51 : pref_task_runner_(new base::TestSimpleTaskRunner()), 52 network_task_runner_(new base::TestSimpleTaskRunner()), 53 url_request_context_getter_( 54 new net::TestURLRequestContextGetter(network_task_runner_)), 55 time_(new MockTime()), 56 monitor_("test-reporter", 57 pref_task_runner_, 58 network_task_runner_, 59 scoped_ptr<MockableTime>(time_)), 60 context_(NULL) { 61 monitor_.MoveToNetworkThread(); 62 monitor_.InitURLRequestContext(url_request_context_getter_); 63 monitor_.SetDiscardUploads(false); 64 context_ = monitor_.AddContextForTesting(MakeTestConfig()); 65 } 66 67 static RequestInfo MakeRequestInfo() { 68 RequestInfo request; 69 request.status = net::URLRequestStatus(); 70 request.status.set_status(net::URLRequestStatus::SUCCESS); 71 request.status.set_error(net::OK); 72 request.response_info.socket_address = 73 net::HostPortPair::FromString("12.34.56.78:80"); 74 request.response_info.headers = MakeHttpResponseHeaders( 75 "HTTP/1.1 200 OK\n\n"); 76 request.response_info.network_accessed = true; 77 request.response_info.was_fetched_via_proxy = false; 78 request.load_flags = 0; 79 request.is_upload = false; 80 return request; 81 } 82 83 void OnRequestLegComplete(const RequestInfo& info) { 84 monitor_.OnRequestLegComplete(info); 85 } 86 87 size_t CountPendingBeacons() { 88 BeaconVector beacons; 89 context_->GetQueuedBeaconsForTesting(&beacons); 90 return beacons.size(); 91 } 92 93 bool CheckRequestCounts(size_t index, 94 uint32 expected_successful, 95 uint32 expected_failed) { 96 return CheckRequestCounts(context_, 97 index, 98 expected_successful, 99 expected_failed); 100 } 101 102 bool CheckRequestCounts(DomainReliabilityContext* context, 103 size_t index, 104 uint32 expected_successful, 105 uint32 expected_failed) { 106 uint32 successful, failed; 107 context->GetRequestCountsForTesting(index, &successful, &failed); 108 EXPECT_EQ(expected_successful, successful); 109 EXPECT_EQ(expected_failed, failed); 110 return expected_successful == successful && expected_failed == failed; 111 } 112 113 DomainReliabilityContext* CreateAndAddContext(const std::string& domain) { 114 return monitor_.AddContextForTesting(MakeTestConfigWithDomain(domain)); 115 } 116 117 scoped_refptr<base::TestSimpleTaskRunner> pref_task_runner_; 118 scoped_refptr<base::TestSimpleTaskRunner> network_task_runner_; 119 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; 120 MockTime* time_; 121 DomainReliabilityMonitor monitor_; 122 DomainReliabilityContext* context_; 123 DomainReliabilityMonitor::RequestInfo request_; 124 }; 125 126 namespace { 127 128 TEST_F(DomainReliabilityMonitorTest, Create) { 129 EXPECT_EQ(0u, CountPendingBeacons()); 130 EXPECT_TRUE(CheckRequestCounts(kAlwaysReportIndex, 0u, 0u)); 131 EXPECT_TRUE(CheckRequestCounts(kNeverReportIndex, 0u, 0u)); 132 } 133 134 TEST_F(DomainReliabilityMonitorTest, NoContext) { 135 RequestInfo request = MakeRequestInfo(); 136 request.url = GURL("http://no-context/"); 137 OnRequestLegComplete(request); 138 139 EXPECT_EQ(0u, CountPendingBeacons()); 140 EXPECT_TRUE(CheckRequestCounts(kAlwaysReportIndex, 0u, 0u)); 141 EXPECT_TRUE(CheckRequestCounts(kNeverReportIndex, 0u, 0u)); 142 } 143 144 TEST_F(DomainReliabilityMonitorTest, NotReported) { 145 RequestInfo request = MakeRequestInfo(); 146 request.url = GURL("http://example/never_report"); 147 OnRequestLegComplete(request); 148 149 EXPECT_EQ(0u, CountPendingBeacons()); 150 EXPECT_TRUE(CheckRequestCounts(kNeverReportIndex, 1u, 0u)); 151 } 152 153 TEST_F(DomainReliabilityMonitorTest, NetworkFailure) { 154 RequestInfo request = MakeRequestInfo(); 155 request.url = GURL("http://example/always_report"); 156 request.status.set_status(net::URLRequestStatus::FAILED); 157 request.status.set_error(net::ERR_CONNECTION_RESET); 158 request.response_info.headers = NULL; 159 OnRequestLegComplete(request); 160 161 EXPECT_EQ(1u, CountPendingBeacons()); 162 EXPECT_TRUE(CheckRequestCounts(kAlwaysReportIndex, 0u, 1u)); 163 } 164 165 TEST_F(DomainReliabilityMonitorTest, ServerFailure) { 166 RequestInfo request = MakeRequestInfo(); 167 request.url = GURL("http://example/always_report"); 168 request.response_info.headers = 169 MakeHttpResponseHeaders("HTTP/1.1 500 :(\n\n"); 170 OnRequestLegComplete(request); 171 172 EXPECT_EQ(1u, CountPendingBeacons()); 173 EXPECT_TRUE(CheckRequestCounts(kAlwaysReportIndex, 0u, 1u)); 174 } 175 176 TEST_F(DomainReliabilityMonitorTest, NotReportedFailure) { 177 RequestInfo request = MakeRequestInfo(); 178 request.url = GURL("http://example/never_report"); 179 request.status.set_status(net::URLRequestStatus::FAILED); 180 request.status.set_error(net::ERR_CONNECTION_RESET); 181 OnRequestLegComplete(request); 182 183 EXPECT_EQ(0u, CountPendingBeacons()); 184 EXPECT_TRUE(CheckRequestCounts(kNeverReportIndex, 0u, 1u)); 185 } 186 187 TEST_F(DomainReliabilityMonitorTest, Request) { 188 RequestInfo request = MakeRequestInfo(); 189 request.url = GURL("http://example/always_report"); 190 OnRequestLegComplete(request); 191 192 EXPECT_EQ(1u, CountPendingBeacons()); 193 EXPECT_TRUE(CheckRequestCounts(kAlwaysReportIndex, 1u, 0u)); 194 } 195 196 // Make sure the monitor does not log requests that did not access the network. 197 TEST_F(DomainReliabilityMonitorTest, DidNotAccessNetwork) { 198 RequestInfo request = MakeRequestInfo(); 199 request.url = GURL("http://example/always_report"); 200 request.response_info.network_accessed = false; 201 OnRequestLegComplete(request); 202 203 EXPECT_EQ(0u, CountPendingBeacons()); 204 EXPECT_TRUE(CheckRequestCounts(kAlwaysReportIndex, 0u, 0u)); 205 } 206 207 // Make sure the monitor does not log requests that don't send cookies. 208 TEST_F(DomainReliabilityMonitorTest, DoNotSendCookies) { 209 RequestInfo request = MakeRequestInfo(); 210 request.url = GURL("http://example/always_report"); 211 request.load_flags = net::LOAD_DO_NOT_SEND_COOKIES; 212 OnRequestLegComplete(request); 213 214 EXPECT_EQ(0u, CountPendingBeacons()); 215 EXPECT_TRUE(CheckRequestCounts(kAlwaysReportIndex, 0u, 0u)); 216 } 217 218 // Make sure the monitor does not log upload requests. 219 TEST_F(DomainReliabilityMonitorTest, IsUpload) { 220 RequestInfo request = MakeRequestInfo(); 221 request.url = GURL("http://example/always_report"); 222 request.is_upload = true; 223 OnRequestLegComplete(request); 224 225 EXPECT_EQ(0u, CountPendingBeacons()); 226 EXPECT_TRUE(CheckRequestCounts(kAlwaysReportIndex, 0u, 0u)); 227 } 228 229 // Make sure the monitor does not log a network-local error. 230 TEST_F(DomainReliabilityMonitorTest, LocalError) { 231 RequestInfo request = MakeRequestInfo(); 232 request.url = GURL("http://example/always_report"); 233 request.status.set_status(net::URLRequestStatus::FAILED); 234 request.status.set_error(net::ERR_PROXY_CONNECTION_FAILED); 235 OnRequestLegComplete(request); 236 237 EXPECT_EQ(0u, CountPendingBeacons()); 238 EXPECT_TRUE(CheckRequestCounts(kAlwaysReportIndex, 0u, 0u)); 239 } 240 241 // Make sure the monitor does not log the proxy's IP if one was used. 242 TEST_F(DomainReliabilityMonitorTest, WasFetchedViaProxy) { 243 RequestInfo request = MakeRequestInfo(); 244 request.url = GURL("http://example/always_report"); 245 request.response_info.socket_address = 246 net::HostPortPair::FromString("127.0.0.1:3128"); 247 request.response_info.was_fetched_via_proxy = true; 248 OnRequestLegComplete(request); 249 250 BeaconVector beacons; 251 context_->GetQueuedBeaconsForTesting(&beacons); 252 EXPECT_EQ(1u, beacons.size()); 253 EXPECT_TRUE(beacons[0].server_ip.empty()); 254 255 EXPECT_TRUE(CheckRequestCounts(kAlwaysReportIndex, 1u, 0u)); 256 } 257 258 // Will fail when baked-in configs expire, as a reminder to update them. 259 // (Contact ttuttle (at) chromium.org if this starts failing.) 260 TEST_F(DomainReliabilityMonitorTest, AddBakedInConfigs) { 261 // AddBakedInConfigs DCHECKs that the baked-in configs parse correctly, so 262 // this unittest will fail if someone tries to add an invalid config to the 263 // source tree. 264 monitor_.AddBakedInConfigs(); 265 266 // Count the number of baked-in configs. 267 size_t num_baked_in_configs = 0; 268 for (const char* const* p = kBakedInJsonConfigs; *p; ++p) 269 ++num_baked_in_configs; 270 271 // The monitor should have contexts for all of the baked-in configs, plus the 272 // test one added in the test constructor. 273 EXPECT_EQ(num_baked_in_configs + 1, monitor_.contexts_size_for_testing()); 274 } 275 276 TEST_F(DomainReliabilityMonitorTest, ClearBeacons) { 277 // Initially the monitor should have just the test context, with no beacons. 278 EXPECT_EQ(1u, monitor_.contexts_size_for_testing()); 279 EXPECT_EQ(0u, CountPendingBeacons()); 280 EXPECT_TRUE(CheckRequestCounts(kAlwaysReportIndex, 0u, 0u)); 281 EXPECT_TRUE(CheckRequestCounts(kNeverReportIndex, 0u, 0u)); 282 283 // Add a beacon. 284 RequestInfo request = MakeRequestInfo(); 285 request.url = GURL("http://example/always_report"); 286 OnRequestLegComplete(request); 287 288 // Make sure it was added. 289 EXPECT_EQ(1u, CountPendingBeacons()); 290 EXPECT_TRUE(CheckRequestCounts(kAlwaysReportIndex, 1u, 0u)); 291 292 monitor_.ClearBrowsingData(CLEAR_BEACONS); 293 294 // Make sure the beacon was cleared, but not the contexts. 295 EXPECT_EQ(1u, monitor_.contexts_size_for_testing()); 296 EXPECT_EQ(0u, CountPendingBeacons()); 297 EXPECT_TRUE(CheckRequestCounts(kAlwaysReportIndex, 0u, 0u)); 298 EXPECT_TRUE(CheckRequestCounts(kNeverReportIndex, 0u, 0u)); 299 } 300 301 TEST_F(DomainReliabilityMonitorTest, ClearContexts) { 302 // Initially the monitor should have just the test context. 303 EXPECT_EQ(1u, monitor_.contexts_size_for_testing()); 304 305 monitor_.ClearBrowsingData(CLEAR_CONTEXTS); 306 307 // Clearing contexts should leave the monitor with none. 308 EXPECT_EQ(0u, monitor_.contexts_size_for_testing()); 309 } 310 311 TEST_F(DomainReliabilityMonitorTest, IgnoreSuccessError) { 312 RequestInfo request = MakeRequestInfo(); 313 request.url = GURL("http://example/always_report"); 314 request.status.set_error(net::ERR_QUIC_PROTOCOL_ERROR); 315 OnRequestLegComplete(request); 316 317 BeaconVector beacons; 318 context_->GetQueuedBeaconsForTesting(&beacons); 319 EXPECT_EQ(1u, beacons.size()); 320 EXPECT_EQ(net::OK, beacons[0].chrome_error); 321 322 EXPECT_TRUE(CheckRequestCounts(kAlwaysReportIndex, 1u, 0u)); 323 } 324 325 TEST_F(DomainReliabilityMonitorTest, WildcardMatchesSelf) { 326 DomainReliabilityContext* context = CreateAndAddContext("*.wildcard"); 327 328 RequestInfo request = MakeRequestInfo(); 329 request.url = GURL("http://wildcard/always_report"); 330 OnRequestLegComplete(request); 331 EXPECT_TRUE(CheckRequestCounts(context, kAlwaysReportIndex, 1u, 0u)); 332 } 333 334 TEST_F(DomainReliabilityMonitorTest, WildcardMatchesSubdomain) { 335 DomainReliabilityContext* context = CreateAndAddContext("*.wildcard"); 336 337 RequestInfo request = MakeRequestInfo(); 338 request.url = GURL("http://test.wildcard/always_report"); 339 OnRequestLegComplete(request); 340 EXPECT_TRUE(CheckRequestCounts(context, kAlwaysReportIndex, 1u, 0u)); 341 } 342 343 TEST_F(DomainReliabilityMonitorTest, WildcardDoesntMatchSubsubdomain) { 344 DomainReliabilityContext* context = CreateAndAddContext("*.wildcard"); 345 346 RequestInfo request = MakeRequestInfo(); 347 request.url = GURL("http://test.test.wildcard/always_report"); 348 OnRequestLegComplete(request); 349 EXPECT_TRUE(CheckRequestCounts(context, kAlwaysReportIndex, 0u, 0u)); 350 } 351 352 TEST_F(DomainReliabilityMonitorTest, WildcardPrefersSelfToSelfWildcard) { 353 DomainReliabilityContext* context1 = CreateAndAddContext("wildcard"); 354 DomainReliabilityContext* context2 = CreateAndAddContext("*.wildcard"); 355 356 RequestInfo request = MakeRequestInfo(); 357 request.url = GURL("http://wildcard/always_report"); 358 OnRequestLegComplete(request); 359 360 EXPECT_TRUE(CheckRequestCounts(context1, kAlwaysReportIndex, 1u, 0u)); 361 EXPECT_TRUE(CheckRequestCounts(context2, kAlwaysReportIndex, 0u, 0u)); 362 } 363 364 TEST_F(DomainReliabilityMonitorTest, WildcardPrefersSelfToParentWildcard) { 365 DomainReliabilityContext* context1 = CreateAndAddContext("test.wildcard"); 366 DomainReliabilityContext* context2 = CreateAndAddContext("*.wildcard"); 367 368 RequestInfo request = MakeRequestInfo(); 369 request.url = GURL("http://test.wildcard/always_report"); 370 OnRequestLegComplete(request); 371 372 EXPECT_TRUE(CheckRequestCounts(context1, kAlwaysReportIndex, 1u, 0u)); 373 EXPECT_TRUE(CheckRequestCounts(context2, kAlwaysReportIndex, 0u, 0u)); 374 } 375 376 TEST_F(DomainReliabilityMonitorTest, 377 WildcardPrefersSelfWildcardToParentWildcard) { 378 DomainReliabilityContext* context1 = CreateAndAddContext("*.test.wildcard"); 379 DomainReliabilityContext* context2 = CreateAndAddContext("*.wildcard"); 380 381 RequestInfo request = MakeRequestInfo(); 382 request.url = GURL("http://test.wildcard/always_report"); 383 OnRequestLegComplete(request); 384 385 EXPECT_TRUE(CheckRequestCounts(context1, kAlwaysReportIndex, 1u, 0u)); 386 EXPECT_TRUE(CheckRequestCounts(context2, kAlwaysReportIndex, 0u, 0u)); 387 } 388 389 } // namespace 390 391 } // namespace domain_reliability 392