proxy_config_service_impl_unittest.cc revision 5e3f23d412006dc4db4e659864679f29341e113f
1// Copyright (c) 2012 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 "chrome/browser/chromeos/proxy_config_service_impl.h"
6
7#include <vector>
8
9#include "base/format_macros.h"
10#include "base/json/json_writer.h"
11#include "base/logging.h"
12#include "base/message_loop.h"
13#include "base/prefs/testing_pref_service.h"
14#include "base/strings/stringprintf.h"
15#include "chrome/browser/chromeos/settings/cros_settings.h"
16#include "chrome/browser/chromeos/settings/device_settings_service.h"
17#include "chrome/browser/chromeos/ui_proxy_config.h"
18#include "chrome/common/pref_names.h"
19#include "chromeos/dbus/dbus_thread_manager.h"
20#include "chromeos/dbus/shill_profile_client.h"
21#include "chromeos/dbus/shill_service_client.h"
22#include "chromeos/network/network_handler.h"
23#include "chromeos/network/network_state.h"
24#include "chromeos/network/network_state_handler.h"
25#include "content/public/test/test_browser_thread.h"
26#include "net/proxy/proxy_config_service_common_unittest.h"
27#include "testing/gtest/include/gtest/gtest.h"
28#include "third_party/cros_system_api/dbus/service_constants.h"
29
30using content::BrowserThread;
31
32namespace chromeos {
33
34namespace {
35
36struct Input {
37  UIProxyConfig::Mode mode;
38  std::string pac_url;
39  std::string server;
40  std::string bypass_rules;
41};
42
43// Builds an identifier for each test in an array.
44#define TEST_DESC(desc) base::StringPrintf("at line %d <%s>", __LINE__, desc)
45
46// Shortcuts to declare enums within chromeos's ProxyConfig.
47#define MK_MODE(mode) UIProxyConfig::MODE_##mode
48
49// Inspired from net/proxy/proxy_config_service_linux_unittest.cc.
50const struct TestParams {
51  // Short description to identify the test
52  std::string description;
53
54  Input input;
55
56  // Expected outputs from fields of net::ProxyConfig (via IO).
57  bool auto_detect;
58  GURL pac_url;
59  net::ProxyRulesExpectation proxy_rules;
60} tests[] = {
61  {  // 0
62    TEST_DESC("No proxying"),
63
64    { // Input.
65      MK_MODE(DIRECT),  // mode
66    },
67
68    // Expected result.
69    false,                                   // auto_detect
70    GURL(),                                  // pac_url
71    net::ProxyRulesExpectation::Empty(),     // proxy_rules
72  },
73
74  {  // 1
75    TEST_DESC("Auto detect"),
76
77    { // Input.
78      MK_MODE(AUTO_DETECT),  // mode
79    },
80
81    // Expected result.
82    true,                                    // auto_detect
83    GURL(),                                  // pac_url
84    net::ProxyRulesExpectation::Empty(),     // proxy_rules
85  },
86
87  {  // 2
88    TEST_DESC("Valid PAC URL"),
89
90    { // Input.
91      MK_MODE(PAC_SCRIPT),     // mode
92      "http://wpad/wpad.dat",  // pac_url
93    },
94
95    // Expected result.
96    false,                                   // auto_detect
97    GURL("http://wpad/wpad.dat"),            // pac_url
98    net::ProxyRulesExpectation::Empty(),     // proxy_rules
99  },
100
101  {  // 3
102    TEST_DESC("Invalid PAC URL"),
103
104    { // Input.
105      MK_MODE(PAC_SCRIPT),  // mode
106      "wpad.dat",           // pac_url
107    },
108
109    // Expected result.
110    false,                                   // auto_detect
111    GURL(),                                  // pac_url
112    net::ProxyRulesExpectation::Empty(),     // proxy_rules
113  },
114
115  {  // 4
116    TEST_DESC("Single-host in proxy list"),
117
118    { // Input.
119      MK_MODE(SINGLE_PROXY),  // mode
120      "",                     // pac_url
121      "www.google.com",       // server
122    },
123
124    // Expected result.
125    false,                                   // auto_detect
126    GURL(),                                  // pac_url
127    net::ProxyRulesExpectation::Single(      // proxy_rules
128        "www.google.com:80",                 // single proxy
129        "<local>"),                          // bypass rules
130  },
131
132  {  // 5
133    TEST_DESC("Single-host, different port"),
134
135    { // Input.
136      MK_MODE(SINGLE_PROXY),  // mode
137      "",                     // pac_url
138      "www.google.com:99",    // server
139    },
140
141    // Expected result.
142    false,                                   // auto_detect
143    GURL(),                                  // pac_url
144    net::ProxyRulesExpectation::Single(      // proxy_rules
145        "www.google.com:99",                 // single
146        "<local>"),                          // bypass rules
147  },
148
149  {  // 6
150    TEST_DESC("Tolerate a scheme"),
151
152    { // Input.
153      MK_MODE(SINGLE_PROXY),       // mode
154      "",                          // pac_url
155      "http://www.google.com:99",  // server
156    },
157
158    // Expected result.
159    false,                                   // auto_detect
160    GURL(),                                  // pac_url
161    net::ProxyRulesExpectation::Single(      // proxy_rules
162        "www.google.com:99",                 // single proxy
163        "<local>"),                          // bypass rules
164  },
165
166  {  // 7
167    TEST_DESC("Per-scheme proxy rules"),
168
169    { // Input.
170      MK_MODE(PROXY_PER_SCHEME),  // mode
171      "",                         // pac_url
172      "http=www.google.com:80;https=https://www.foo.com:110;"
173      "ftp=ftp.foo.com:121;socks=socks5://socks.com:888",  // server
174    },
175
176    // Expected result.
177    false,                          // auto_detect
178    GURL(),                         // pac_url
179    net::ProxyRulesExpectation::PerSchemeWithSocks(  // proxy_rules
180        "www.google.com:80",        // http
181        "https://www.foo.com:110",  // https
182        "ftp.foo.com:121",          // ftp
183        "socks5://socks.com:888",   // fallback proxy
184        "<local>"),                 // bypass rules
185  },
186
187  {  // 8
188    TEST_DESC("Bypass rules"),
189
190    { // Input.
191      MK_MODE(SINGLE_PROXY),      // mode
192      "",                         // pac_url
193      "www.google.com",           // server
194      "*.google.com, *foo.com:99, 1.2.3.4:22, 127.0.0.1/8",  // bypass_rules
195    },
196
197    // Expected result.
198    false,                          // auto_detect
199    GURL(),                         // pac_url
200    net::ProxyRulesExpectation::Single(  // proxy_rules
201        "www.google.com:80",             // single proxy
202        // bypass_rules
203        "*.google.com,*foo.com:99,1.2.3.4:22,127.0.0.1/8,<local>"),
204  },
205};  // tests
206
207const char* kUserProfilePath = "user_profile";
208
209}  // namespace
210
211class ProxyConfigServiceImplTest : public testing::Test {
212 protected:
213  ProxyConfigServiceImplTest()
214      : ui_thread_(BrowserThread::UI, &loop_),
215        io_thread_(BrowserThread::IO, &loop_) {}
216
217  virtual void SetUp() {
218    DBusThreadManager::InitializeWithStub();
219    NetworkHandler::Initialize();
220
221    SetUpNetwork();
222
223    PrefProxyConfigTrackerImpl::RegisterPrefs(pref_service_.registry());
224    ProxyConfigServiceImpl::RegisterPrefs(pref_service_.registry());
225    proxy_config_service_.reset(new ChromeProxyConfigService(NULL));
226    config_service_impl_.reset(new ProxyConfigServiceImpl(&pref_service_));
227    config_service_impl_->SetChromeProxyConfigService(
228        proxy_config_service_.get());
229    // SetChromeProxyConfigService triggers update of initial prefs proxy
230    // config by tracker to chrome proxy config service, so flush all pending
231    // tasks so that tests start fresh.
232    loop_.RunUntilIdle();
233  }
234
235  void SetUpNetwork() {
236    ShillProfileClient::TestInterface* profile_test =
237        DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
238    ShillServiceClient::TestInterface* service_test =
239        DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
240
241    service_test->ClearServices();
242
243    // Sends a notification about the added profile.
244    profile_test->AddProfile(kUserProfilePath, "user_hash");
245
246    service_test->AddService("stub_wifi2", "wifi2_PSK",
247                             flimflam::kTypeWifi, flimflam::kStateOnline,
248                             true /* add to watchlist */);
249    service_test->SetServiceProperty("stub_wifi2",
250                                     flimflam::kGuidProperty,
251                                     base::StringValue("stub_wifi2"));
252    service_test->SetServiceProperty("stub_wifi2",
253                                     flimflam::kProfileProperty,
254                                     base::StringValue(kUserProfilePath));
255    profile_test->AddService("stub_wifi2");
256
257    loop_.RunUntilIdle();
258  }
259
260  virtual void TearDown() {
261    config_service_impl_->DetachFromPrefService();
262    loop_.RunUntilIdle();
263    config_service_impl_.reset();
264    proxy_config_service_.reset();
265    NetworkHandler::Shutdown();
266    DBusThreadManager::Shutdown();
267  }
268
269  void InitConfigWithTestInput(const Input& input,
270                               base::DictionaryValue* result) {
271    base::DictionaryValue* new_config = NULL;
272    switch (input.mode) {
273      case MK_MODE(DIRECT):
274        new_config = ProxyConfigDictionary::CreateDirect();
275        break;
276      case MK_MODE(AUTO_DETECT):
277        new_config = ProxyConfigDictionary::CreateAutoDetect();
278        break;
279      case MK_MODE(PAC_SCRIPT):
280        new_config =
281            ProxyConfigDictionary::CreatePacScript(input.pac_url, false);
282        break;
283      case MK_MODE(SINGLE_PROXY):
284      case MK_MODE(PROXY_PER_SCHEME):
285        new_config =
286          ProxyConfigDictionary::CreateFixedServers(input.server,
287                                                    input.bypass_rules);
288        break;
289    }
290    result->Swap(new_config);
291    delete new_config;
292  }
293
294  void SetConfig(base::DictionaryValue* pref_proxy_config_dict) {
295    std::string proxy_config;
296    if (pref_proxy_config_dict)
297      base::JSONWriter::Write(pref_proxy_config_dict, &proxy_config);
298
299    NetworkStateHandler* network_state_handler =
300        NetworkHandler::Get()->network_state_handler();
301    const NetworkState* network = network_state_handler->DefaultNetwork();
302    ASSERT_TRUE(network);
303    DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface()->
304        SetServiceProperty(network->path(),
305                           flimflam::kProxyConfigProperty,
306                           StringValue(proxy_config));
307  }
308
309  // Synchronously gets the latest proxy config.
310  void SyncGetLatestProxyConfig(net::ProxyConfig* config) {
311    *config = net::ProxyConfig();
312    // Let message loop process all messages. This will run
313    // ChromeProxyConfigService::UpdateProxyConfig, which is posted on IO from
314    // PrefProxyConfigTrackerImpl::OnProxyConfigChanged.
315    loop_.RunUntilIdle();
316    net::ProxyConfigService::ConfigAvailability availability =
317        proxy_config_service_->GetLatestProxyConfig(config);
318
319    EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID, availability);
320  }
321
322  base::MessageLoop loop_;
323  scoped_ptr<ChromeProxyConfigService> proxy_config_service_;
324  scoped_ptr<ProxyConfigServiceImpl> config_service_impl_;
325  TestingPrefServiceSimple pref_service_;
326
327 private:
328  ScopedTestDeviceSettingsService test_device_settings_service_;
329  ScopedTestCrosSettings test_cros_settings_;
330  content::TestBrowserThread ui_thread_;
331  content::TestBrowserThread io_thread_;
332};
333
334TEST_F(ProxyConfigServiceImplTest, NetworkProxy) {
335  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
336    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "] %s", i,
337                                    tests[i].description.c_str()));
338
339    base::DictionaryValue test_config;
340    InitConfigWithTestInput(tests[i].input, &test_config);
341    SetConfig(&test_config);
342
343    net::ProxyConfig config;
344    SyncGetLatestProxyConfig(&config);
345
346    EXPECT_EQ(tests[i].auto_detect, config.auto_detect());
347    EXPECT_EQ(tests[i].pac_url, config.pac_url());
348    EXPECT_TRUE(tests[i].proxy_rules.Matches(config.proxy_rules()));
349  }
350}
351
352TEST_F(ProxyConfigServiceImplTest, DynamicPrefsOverride) {
353  // Groupings of 3 test inputs to use for managed, recommended and network
354  // proxies respectively.  Only valid and non-direct test inputs are used.
355  const size_t proxies[][3] = {
356    { 1, 2, 4, },
357    { 1, 4, 2, },
358    { 4, 2, 1, },
359    { 2, 1, 4, },
360    { 2, 4, 5, },
361    { 2, 5, 4, },
362    { 5, 4, 2, },
363    { 4, 2, 5, },
364    { 4, 5, 6, },
365    { 4, 6, 5, },
366    { 6, 5, 4, },
367    { 5, 4, 6, },
368    { 5, 6, 7, },
369    { 5, 7, 6, },
370    { 7, 6, 5, },
371    { 6, 5, 7, },
372    { 6, 7, 8, },
373    { 6, 8, 7, },
374    { 8, 7, 6, },
375    { 7, 6, 8, },
376  };
377  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(proxies); ++i) {
378    const TestParams& managed_params = tests[proxies[i][0]];
379    const TestParams& recommended_params = tests[proxies[i][1]];
380    const TestParams& network_params = tests[proxies[i][2]];
381
382    SCOPED_TRACE(base::StringPrintf(
383        "Test[%" PRIuS "] managed=[%s], recommended=[%s], network=[%s]", i,
384        managed_params.description.c_str(),
385        recommended_params.description.c_str(),
386        network_params.description.c_str()));
387
388    base::DictionaryValue managed_config;
389    InitConfigWithTestInput(managed_params.input, &managed_config);
390    base::DictionaryValue recommended_config;
391    InitConfigWithTestInput(recommended_params.input, &recommended_config);
392    base::DictionaryValue network_config;
393    InitConfigWithTestInput(network_params.input, &network_config);
394
395    // Managed proxy pref should take effect over recommended proxy and
396    // non-existent network proxy.
397    SetConfig(NULL);
398    pref_service_.SetManagedPref(prefs::kProxy, managed_config.DeepCopy());
399    pref_service_.SetRecommendedPref(prefs::kProxy,
400                                     recommended_config.DeepCopy());
401    net::ProxyConfig actual_config;
402    SyncGetLatestProxyConfig(&actual_config);
403    EXPECT_EQ(managed_params.auto_detect, actual_config.auto_detect());
404    EXPECT_EQ(managed_params.pac_url, actual_config.pac_url());
405    EXPECT_TRUE(managed_params.proxy_rules.Matches(
406        actual_config.proxy_rules()));
407
408    // Recommended proxy pref should take effect when managed proxy pref is
409    // removed.
410    pref_service_.RemoveManagedPref(prefs::kProxy);
411    SyncGetLatestProxyConfig(&actual_config);
412    EXPECT_EQ(recommended_params.auto_detect, actual_config.auto_detect());
413    EXPECT_EQ(recommended_params.pac_url, actual_config.pac_url());
414    EXPECT_TRUE(recommended_params.proxy_rules.Matches(
415        actual_config.proxy_rules()));
416
417    // Network proxy should take take effect over recommended proxy pref.
418    SetConfig(&network_config);
419    SyncGetLatestProxyConfig(&actual_config);
420    EXPECT_EQ(network_params.auto_detect, actual_config.auto_detect());
421    EXPECT_EQ(network_params.pac_url, actual_config.pac_url());
422    EXPECT_TRUE(network_params.proxy_rules.Matches(
423        actual_config.proxy_rules()));
424
425    // Managed proxy pref should take effect over network proxy.
426    pref_service_.SetManagedPref(prefs::kProxy, managed_config.DeepCopy());
427    SyncGetLatestProxyConfig(&actual_config);
428    EXPECT_EQ(managed_params.auto_detect, actual_config.auto_detect());
429    EXPECT_EQ(managed_params.pac_url, actual_config.pac_url());
430    EXPECT_TRUE(managed_params.proxy_rules.Matches(
431        actual_config.proxy_rules()));
432
433    // Network proxy should take effect over recommended proxy pref when managed
434    // proxy pref is removed.
435    pref_service_.RemoveManagedPref(prefs::kProxy);
436    SyncGetLatestProxyConfig(&actual_config);
437    EXPECT_EQ(network_params.auto_detect, actual_config.auto_detect());
438    EXPECT_EQ(network_params.pac_url, actual_config.pac_url());
439    EXPECT_TRUE(network_params.proxy_rules.Matches(
440        actual_config.proxy_rules()));
441
442    // Removing recommended proxy pref should have no effect on network proxy.
443    pref_service_.RemoveRecommendedPref(prefs::kProxy);
444    SyncGetLatestProxyConfig(&actual_config);
445    EXPECT_EQ(network_params.auto_detect, actual_config.auto_detect());
446    EXPECT_EQ(network_params.pac_url, actual_config.pac_url());
447    EXPECT_TRUE(network_params.proxy_rules.Matches(
448        actual_config.proxy_rules()));
449  }
450}
451
452}  // namespace chromeos
453