1#!/usr/bin/env python
2# Copyright (c) 2012 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Generator script for proxy tests.
7
8See AndroidProxySelectorTest.java
9and net/proxy/proxy_config_service_android_unittest.cc
10
11To generate C++, run this script without arguments.
12To generate Java, run this script with -j argument.
13
14Note that this generator is not run as part of the build process because
15we are assuming that these test cases will not change often.
16"""
17
18import optparse
19
20test_cases = [
21  {
22    "name": "NoProxy",
23    "description" : "Test direct mapping when no proxy defined.",
24    "properties" : {
25    },
26    "mappings" : {
27      "http://example.com/" : "DIRECT",
28      "ftp://example.com/" : "DIRECT",
29      "https://example.com/" : "DIRECT",
30    }
31  },
32  {
33    "name": "HttpProxyHostAndPort",
34    "description" : "Test http.proxyHost and http.proxyPort works.",
35    "properties" : {
36      "http.proxyHost" : "httpproxy.com",
37      "http.proxyPort" : "8080",
38    },
39    "mappings" : {
40      "http://example.com/" : "PROXY httpproxy.com:8080",
41      "ftp://example.com/" : "DIRECT",
42      "https://example.com/" : "DIRECT",
43    }
44  },
45  {
46    "name": "HttpProxyHostOnly",
47    "description" : "We should get the default port (80) for proxied hosts.",
48    "properties" : {
49      "http.proxyHost" : "httpproxy.com",
50    },
51    "mappings" : {
52      "http://example.com/" : "PROXY httpproxy.com:80",
53      "ftp://example.com/" : "DIRECT",
54      "https://example.com/" : "DIRECT",
55    }
56  },
57  {
58    "name": "HttpProxyPortOnly",
59    "description" :
60        "http.proxyPort only should not result in any hosts being proxied.",
61    "properties" : {
62      "http.proxyPort" : "8080",
63    },
64    "mappings" : {
65      "http://example.com/" : "DIRECT",
66      "ftp://example.com/" : "DIRECT",
67      "https://example.com/" : "DIRECT"
68    }
69  },
70  {
71    "name": "HttpNonProxyHosts1",
72    "description" : "Test that HTTP non proxy hosts are mapped correctly",
73    "properties" : {
74      "http.nonProxyHosts" : "slashdot.org",
75      "http.proxyHost" : "httpproxy.com",
76      "http.proxyPort" : "8080",
77    },
78    "mappings" : {
79      "http://example.com/" : "PROXY httpproxy.com:8080",
80      "http://slashdot.org/" : "DIRECT",
81    }
82  },
83  {
84    "name": "HttpNonProxyHosts2",
85    "description" : "Test that | pattern works.",
86    "properties" : {
87      "http.nonProxyHosts" : "slashdot.org|freecode.net",
88      "http.proxyHost" : "httpproxy.com",
89      "http.proxyPort" : "8080",
90    },
91    "mappings" : {
92      "http://example.com/" : "PROXY httpproxy.com:8080",
93      "http://slashdot.org/" : "DIRECT",
94      "http://freecode.net/" : "DIRECT",
95    }
96  },
97  {
98    "name": "HttpNonProxyHosts3",
99    "description" : "Test that * pattern works.",
100    "properties" : {
101      "http.nonProxyHosts" : "*example.com",
102      "http.proxyHost" : "httpproxy.com",
103      "http.proxyPort" : "8080",
104    },
105    "mappings" : {
106      "http://example.com/" : "DIRECT",
107      "http://www.example.com/" : "DIRECT",
108      "http://slashdot.org/" : "PROXY httpproxy.com:8080",
109    }
110  },
111  {
112    "name": "FtpNonProxyHosts",
113    "description" : "Test that FTP non proxy hosts are mapped correctly",
114    "properties" : {
115      "ftp.nonProxyHosts" : "slashdot.org",
116      "ftp.proxyHost" : "httpproxy.com",
117      "ftp.proxyPort" : "8080",
118    },
119    "mappings" : {
120      "http://example.com/" : "DIRECT",
121      "ftp://example.com/" : "PROXY httpproxy.com:8080",
122    }
123  },
124  {
125    "name": "FtpProxyHostAndPort",
126    "description" : "Test ftp.proxyHost and ftp.proxyPort works.",
127    "properties" : {
128      "ftp.proxyHost" : "httpproxy.com",
129      "ftp.proxyPort" : "8080",
130    },
131    "mappings" : {
132      "ftp://example.com/" : "PROXY httpproxy.com:8080",
133      "http://example.com/" : "DIRECT",
134      "https://example.com/" : "DIRECT",
135    }
136  },
137  {
138    "name": "FtpProxyHostOnly",
139    "description" : "Test ftp.proxyHost and default port.",
140    "properties" : {
141      "ftp.proxyHost" : "httpproxy.com",
142    },
143    "mappings" : {
144      "ftp://example.com/" : "PROXY httpproxy.com:80",
145      "http://example.com/" : "DIRECT",
146      "https://example.com/" : "DIRECT",
147    }
148  },
149  {
150    "name": "HttpsProxyHostAndPort",
151    "description" : "Test https.proxyHost and https.proxyPort works.",
152    "properties" : {
153      "https.proxyHost" : "httpproxy.com",
154      "https.proxyPort" : "8080",
155    },
156    "mappings" : {
157      "https://example.com/" : "PROXY httpproxy.com:8080",
158      "http://example.com/" : "DIRECT",
159      "ftp://example.com/" : "DIRECT",
160    }
161  },
162  {
163    "name": "HttpsProxyHostOnly",
164    "description" : "Test https.proxyHost and default port.",
165    # Chromium differs from the Android platform by connecting to port 80 for
166    # HTTPS connections by default, hence cpp-only.
167    "cpp-only" : "",
168    "properties" : {
169      "https.proxyHost" : "httpproxy.com",
170    },
171    "mappings" : {
172      "https://example.com/" : "PROXY httpproxy.com:80",
173      "http://example.com/" : "DIRECT",
174      "ftp://example.com/" : "DIRECT",
175    }
176  },
177  {
178    "name": "HttpProxyHostIPv6",
179    "description" : "Test IPv6 https.proxyHost and default port.",
180    "cpp-only" : "",
181    "properties" : {
182      "http.proxyHost" : "a:b:c::d:1",
183    },
184    "mappings" : {
185      "http://example.com/" : "PROXY [a:b:c::d:1]:80",
186      "ftp://example.com/" : "DIRECT",
187    }
188  },
189  {
190    "name": "HttpProxyHostAndPortIPv6",
191    "description" : "Test IPv6 http.proxyHost and http.proxyPort works.",
192    "cpp-only" : "",
193    "properties" : {
194      "http.proxyHost" : "a:b:c::d:1",
195      "http.proxyPort" : "8080",
196    },
197    "mappings" : {
198      "http://example.com/" : "PROXY [a:b:c::d:1]:8080",
199      "ftp://example.com/" : "DIRECT",
200    }
201  },
202  {
203    "name": "HttpProxyHostAndInvalidPort",
204    "description" : "Test invalid http.proxyPort does not crash.",
205    "cpp-only" : "",
206    "properties" : {
207      "http.proxyHost" : "a:b:c::d:1",
208      "http.proxyPort" : "65536",
209    },
210    "mappings" : {
211      "http://example.com/" : "DIRECT",
212      "ftp://example.com/" : "DIRECT",
213    }
214  },
215  {
216    "name": "DefaultProxyExplictPort",
217    "description" :
218        "Default http proxy is used if a scheme-specific one is not found.",
219    "properties" : {
220      "proxyHost" : "defaultproxy.com",
221      "proxyPort" : "8080",
222      "ftp.proxyHost" : "httpproxy.com",
223      "ftp.proxyPort" : "8080",
224    },
225    "mappings" : {
226      "http://example.com/" : "PROXY defaultproxy.com:8080",
227      "https://example.com/" : "PROXY defaultproxy.com:8080",
228      "ftp://example.com/" : "PROXY httpproxy.com:8080",
229    }
230  },
231  {
232    "name": "DefaultProxyDefaultPort",
233    "description" : "Check that the default proxy port is as expected.",
234    # Chromium differs from the Android platform by connecting to port 80 for
235    # HTTPS connections by default, hence cpp-only.
236    "cpp-only" : "",
237    "properties" : {
238      "proxyHost" : "defaultproxy.com",
239    },
240    "mappings" : {
241      "http://example.com/" : "PROXY defaultproxy.com:80",
242      "https://example.com/" : "PROXY defaultproxy.com:80",
243    }
244  },
245  {
246    "name": "FallbackToSocks",
247    "description" : "SOCKS proxy is used if scheme-specific one is not found.",
248    "properties" : {
249      "http.proxyHost" : "defaultproxy.com",
250      "socksProxyHost" : "socksproxy.com"
251    },
252    "mappings" : {
253      "http://example.com/" : "PROXY defaultproxy.com:80",
254      "https://example.com/" : "SOCKS5 socksproxy.com:1080",
255      "ftp://example.com" : "SOCKS5 socksproxy.com:1080",
256    }
257  },
258  {
259    "name": "SocksExplicitPort",
260    "description" : "SOCKS proxy port is used if specified",
261    "properties" : {
262      "socksProxyHost" : "socksproxy.com",
263      "socksProxyPort" : "9000",
264    },
265    "mappings" : {
266      "http://example.com/" : "SOCKS5 socksproxy.com:9000",
267    }
268  },
269  {
270    "name": "HttpProxySupercedesSocks",
271    "description" : "SOCKS proxy is ignored if default HTTP proxy defined.",
272    "properties" : {
273      "proxyHost" : "defaultproxy.com",
274      "socksProxyHost" : "socksproxy.com",
275      "socksProxyPort" : "9000",
276    },
277    "mappings" : {
278      "http://example.com/" : "PROXY defaultproxy.com:80",
279    }
280  },
281]
282
283class GenerateCPlusPlus:
284  """Generate C++ test cases"""
285
286  def Generate(self):
287    for test_case in test_cases:
288      print ("TEST_F(ProxyConfigServiceAndroidTest, %s) {" % test_case["name"])
289      if "description" in test_case:
290        self._GenerateDescription(test_case["description"]);
291      self._GenerateConfiguration(test_case["properties"])
292      self._GenerateMappings(test_case["mappings"])
293      print "}"
294      print ""
295
296  def _GenerateDescription(self, description):
297    print "  // %s" % description
298
299  def _GenerateConfiguration(self, properties):
300    for key in sorted(properties.iterkeys()):
301      print "  AddProperty(\"%s\", \"%s\");" % (key, properties[key])
302    print "  ProxySettingsChanged();"
303
304  def _GenerateMappings(self, mappings):
305    for url in sorted(mappings.iterkeys()):
306      print "  TestMapping(\"%s\", \"%s\");" % (url, mappings[url])
307
308
309class GenerateJava:
310  """Generate Java test cases"""
311
312  def Generate(self):
313    for test_case in test_cases:
314      if test_case.has_key("cpp-only"):
315        continue
316      if "description" in test_case:
317        self._GenerateDescription(test_case["description"]);
318      print "    @SmallTest"
319      print "    @Feature({\"AndroidWebView\"})"
320      print "    public void test%s() throws Exception {" % test_case["name"]
321      self._GenerateConfiguration(test_case["properties"])
322      self._GenerateMappings(test_case["mappings"])
323      print "    }"
324      print ""
325
326  def _GenerateDescription(self, description):
327    print "    /**"
328    print "     * %s" % description
329    print "     *"
330    print "     * @throws Exception"
331    print "     */"
332
333  def _GenerateConfiguration(self, properties):
334    for key in sorted(properties.iterkeys()):
335      print "        System.setProperty(\"%s\", \"%s\");" % (
336          key, properties[key])
337
338  def _GenerateMappings(self, mappings):
339    for url in sorted(mappings.iterkeys()):
340      mapping = mappings[url]
341      if 'HTTPS' in mapping:
342        mapping = mapping.replace('HTTPS', 'PROXY')
343      print "        checkMapping(\"%s\", \"%s\");" % (url, mapping)
344
345
346def main():
347  parser = optparse.OptionParser()
348  parser.add_option("-j", "--java",
349                action="store_true", dest="java");
350  (options, args) = parser.parse_args();
351  if options.java:
352    generator = GenerateJava()
353  else:
354    generator = GenerateCPlusPlus()
355  generator.Generate()
356
357if __name__ == '__main__':
358  main()
359