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
28namespace domain_reliability {
29
30namespace {
31
32typedef std::vector<DomainReliabilityBeacon> BeaconVector;
33
34static const size_t kAlwaysReportIndex = 0u;
35static const size_t kNeverReportIndex = 1u;
36
37scoped_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
46class 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
126namespace {
127
128TEST_F(DomainReliabilityMonitorTest, Create) {
129  EXPECT_EQ(0u, CountPendingBeacons());
130  EXPECT_TRUE(CheckRequestCounts(kAlwaysReportIndex, 0u, 0u));
131  EXPECT_TRUE(CheckRequestCounts(kNeverReportIndex, 0u, 0u));
132}
133
134TEST_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
144TEST_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
153TEST_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
165TEST_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
176TEST_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
187TEST_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.
197TEST_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.
208TEST_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.
219TEST_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.
230TEST_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.
242TEST_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@chromium.org if this starts failing.)
260TEST_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
276TEST_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
301TEST_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
311TEST_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
325TEST_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
334TEST_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
343TEST_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
352TEST_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
364TEST_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
376TEST_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