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/rappor/log_uploader.h"
6
7#include "base/compiler_specific.h"
8#include "base/message_loop/message_loop_proxy.h"
9#include "net/url_request/test_url_fetcher_factory.h"
10#include "net/url_request/url_request_test_util.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13namespace rappor {
14
15namespace {
16
17const char kTestServerURL[] = "http://a.com/";
18const char kTestMimeType[] = "text/plain";
19
20class TestLogUploader : public LogUploader {
21 public:
22  TestLogUploader(net::URLRequestContextGetter* request_context) :
23      LogUploader(GURL(kTestServerURL), kTestMimeType, request_context) {
24  }
25
26  base::TimeDelta last_interval_set() const { return last_interval_set_; };
27
28  void StartUpload() {
29    last_interval_set_ = base::TimeDelta();
30    StartScheduledUpload();
31  }
32
33  static base::TimeDelta BackOff(base::TimeDelta t) {
34    return LogUploader::BackOffUploadInterval(t);
35  }
36
37 protected:
38  virtual bool IsUploadScheduled() const OVERRIDE {
39    return last_interval_set() != base::TimeDelta();
40  }
41
42  // Schedules a future call to StartScheduledUpload if one isn't already
43  // pending.
44  virtual void ScheduleNextUpload(base::TimeDelta interval) OVERRIDE {
45    EXPECT_EQ(last_interval_set(), base::TimeDelta());
46    last_interval_set_ = interval;
47  }
48
49  base::TimeDelta last_interval_set_;
50
51  DISALLOW_COPY_AND_ASSIGN(TestLogUploader);
52};
53
54}  // namespace
55
56class LogUploaderTest : public testing::Test {
57 public:
58  LogUploaderTest()
59      : request_context_(new net::TestURLRequestContextGetter(
60            base::MessageLoopProxy::current())),
61        factory_(NULL) {}
62
63 protected:
64  // Required for base::MessageLoopProxy::current().
65  base::MessageLoopForUI loop_;
66  scoped_refptr<net::TestURLRequestContextGetter> request_context_;
67  net::FakeURLFetcherFactory factory_;
68
69  DISALLOW_COPY_AND_ASSIGN(LogUploaderTest);
70};
71
72TEST_F(LogUploaderTest, Success) {
73  TestLogUploader uploader(request_context_.get());
74
75  factory_.SetFakeResponse(GURL(kTestServerURL),
76                           std::string(),
77                           net::HTTP_OK,
78                           net::URLRequestStatus::SUCCESS);
79
80  uploader.QueueLog("log1");
81  base::MessageLoop::current()->RunUntilIdle();
82  // Log should be discarded instead of retransmitted.
83  EXPECT_EQ(uploader.last_interval_set(), base::TimeDelta());
84}
85
86TEST_F(LogUploaderTest, Rejection) {
87  TestLogUploader uploader(request_context_.get());
88
89  factory_.SetFakeResponse(GURL(kTestServerURL),
90                           std::string(),
91                           net::HTTP_BAD_REQUEST,
92                           net::URLRequestStatus::SUCCESS);
93
94  uploader.QueueLog("log1");
95  base::MessageLoop::current()->RunUntilIdle();
96  // Log should be discarded instead of retransmitted.
97  EXPECT_EQ(uploader.last_interval_set(), base::TimeDelta());
98}
99
100TEST_F(LogUploaderTest, Failure) {
101  TestLogUploader uploader(request_context_.get());
102
103  factory_.SetFakeResponse(GURL(kTestServerURL),
104                           std::string(),
105                           net::HTTP_INTERNAL_SERVER_ERROR,
106                           net::URLRequestStatus::SUCCESS);
107
108  uploader.QueueLog("log1");
109  base::MessageLoop::current()->RunUntilIdle();
110  // Log should be scheduled for retransmission.
111  base::TimeDelta error_interval = uploader.last_interval_set();
112  EXPECT_GT(error_interval, base::TimeDelta());
113
114  for (int i = 0; i < 10; i++) {
115    uploader.QueueLog("logX");
116  }
117
118  // A second failure should lead to a longer interval, and the log should
119  // be discarded due to full queue.
120  uploader.StartUpload();
121  base::MessageLoop::current()->RunUntilIdle();
122  EXPECT_GT(uploader.last_interval_set(), error_interval);
123
124  factory_.SetFakeResponse(GURL(kTestServerURL),
125                           std::string(),
126                           net::HTTP_OK,
127                           net::URLRequestStatus::SUCCESS);
128
129  // A success should revert to base interval while queue is not empty.
130  for (int i = 0; i < 9; i++) {
131    uploader.StartUpload();
132    base::MessageLoop::current()->RunUntilIdle();
133    EXPECT_LT(uploader.last_interval_set(), error_interval);
134  }
135
136  // Queue should be empty.
137  uploader.StartUpload();
138  base::MessageLoop::current()->RunUntilIdle();
139  EXPECT_EQ(uploader.last_interval_set(), base::TimeDelta());
140}
141
142TEST_F(LogUploaderTest, Backoff) {
143  base::TimeDelta current = base::TimeDelta();
144  base::TimeDelta next = base::TimeDelta::FromSeconds(1);
145  // Backoff until the maximum is reached.
146  while (next > current) {
147    current = next;
148    next = TestLogUploader::BackOff(current);
149  }
150  // Maximum backoff should have been reached.
151  EXPECT_EQ(next, current);
152}
153
154}  // namespace rappor
155