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
13 namespace rappor {
14
15 namespace {
16
17 const char kTestServerURL[] = "http://a.com/";
18 const char kTestMimeType[] = "text/plain";
19
20 class TestLogUploader : public LogUploader {
21 public:
TestLogUploader(net::URLRequestContextGetter * request_context)22 TestLogUploader(net::URLRequestContextGetter* request_context) :
23 LogUploader(GURL(kTestServerURL), kTestMimeType, request_context) {
24 }
25
last_interval_set() const26 base::TimeDelta last_interval_set() const { return last_interval_set_; };
27
StartUpload()28 void StartUpload() {
29 last_interval_set_ = base::TimeDelta();
30 StartScheduledUpload();
31 }
32
BackOff(base::TimeDelta t)33 static base::TimeDelta BackOff(base::TimeDelta t) {
34 return LogUploader::BackOffUploadInterval(t);
35 }
36
37 protected:
IsUploadScheduled() const38 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.
ScheduleNextUpload(base::TimeDelta interval)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
56 class LogUploaderTest : public testing::Test {
57 public:
LogUploaderTest()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
TEST_F(LogUploaderTest,Success)72 TEST_F(LogUploaderTest, Success) {
73 TestLogUploader uploader(request_context_);
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
TEST_F(LogUploaderTest,Rejection)86 TEST_F(LogUploaderTest, Rejection) {
87 TestLogUploader uploader(request_context_);
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
TEST_F(LogUploaderTest,Failure)100 TEST_F(LogUploaderTest, Failure) {
101 TestLogUploader uploader(request_context_);
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
TEST_F(LogUploaderTest,Backoff)142 TEST_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