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/data_reduction_proxy/browser/data_reduction_proxy_config_service.h"
6
7#include <string>
8
9#include "base/bind.h"
10#include "base/memory/ref_counted.h"
11#include "base/message_loop/message_loop.h"
12#include "base/test/test_simple_task_runner.h"
13#include "testing/gmock/include/gmock/gmock.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16using testing::Mock;
17
18namespace {
19
20// Test system proxy rules.
21static const char kSystemProxyRules[] = "http=http://system.com:80,direct://";
22
23// Test data reduction proxy rules.
24static const char kDataReductionProxyRules[] =
25    "http=https://foo.com:443,http://bar.com:80,direct://";
26
27// Test data reduction proxy rules when in restricted mode.
28static const char kDataReductionProxyRestrictedRules[] =
29    "http=http://bar.com:80,direct://";
30
31}  // namespace
32
33namespace data_reduction_proxy {
34
35class TestProxyConfigService : public net::ProxyConfigService {
36 public:
37  TestProxyConfigService()
38      : availability_(net::ProxyConfigService::CONFIG_VALID) {
39    config_.proxy_rules().ParseFromString(kSystemProxyRules);
40  }
41
42  void SetProxyConfig(const net::ProxyConfig config,
43                      ConfigAvailability availability) {
44    config_ = config;
45    availability_ = availability;
46    FOR_EACH_OBSERVER(net::ProxyConfigService::Observer, observers_,
47                      OnProxyConfigChanged(config, availability));
48  }
49
50  virtual void AddObserver(
51      net::ProxyConfigService::Observer* observer) OVERRIDE {
52    observers_.AddObserver(observer);
53  }
54
55  virtual void RemoveObserver(
56      net::ProxyConfigService::Observer* observer) OVERRIDE {
57    observers_.RemoveObserver(observer);
58  }
59
60  virtual ConfigAvailability GetLatestProxyConfig(
61      net::ProxyConfig* config) OVERRIDE {
62    *config = config_;
63    return availability_;
64  }
65
66 private:
67  net::ProxyConfig config_;
68  ConfigAvailability availability_;
69  ObserverList<net::ProxyConfigService::Observer, true> observers_;
70};
71
72
73// A mock observer for capturing callbacks.
74class MockObserver : public net::ProxyConfigService::Observer {
75 public:
76  MOCK_METHOD2(OnProxyConfigChanged,
77               void(const net::ProxyConfig&,
78                    net::ProxyConfigService::ConfigAvailability));
79};
80
81
82class DataReductionProxyConfigServiceTest : public testing::Test {
83 public:
84  virtual void SetUp() {
85    observer_.reset(new MockObserver());
86    base_service_ = new TestProxyConfigService();
87    scoped_ptr<net::ProxyConfigService> base_service(base_service_);
88    config_service_.reset(
89        new DataReductionProxyConfigService(base_service.Pass()));
90  }
91
92  void EnableDataReductionProxy(bool data_reduction_proxy_enabled) {
93    config_service_->enabled_ = data_reduction_proxy_enabled;
94    config_service_->config_.proxy_rules().ParseFromString(
95        kDataReductionProxyRules);
96  }
97
98  scoped_ptr<net::ProxyConfigService::Observer> observer_;
99
100  // Holds a weak pointer to the base service. Ownership is passed to
101  // |config_service_|.
102  TestProxyConfigService* base_service_;
103
104  scoped_ptr<DataReductionProxyConfigService> config_service_;
105};
106
107// Compares proxy configurations, but allows different identifiers.
108MATCHER_P(ProxyConfigMatches, config, "") {
109  net::ProxyConfig reference(config);
110  reference.set_id(arg.id());
111  return reference.Equals(arg);
112}
113
114TEST_F(DataReductionProxyConfigServiceTest, GetLatestProxyConfigEnabled) {
115  // Set up the |config_service_| as though Enable had been previously called
116  // and check that |GetLatestProxyConfigEnabled| return rules for the data
117  // reduction proxy.
118  EnableDataReductionProxy(true);
119  net::ProxyConfig::ProxyRules expected_rules;
120  expected_rules.ParseFromString(kDataReductionProxyRules);
121  net::ProxyConfig latest_config;
122  EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
123            config_service_->GetLatestProxyConfig(&latest_config));
124  ASSERT_TRUE(latest_config.proxy_rules().Equals(expected_rules));
125}
126
127TEST_F(DataReductionProxyConfigServiceTest, GetLatestProxyConfigDisabledValid) {
128  // Set up the |config_service_| with the data reduction proxy disabled and
129  // check that the underlying system config is returned.
130  EnableDataReductionProxy(false);
131  net::ProxyConfig::ProxyRules expected_rules;
132  expected_rules.ParseFromString(kSystemProxyRules);
133  net::ProxyConfig latest_config;
134  EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
135            config_service_->GetLatestProxyConfig(&latest_config));
136  ASSERT_TRUE(latest_config.proxy_rules().Equals(expected_rules));
137}
138
139TEST_F(DataReductionProxyConfigServiceTest, GetLatestProxyConfigDisabledUnset) {
140  // Set up the |config_service_| with the data reduction proxy disabled and
141  // check that direct is returned if the the underlying system config is unset.
142  EnableDataReductionProxy(false);
143  base_service_->SetProxyConfig(net::ProxyConfig(),
144                                net::ProxyConfigService::CONFIG_UNSET);
145  net::ProxyConfig latest_config;
146  EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID,
147            config_service_->GetLatestProxyConfig(&latest_config));
148  ASSERT_TRUE(latest_config.Equals(net::ProxyConfig()));
149}
150
151TEST_F(DataReductionProxyConfigServiceTest, UpdateProxyConfig) {
152  MockObserver observer;
153  base::MessageLoopForUI loop;
154  config_service_->AddObserver(&observer);
155  // Firing the observers in the delegate should trigger a notification.
156  net::ProxyConfig config2;
157  config2.set_auto_detect(true);
158  EXPECT_CALL(observer, OnProxyConfigChanged(
159      ProxyConfigMatches(config2),
160      net::ProxyConfigService::CONFIG_VALID)).Times(1);
161  base_service_->SetProxyConfig(config2, net::ProxyConfigService::CONFIG_VALID);
162  loop.RunUntilIdle();
163  Mock::VerifyAndClearExpectations(&observer);
164
165  // Enable the data reduction proxy, which should trigger a notification.
166  net::ProxyConfig system_config;
167  system_config.proxy_rules().ParseFromString(kSystemProxyRules);
168  base_service_->SetProxyConfig(system_config,
169                                net::ProxyConfigService::CONFIG_VALID);
170  net::ProxyConfig data_reduction_proxy_config;
171  data_reduction_proxy_config.proxy_rules().ParseFromString(
172      kDataReductionProxyRules);
173
174  EXPECT_CALL(observer, OnProxyConfigChanged(
175      ProxyConfigMatches(data_reduction_proxy_config),
176      net::ProxyConfigService::CONFIG_VALID)).Times(1);
177  config_service_->UpdateProxyConfig(true, data_reduction_proxy_config);
178  loop.RunUntilIdle();
179  Mock::VerifyAndClearExpectations(&observer);
180
181
182  // Disable the data reduction proxy, which should trigger a notification.
183  base_service_->SetProxyConfig(system_config,
184                                net::ProxyConfigService::CONFIG_VALID);
185  EXPECT_CALL(observer, OnProxyConfigChanged(
186                  ProxyConfigMatches(system_config),
187                  net::ProxyConfigService::CONFIG_VALID)).Times(1);
188  config_service_->UpdateProxyConfig(false, data_reduction_proxy_config);
189  loop.RunUntilIdle();
190  Mock::VerifyAndClearExpectations(&observer);
191
192  config_service_->RemoveObserver(&observer);
193}
194
195TEST_F(DataReductionProxyConfigServiceTest, TrackerEnable) {
196  MockObserver observer;
197  //base::MessageLoopForUI loop;
198  config_service_->AddObserver(&observer);
199  scoped_refptr<base::TestSimpleTaskRunner> task_runner_(
200      new base::TestSimpleTaskRunner());
201  DataReductionProxyConfigTracker tracker(
202      base::Bind(&data_reduction_proxy::DataReductionProxyConfigService::
203                     UpdateProxyConfig,
204                 base::Unretained(config_service_.get())),
205      task_runner_.get());
206  net::ProxyConfig expected_config;
207  expected_config.proxy_rules().ParseFromString(kDataReductionProxyRules);
208  EXPECT_CALL(observer, OnProxyConfigChanged(
209                  ProxyConfigMatches(expected_config),
210                  net::ProxyConfigService::CONFIG_VALID)).Times(1);
211  tracker.Enable(false,
212                 false,
213                 "https://foo.com:443",
214                 "http://bar.com:80",
215                 "");
216  task_runner_->RunUntilIdle();
217  Mock::VerifyAndClearExpectations(&observer);
218
219  config_service_->RemoveObserver(&observer);
220}
221
222TEST_F(DataReductionProxyConfigServiceTest, TrackerEnableRestricted) {
223  MockObserver observer;
224  //base::MessageLoopForUI loop;
225  config_service_->AddObserver(&observer);
226  scoped_refptr<base::TestSimpleTaskRunner> task_runner_(
227      new base::TestSimpleTaskRunner());
228  DataReductionProxyConfigTracker tracker(
229      base::Bind(&data_reduction_proxy::DataReductionProxyConfigService::
230                     UpdateProxyConfig,
231                 base::Unretained(config_service_.get())),
232      task_runner_.get());
233  net::ProxyConfig expected_config;
234  expected_config.proxy_rules().ParseFromString(
235      kDataReductionProxyRestrictedRules);
236  EXPECT_CALL(observer, OnProxyConfigChanged(
237                  ProxyConfigMatches(expected_config),
238                  net::ProxyConfigService::CONFIG_VALID)).Times(1);
239  tracker.Enable(true,
240                 false,
241                 "https://foo.com:443",
242                 "http://bar.com:80",
243                 "");
244  task_runner_->RunUntilIdle();
245  Mock::VerifyAndClearExpectations(&observer);
246
247  config_service_->RemoveObserver(&observer);
248}
249
250TEST_F(DataReductionProxyConfigServiceTest, TrackerDisable) {
251  MockObserver observer;
252  //base::MessageLoopForUI loop;
253  config_service_->AddObserver(&observer);
254  scoped_refptr<base::TestSimpleTaskRunner> task_runner_(
255      new base::TestSimpleTaskRunner());
256  DataReductionProxyConfigTracker tracker(
257      base::Bind(&data_reduction_proxy::DataReductionProxyConfigService::
258                     UpdateProxyConfig,
259                 base::Unretained(config_service_.get())),
260      task_runner_.get());
261  net::ProxyConfig expected_config;
262  expected_config.proxy_rules().ParseFromString(kSystemProxyRules);
263  EXPECT_CALL(observer, OnProxyConfigChanged(
264                  ProxyConfigMatches(expected_config),
265                  net::ProxyConfigService::CONFIG_VALID)).Times(1);
266  tracker.Disable();
267  task_runner_->RunUntilIdle();
268  //loop.RunUntilIdle();
269  Mock::VerifyAndClearExpectations(&observer);
270
271  config_service_->RemoveObserver(&observer);
272}
273
274
275TEST_F(DataReductionProxyConfigServiceTest, TrackerBypassList) {
276  base::MessageLoopForUI loop;
277  scoped_refptr<base::TestSimpleTaskRunner> task_runner_(
278      new base::TestSimpleTaskRunner());
279  DataReductionProxyConfigTracker tracker(
280      base::Bind(&data_reduction_proxy::DataReductionProxyConfigService::
281                     UpdateProxyConfig,
282                 base::Unretained(config_service_.get())),
283      task_runner_.get());
284  tracker.AddHostPatternToBypass("http://www.google.com");
285  tracker.AddHostPatternToBypass("fefe:13::abc/33");
286  tracker.AddURLPatternToBypass("foo.org/images/*");
287  tracker.AddURLPatternToBypass("http://foo.com/*");
288  tracker.AddURLPatternToBypass("http://baz.com:22/bar/*");
289  tracker.AddURLPatternToBypass("http://*bat.com/bar/*");
290
291  std::string expected[] = {
292    "http://www.google.com",
293    "fefe:13::abc/33",
294    "foo.org",
295    "http://foo.com",
296    "http://baz.com:22",
297    "http://*bat.com"
298  };
299
300  ASSERT_EQ(tracker.bypass_rules_.size(), 6u);
301  int i = 0;
302  for (std::vector<std::string>::iterator it = tracker.bypass_rules_.begin();
303       it != tracker.bypass_rules_.end(); ++it) {
304    EXPECT_EQ(expected[i++], *it);
305  }
306}
307
308}  // namespace data_reduction_proxy
309