1// Copyright 2013 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 <cmath>
6
7#include "base/command_line.h"
8#include "base/format_macros.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/message_loop/message_loop.h"
11#include "base/strings/stringprintf.h"
12#include "components/autofill/content/browser/autocheckout/whitelist_manager.h"
13#include "components/autofill/core/browser/autofill_metrics.h"
14#include "components/autofill/core/common/autofill_switches.h"
15#include "content/public/test/test_browser_thread_bundle.h"
16#include "net/base/net_errors.h"
17#include "net/http/http_status_code.h"
18#include "net/url_request/test_url_fetcher_factory.h"
19#include "net/url_request/url_fetcher_delegate.h"
20#include "net/url_request/url_request_status.h"
21#include "testing/gmock/include/gmock/gmock.h"
22#include "testing/gtest/include/gtest/gtest.h"
23#include "url/gurl.h"
24
25namespace {
26
27const int64 kTestDownloadInterval = 3;  // 3 seconds
28
29// First 4 retry delays are 3, 18, 108, 648 seconds, and following retries
30// capped at one hour.
31const int64 kBackoffDelaysInMs[] = {
32    3000, 18000, 108000, 648000, 3600000, 3600000 };
33
34const char kDownloadWhitelistResponse[] =
35    "https://www.merchant1.com/checkout/\n"
36    "https://cart.merchant2.com/";
37
38}  // namespace
39
40namespace autofill {
41namespace autocheckout {
42
43class WhitelistManagerTest;
44
45class MockAutofillMetrics : public AutofillMetrics {
46 public:
47  MockAutofillMetrics() {}
48  MOCK_CONST_METHOD2(LogAutocheckoutWhitelistDownloadDuration,
49      void(const base::TimeDelta& duration,
50           AutofillMetrics::AutocheckoutWhitelistDownloadStatus));
51 private:
52  DISALLOW_COPY_AND_ASSIGN(MockAutofillMetrics);
53};
54
55class TestWhitelistManager : public WhitelistManager {
56 public:
57  TestWhitelistManager()
58      : WhitelistManager(),
59        did_start_download_timer_(false) {}
60
61  virtual void ScheduleDownload(base::TimeDelta interval) OVERRIDE {
62    did_start_download_timer_ = false;
63    download_interval_ = interval;
64    return WhitelistManager::ScheduleDownload(interval);
65  }
66
67  virtual void StartDownloadTimer(base::TimeDelta interval) OVERRIDE {
68    WhitelistManager::StartDownloadTimer(interval);
69    did_start_download_timer_ = true;
70  }
71
72  bool did_start_download_timer() const {
73    return did_start_download_timer_;
74  }
75
76  void TriggerDownload() {
77    WhitelistManager::TriggerDownload();
78  }
79
80  void StopDownloadTimer() {
81    WhitelistManager::StopDownloadTimer();
82  }
83
84  const base::TimeDelta& download_interval() const {
85    return download_interval_;
86  }
87
88  const std::vector<std::string>& url_prefixes() const {
89    return WhitelistManager::url_prefixes();
90  }
91
92  virtual const AutofillMetrics& GetMetricLogger() const OVERRIDE {
93      return mock_metrics_logger_;
94  }
95
96 private:
97  bool did_start_download_timer_;
98  base::TimeDelta download_interval_;
99
100  MockAutofillMetrics mock_metrics_logger_;
101
102  DISALLOW_COPY_AND_ASSIGN(TestWhitelistManager);
103};
104
105class WhitelistManagerTest : public testing::Test {
106 public:
107  WhitelistManagerTest()
108      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
109
110 protected:
111  void CreateWhitelistManager() {
112    if (!whitelist_manager_.get()) {
113      whitelist_manager_.reset(new TestWhitelistManager());
114    }
115  }
116
117  void DownloadWhitelist(int response_code, const std::string& response) {
118    // Create and register factory.
119    net::TestURLFetcherFactory factory;
120
121    CreateWhitelistManager();
122
123    AutofillMetrics::AutocheckoutWhitelistDownloadStatus status;
124    if (response_code == net::HTTP_OK)
125      status = AutofillMetrics::AUTOCHECKOUT_WHITELIST_DOWNLOAD_SUCCEEDED;
126    else
127      status = AutofillMetrics::AUTOCHECKOUT_WHITELIST_DOWNLOAD_FAILED;
128    EXPECT_CALL(
129        static_cast<const MockAutofillMetrics&>(
130            whitelist_manager_->GetMetricLogger()),
131        LogAutocheckoutWhitelistDownloadDuration(testing::_, status)).Times(1);
132
133    whitelist_manager_->TriggerDownload();
134    net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
135    ASSERT_TRUE(fetcher);
136    fetcher->set_response_code(response_code);
137    fetcher->SetResponseString(response);
138    fetcher->delegate()->OnURLFetchComplete(fetcher);
139  }
140
141 protected:
142  scoped_ptr<TestWhitelistManager> whitelist_manager_;
143
144 private:
145  content::TestBrowserThreadBundle thread_bundle_;
146};
147
148TEST_F(WhitelistManagerTest, DownloadWhitelist) {
149  CommandLine::ForCurrentProcess()->AppendSwitch(
150      switches::kEnableExperimentalFormFilling);
151  DownloadWhitelist(net::HTTP_OK, kDownloadWhitelistResponse);
152  ASSERT_EQ(2U, whitelist_manager_->url_prefixes().size());
153  EXPECT_EQ("https://www.merchant1.com/checkout/",
154            whitelist_manager_->url_prefixes()[0]);
155  EXPECT_EQ("https://cart.merchant2.com/",
156            whitelist_manager_->url_prefixes()[1]);
157}
158
159TEST_F(WhitelistManagerTest, DoNotDownloadWhitelistWhenSwitchIsOff) {
160  CreateWhitelistManager();
161  whitelist_manager_->ScheduleDownload(
162      base::TimeDelta::FromSeconds(kTestDownloadInterval));
163  EXPECT_FALSE(whitelist_manager_->did_start_download_timer());
164}
165
166TEST_F(WhitelistManagerTest, DoNotDownloadWhitelistIfAlreadyScheduled) {
167  CommandLine::ForCurrentProcess()->AppendSwitch(
168      switches::kEnableExperimentalFormFilling);
169  CreateWhitelistManager();
170  // First attempt should schedule a download.
171  whitelist_manager_->ScheduleDownload(
172      base::TimeDelta::FromSeconds(kTestDownloadInterval));
173  EXPECT_TRUE(whitelist_manager_->did_start_download_timer());
174  // Second attempt should NOT schedule a download while there is already one.
175  whitelist_manager_->ScheduleDownload(
176      base::TimeDelta::FromSeconds(kTestDownloadInterval));
177  EXPECT_FALSE(whitelist_manager_->did_start_download_timer());
178  // It should schedule a new download when not in backoff mode.
179  whitelist_manager_->StopDownloadTimer();
180  whitelist_manager_->ScheduleDownload(
181      base::TimeDelta::FromSeconds(kTestDownloadInterval));
182  EXPECT_TRUE(whitelist_manager_->did_start_download_timer());
183}
184
185TEST_F(WhitelistManagerTest, DownloadWhitelistFailed) {
186  CommandLine::ForCurrentProcess()->AppendSwitch(
187      switches::kEnableExperimentalFormFilling);
188  DownloadWhitelist(net::HTTP_INTERNAL_SERVER_ERROR,
189                    kDownloadWhitelistResponse);
190  EXPECT_EQ(0U, whitelist_manager_->url_prefixes().size());
191
192  whitelist_manager_->StopDownloadTimer();
193  DownloadWhitelist(net::HTTP_OK, kDownloadWhitelistResponse);
194  EXPECT_EQ(2U, whitelist_manager_->url_prefixes().size());
195
196  whitelist_manager_->StopDownloadTimer();
197  DownloadWhitelist(net::HTTP_INTERNAL_SERVER_ERROR,
198                    kDownloadWhitelistResponse);
199  EXPECT_EQ(2U, whitelist_manager_->url_prefixes().size());
200}
201
202TEST_F(WhitelistManagerTest, DownloadWhitelistRetry) {
203  CommandLine::ForCurrentProcess()->AppendSwitch(
204      switches::kEnableExperimentalFormFilling);
205
206  for (size_t i = 0; i < arraysize(kBackoffDelaysInMs); ++i) {
207    DownloadWhitelist(net::HTTP_INTERNAL_SERVER_ERROR,
208                      kDownloadWhitelistResponse);
209    SCOPED_TRACE(base::StringPrintf("Testing retry %" PRIuS
210                                    ", expecting delay: %" PRId64,
211                                    i,
212                                    kBackoffDelaysInMs[i]));
213    EXPECT_EQ(
214        kBackoffDelaysInMs[i],
215        whitelist_manager_->download_interval().InMillisecondsRoundedUp());
216  }
217}
218
219TEST_F(WhitelistManagerTest, GetMatchedURLPrefix) {
220  CommandLine::ForCurrentProcess()->AppendSwitch(
221      switches::kEnableExperimentalFormFilling);
222  DownloadWhitelist(net::HTTP_OK, kDownloadWhitelistResponse);
223  EXPECT_EQ(2U, whitelist_manager_->url_prefixes().size());
224
225  // Empty url.
226  EXPECT_EQ(std::string(),
227            whitelist_manager_->GetMatchedURLPrefix(GURL(std::string())));
228  EXPECT_EQ(std::string(),
229            whitelist_manager_->GetMatchedURLPrefix(GURL()));
230
231  // Positive tests.
232  EXPECT_EQ("https://www.merchant1.com/checkout/",
233            whitelist_manager_->GetMatchedURLPrefix(
234                GURL("https://www.merchant1.com/checkout/")));
235  EXPECT_EQ("https://www.merchant1.com/checkout/",
236            whitelist_manager_->GetMatchedURLPrefix(
237                GURL("https://www.merchant1.com/checkout/Shipping")));
238  EXPECT_EQ("https://www.merchant1.com/checkout/",
239            whitelist_manager_->GetMatchedURLPrefix(
240                GURL("https://www.merchant1.com/checkout/?a=b&c=d")));
241  EXPECT_EQ("https://cart.merchant2.com/",
242            whitelist_manager_->GetMatchedURLPrefix(
243                GURL("https://cart.merchant2.com/")));
244  EXPECT_EQ("https://cart.merchant2.com/",
245            whitelist_manager_->GetMatchedURLPrefix(
246                GURL("https://cart.merchant2.com/ShippingInfo")));
247  EXPECT_EQ("https://cart.merchant2.com/",
248            whitelist_manager_->GetMatchedURLPrefix(
249                GURL("https://cart.merchant2.com/ShippingInfo?a=b&c=d")));
250
251  // Negative tests.
252  EXPECT_EQ(std::string(),
253            whitelist_manager_->GetMatchedURLPrefix(
254                GURL("https://www.merchant1.com/checkout")));
255  EXPECT_EQ(std::string(),
256            whitelist_manager_->GetMatchedURLPrefix(
257                GURL("https://www.merchant1.com/")));
258  EXPECT_EQ(std::string(),
259            whitelist_manager_->GetMatchedURLPrefix(
260                GURL("https://www.merchant1.com/Building")));
261  EXPECT_EQ(std::string(),
262            whitelist_manager_->GetMatchedURLPrefix(
263                GURL("https://www.merchant2.com/cart")));
264  EXPECT_EQ(std::string(),
265            whitelist_manager_->GetMatchedURLPrefix(
266                GURL("a random string")));
267
268  // Test different cases in schema, host and path.
269  EXPECT_EQ(std::string(),
270            whitelist_manager_->GetMatchedURLPrefix(
271                GURL("http://www.merchant1.com/checkout/")));
272  EXPECT_EQ(std::string(),
273            whitelist_manager_->GetMatchedURLPrefix(
274                GURL("www.merchant1.com/checkout/")));
275  EXPECT_EQ("https://www.merchant1.com/checkout/",
276            whitelist_manager_->GetMatchedURLPrefix(
277                GURL("https://www.Merchant1.com/checkout/")));
278  EXPECT_EQ(std::string(),
279            whitelist_manager_->GetMatchedURLPrefix(
280                GURL("https://www.merchant1.com/CheckOut/")));
281}
282
283TEST_F(WhitelistManagerTest, BypassWhitelist) {
284  CommandLine::ForCurrentProcess()->AppendSwitch(
285      switches::kEnableExperimentalFormFilling);
286  CommandLine::ForCurrentProcess()->AppendSwitch(
287      switches::kBypassAutocheckoutWhitelist);
288  DownloadWhitelist(net::HTTP_OK, kDownloadWhitelistResponse);
289  EXPECT_EQ(2U, whitelist_manager_->url_prefixes().size());
290
291  // Empty url.
292  EXPECT_EQ(std::string(),
293            whitelist_manager_->GetMatchedURLPrefix(GURL(std::string())));
294  // Positive tests.
295  EXPECT_EQ("https://www.merchant1.com/checkout/",
296            whitelist_manager_->GetMatchedURLPrefix(
297                GURL("https://www.merchant1.com/checkout/")));
298  EXPECT_EQ("https://cart.merchant2.com/",
299            whitelist_manager_->GetMatchedURLPrefix(
300                GURL("https://cart.merchant2.com/ShippingInfo?a=b&c=d")));
301  // Bypass other urls.
302  EXPECT_EQ(std::string("https://bypass.me/"),
303            whitelist_manager_->GetMatchedURLPrefix(
304                GURL("https://bypass.me/")));
305}
306
307}  // namespace autocheckout
308}  // namespace autofill
309
310