1// Copyright (c) 2011 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// Unit tests for helper functions for the Chrome Extensions Proxy Settings API.
6
7#include "base/scoped_ptr.h"
8#include "base/values.h"
9#include "chrome/browser/extensions/extension_proxy_api_constants.h"
10#include "chrome/browser/extensions/extension_proxy_api_helpers.h"
11#include "chrome/browser/prefs/proxy_config_dictionary.h"
12#include "chrome/browser/prefs/proxy_prefs.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15namespace keys = extension_proxy_api_constants;
16
17namespace {
18
19const char kSamplePacScript[] = "test";
20const char kSamplePacScriptAsDataUrl[] =
21    "data:application/x-ns-proxy-autoconfig;base64,dGVzdA==";
22const char kSamplePacScriptUrl[] = "http://wpad/wpad.dat";
23
24// Helper function to create a ProxyServer dictionary as defined in the
25// extension API.
26DictionaryValue* CreateTestProxyServerDict(const std::string& host) {
27  DictionaryValue* dict = new DictionaryValue;
28  dict->SetString(keys::kProxyConfigRuleHost, host);
29  return dict;
30}
31
32// Helper function to create a ProxyServer dictionary as defined in the
33// extension API.
34DictionaryValue* CreateTestProxyServerDict(const std::string& schema,
35                                           const std::string& host,
36                                           int port) {
37  DictionaryValue* dict = new DictionaryValue;
38  dict->SetString(keys::kProxyConfigRuleScheme, schema);
39  dict->SetString(keys::kProxyConfigRuleHost, host);
40  dict->SetInteger(keys::kProxyConfigRulePort, port);
41  return dict;
42}
43
44}  // namespace
45
46namespace extension_proxy_api_helpers {
47
48TEST(ExtensionProxyApiHelpers, CreateDataURLFromPACScript) {
49  std::string out;
50  ASSERT_TRUE(CreateDataURLFromPACScript(kSamplePacScript, &out));
51  EXPECT_EQ(kSamplePacScriptAsDataUrl, out);
52}
53
54TEST(ExtensionProxyApiHelpers, CreatePACScriptFromDataURL) {
55  std::string out;
56  ASSERT_TRUE(CreatePACScriptFromDataURL(kSamplePacScriptAsDataUrl, &out));
57  EXPECT_EQ(kSamplePacScript, out);
58
59  EXPECT_FALSE(CreatePACScriptFromDataURL("http://www.google.com", &out));
60}
61
62TEST(ExtensionProxyApiHelpers, GetProxyModeFromExtensionPref) {
63  DictionaryValue proxy_config;
64  ProxyPrefs::ProxyMode mode;
65  std::string error;
66
67  // Test positive case.
68  proxy_config.SetString(
69      keys::kProxyConfigMode,
70      ProxyPrefs::ProxyModeToString(ProxyPrefs::MODE_DIRECT));
71  ASSERT_TRUE(GetProxyModeFromExtensionPref(&proxy_config, &mode, &error));
72  EXPECT_EQ(ProxyPrefs::MODE_DIRECT, mode);
73  EXPECT_EQ(std::string(), error);
74
75  // Test negative case.
76  proxy_config.SetString(keys::kProxyConfigMode, "foobar");
77  EXPECT_FALSE(GetProxyModeFromExtensionPref(&proxy_config, &mode, &error));
78
79  // Do not test |error|, as an invalid enumeration value is considered an
80  // internal error. It should be filtered by the extensions API.
81}
82
83TEST(ExtensionProxyApiHelpers, GetPacUrlFromExtensionPref) {
84  std::string out;
85  std::string error;
86
87  DictionaryValue proxy_config;
88  proxy_config.SetString(
89      keys::kProxyConfigMode,
90      ProxyPrefs::ProxyModeToString(ProxyPrefs::MODE_PAC_SCRIPT));
91
92  // Currently we are still missing a PAC script entry.
93  // This is silently ignored.
94  ASSERT_TRUE(GetPacUrlFromExtensionPref(&proxy_config, &out, &error));
95  EXPECT_EQ(std::string(), out);
96  EXPECT_EQ(std::string(), error);
97
98  // Set up a pac script.
99  DictionaryValue* pacScriptDict = new DictionaryValue;
100  pacScriptDict->SetString(keys::kProxyConfigPacScriptUrl, kSamplePacScriptUrl);
101  proxy_config.Set(keys::kProxyConfigPacScript, pacScriptDict);
102
103  ASSERT_TRUE(GetPacUrlFromExtensionPref(&proxy_config, &out, &error));
104  EXPECT_EQ(kSamplePacScriptUrl, out);
105  EXPECT_EQ(std::string(), error);
106}
107
108TEST(ExtensionProxyApiHelpers, GetPacDataFromExtensionPref) {
109  std::string out;
110  std::string error;
111
112  DictionaryValue proxy_config;
113  proxy_config.SetString(
114      keys::kProxyConfigMode,
115      ProxyPrefs::ProxyModeToString(ProxyPrefs::MODE_PAC_SCRIPT));
116
117  // Currently we are still missing a PAC data entry. This is silently ignored.
118  ASSERT_TRUE(GetPacDataFromExtensionPref(&proxy_config, &out, &error));
119  EXPECT_EQ(std::string(), out);
120  EXPECT_EQ(std::string(), error);
121
122  // Set up a PAC script.
123  DictionaryValue* pacScriptDict = new DictionaryValue;
124  pacScriptDict->SetString(keys::kProxyConfigPacScriptData, kSamplePacScript);
125  proxy_config.Set(keys::kProxyConfigPacScript, pacScriptDict);
126
127  ASSERT_TRUE(GetPacDataFromExtensionPref(&proxy_config, &out, &error));
128  EXPECT_EQ(kSamplePacScript, out);
129  EXPECT_EQ(std::string(), error);
130}
131
132TEST(ExtensionProxyApiHelpers, GetProxyRulesStringFromExtensionPref) {
133  std::string out;
134  std::string error;
135
136  DictionaryValue proxy_config;
137  proxy_config.SetString(
138      keys::kProxyConfigMode,
139      ProxyPrefs::ProxyModeToString(ProxyPrefs::MODE_FIXED_SERVERS));
140
141  // Currently we are still missing a proxy config entry.
142  // This is silently ignored.
143  ASSERT_TRUE(
144      GetProxyRulesStringFromExtensionPref(&proxy_config, &out, &error));
145  EXPECT_EQ(std::string(), out);
146  EXPECT_EQ(std::string(), error);
147
148  DictionaryValue* proxy_rules = new DictionaryValue;
149  proxy_rules->Set(keys::field_name[1], CreateTestProxyServerDict("proxy1"));
150  proxy_rules->Set(keys::field_name[2], CreateTestProxyServerDict("proxy2"));
151  proxy_config.Set(keys::kProxyConfigRules, proxy_rules);
152
153  ASSERT_TRUE(
154      GetProxyRulesStringFromExtensionPref(&proxy_config, &out, &error));
155  EXPECT_EQ("http=proxy1:80;https=proxy2:80", out);
156  EXPECT_EQ(std::string(), error);
157}
158
159TEST(ExtensionProxyApiHelpers, GetBypassListFromExtensionPref) {
160  std::string out;
161  std::string error;
162
163  DictionaryValue proxy_config;
164  proxy_config.SetString(
165      keys::kProxyConfigMode,
166      ProxyPrefs::ProxyModeToString(ProxyPrefs::MODE_FIXED_SERVERS));
167
168  // Currently we are still missing a proxy config entry.
169  // This is silently ignored.
170  ASSERT_TRUE(
171      GetBypassListFromExtensionPref(&proxy_config, &out, &error));
172  EXPECT_EQ(std::string(), out);
173  EXPECT_EQ(std::string(), error);
174
175  ListValue* bypass_list = new ListValue;
176  bypass_list->Append(Value::CreateStringValue("host1"));
177  bypass_list->Append(Value::CreateStringValue("host2"));
178  DictionaryValue* proxy_rules = new DictionaryValue;
179  proxy_rules->Set(keys::kProxyConfigBypassList, bypass_list);
180  proxy_config.Set(keys::kProxyConfigRules, proxy_rules);
181
182  ASSERT_TRUE(
183      GetBypassListFromExtensionPref(&proxy_config, &out, &error));
184  EXPECT_EQ("host1,host2", out);
185  EXPECT_EQ(std::string(), error);
186}
187
188TEST(ExtensionProxyApiHelpers, CreateProxyConfigDict) {
189  std::string error;
190  scoped_ptr<DictionaryValue> exp_direct(ProxyConfigDictionary::CreateDirect());
191  scoped_ptr<DictionaryValue> out_direct(
192      CreateProxyConfigDict(ProxyPrefs::MODE_DIRECT, "", "", "", "", &error));
193  EXPECT_TRUE(Value::Equals(exp_direct.get(), out_direct.get()));
194
195  scoped_ptr<DictionaryValue> exp_auto(
196      ProxyConfigDictionary::CreateAutoDetect());
197  scoped_ptr<DictionaryValue> out_auto(
198      CreateProxyConfigDict(ProxyPrefs::MODE_AUTO_DETECT, "", "", "", "",
199                            &error));
200  EXPECT_TRUE(Value::Equals(exp_auto.get(), out_auto.get()));
201
202  scoped_ptr<DictionaryValue> exp_pac_url(
203      ProxyConfigDictionary::CreatePacScript(kSamplePacScriptUrl));
204  scoped_ptr<DictionaryValue> out_pac_url(
205        CreateProxyConfigDict(ProxyPrefs::MODE_PAC_SCRIPT, kSamplePacScriptUrl,
206                              "", "", "", &error));
207  EXPECT_TRUE(Value::Equals(exp_pac_url.get(), out_pac_url.get()));
208
209  scoped_ptr<DictionaryValue> exp_pac_data(
210      ProxyConfigDictionary::CreatePacScript(kSamplePacScriptAsDataUrl));
211  scoped_ptr<DictionaryValue> out_pac_data(
212          CreateProxyConfigDict(ProxyPrefs::MODE_PAC_SCRIPT, "",
213                                kSamplePacScript, "", "", &error));
214  EXPECT_TRUE(Value::Equals(exp_pac_data.get(), out_pac_data.get()));
215
216  scoped_ptr<DictionaryValue> exp_fixed(
217      ProxyConfigDictionary::CreateFixedServers("foo:80", "localhost"));
218  scoped_ptr<DictionaryValue> out_fixed(
219          CreateProxyConfigDict(ProxyPrefs::MODE_FIXED_SERVERS, "", "",
220                                "foo:80", "localhost", &error));
221  EXPECT_TRUE(Value::Equals(exp_fixed.get(), out_fixed.get()));
222
223  scoped_ptr<DictionaryValue> exp_system(ProxyConfigDictionary::CreateSystem());
224  scoped_ptr<DictionaryValue> out_system(
225      CreateProxyConfigDict(ProxyPrefs::MODE_SYSTEM, "", "", "", "", &error));
226  EXPECT_TRUE(Value::Equals(exp_system.get(), out_system.get()));
227
228  // Neither of them should have set an error.
229  EXPECT_EQ(std::string(), error);
230}
231
232TEST(ExtensionProxyApiHelpers, GetProxyServer) {
233  DictionaryValue proxy_server_dict;
234  net::ProxyServer created;
235  std::string error;
236
237  // Test simplest case, no schema nor port specified --> defaults are used.
238  proxy_server_dict.SetString(keys::kProxyConfigRuleHost, "proxy_server");
239  ASSERT_TRUE(
240      GetProxyServer(&proxy_server_dict, net::ProxyServer::SCHEME_HTTP,
241                     &created, &error));
242  EXPECT_EQ("PROXY proxy_server:80", created.ToPacString());
243
244  // Test complete case.
245  proxy_server_dict.SetString(keys::kProxyConfigRuleScheme, "socks4");
246  proxy_server_dict.SetInteger(keys::kProxyConfigRulePort, 1234);
247  ASSERT_TRUE(
248        GetProxyServer(&proxy_server_dict, net::ProxyServer::SCHEME_HTTP,
249                       &created, &error));
250  EXPECT_EQ("SOCKS proxy_server:1234", created.ToPacString());
251}
252
253TEST(ExtensionProxyApiHelpers, JoinUrlList) {
254  ListValue list;
255  list.Append(Value::CreateStringValue("s1"));
256  list.Append(Value::CreateStringValue("s2"));
257  list.Append(Value::CreateStringValue("s3"));
258
259  std::string out;
260  std::string error;
261  ASSERT_TRUE(JoinUrlList(&list, ";", &out, &error));
262  EXPECT_EQ("s1;s2;s3", out);
263}
264
265// This tests CreateProxyServerDict as well.
266TEST(ExtensionProxyApiHelpers, CreateProxyRulesDict) {
267  scoped_ptr<DictionaryValue> browser_pref(
268      ProxyConfigDictionary::CreateFixedServers(
269          "http=proxy1:80;https=proxy2:80;ftp=proxy3:80;socks=proxy4:80",
270          "localhost"));
271  ProxyConfigDictionary config(browser_pref.get());
272  scoped_ptr<DictionaryValue> extension_pref(CreateProxyRulesDict(config));
273  ASSERT_TRUE(extension_pref.get());
274
275  scoped_ptr<DictionaryValue> expected(new DictionaryValue);
276  expected->Set("proxyForHttp",
277                CreateTestProxyServerDict("http", "proxy1", 80));
278  expected->Set("proxyForHttps",
279                CreateTestProxyServerDict("http", "proxy2", 80));
280  expected->Set("proxyForFtp",
281                CreateTestProxyServerDict("http", "proxy3", 80));
282  expected->Set("fallbackProxy",
283                CreateTestProxyServerDict("socks4", "proxy4", 80));
284  ListValue* bypass_list = new ListValue;
285  bypass_list->Append(Value::CreateStringValue("localhost"));
286  expected->Set(keys::kProxyConfigBypassList, bypass_list);
287
288  EXPECT_TRUE(Value::Equals(expected.get(), extension_pref.get()));
289}
290
291// Test if a PAC script URL is specified.
292TEST(ExtensionProxyApiHelpers, CreatePacScriptDictWithUrl) {
293  scoped_ptr<DictionaryValue> browser_pref(
294      ProxyConfigDictionary::CreatePacScript(kSamplePacScriptUrl));
295  ProxyConfigDictionary config(browser_pref.get());
296  scoped_ptr<DictionaryValue> extension_pref(CreatePacScriptDict(config));
297  ASSERT_TRUE(extension_pref.get());
298
299  scoped_ptr<DictionaryValue> expected(new DictionaryValue);
300  expected->SetString(keys::kProxyConfigPacScriptUrl, kSamplePacScriptUrl);
301
302  EXPECT_TRUE(Value::Equals(expected.get(), extension_pref.get()));
303}
304
305// Test if a PAC script is encoded in a data URL.
306TEST(ExtensionProxyApiHelpers, CreatePacScriptDictWidthData) {
307  scoped_ptr<DictionaryValue> browser_pref(
308      ProxyConfigDictionary::CreatePacScript(kSamplePacScriptAsDataUrl));
309  ProxyConfigDictionary config(browser_pref.get());
310  scoped_ptr<DictionaryValue> extension_pref(CreatePacScriptDict(config));
311  ASSERT_TRUE(extension_pref.get());
312
313  scoped_ptr<DictionaryValue> expected(new DictionaryValue);
314  expected->SetString(keys::kProxyConfigPacScriptData, kSamplePacScript);
315
316  EXPECT_TRUE(Value::Equals(expected.get(), extension_pref.get()));
317}
318
319TEST(ExtensionProxyApiHelpers, TokenizeToStringList) {
320  ListValue expected;
321  expected.Append(Value::CreateStringValue("s1"));
322  expected.Append(Value::CreateStringValue("s2"));
323  expected.Append(Value::CreateStringValue("s3"));
324
325  scoped_ptr<ListValue> out(TokenizeToStringList("s1;s2;s3", ";"));
326  EXPECT_TRUE(Value::Equals(&expected, out.get()));
327}
328
329}  // namespace extension_proxy_api_helpers
330