commit c99b1657c35a2c83126001282fe01ecaee57b66f Author: Arturo Filastò arturo@filasto.net Date: Sat Oct 6 10:21:20 2012 +0000
Make nettest and runner support test relative options. --- nettests/httphost.py | 124 ++++++++++++++++++++++++++++++++++++++++++++++ ooni/nettest.py | 2 + ooni/plugins/httphost.py | 124 ---------------------------------------------- ooni/runner.py | 17 +++++- 4 files changed, 140 insertions(+), 127 deletions(-)
diff --git a/nettests/httphost.py b/nettests/httphost.py new file mode 100644 index 0000000..b57a50d --- /dev/null +++ b/nettests/httphost.py @@ -0,0 +1,124 @@ +""" + HTTP Host based filtering + ************************* + + This test detect HTTP Host field + based filtering. +""" +import os +from datetime import datetime + +import urllib2 +import httplib +try: + from BeautifulSoup import BeautifulSoup +except: + print "Beautiful Soup not installed. HTTPHost may not work" + +# XXX reduce boilerplating. +from zope.interface import implements +from twisted.python import usage +from twisted.plugin import IPlugin + +from ooni.plugoo.assets import Asset +from ooni.plugoo.tests import ITest, OONITest + +class HTTPHostArgs(usage.Options): + optParameters = [['asset', 'a', None, 'Asset file'], + ['controlserver', 'c', 'google.com', 'Specify the control server'], + ['resume', 'r', 0, 'Resume at this index'], + ['other', 'o', None, 'Other arguments']] + def control(self, experiment_result, args): + print "Experiment Result:", experiment_result + print "Args", args + return experiment_result + + def experiment(self, args): + import urllib + req = urllib.urlopen(args['asset']) + return {'page': req.readlines()} + +class HTTPHostAsset(Asset): + """ + This is the asset that should be used by the Test. It will + contain all the code responsible for parsing the asset file + and should be passed on instantiation to the test. + """ + def __init__(self, file=None): + self = Asset.__init__(self, file) + + def parse_line(self, line): + return line.split(',')[1].replace('\n','') + + +class HTTPHostTest(OONITest): + implements(IPlugin, ITest) + + shortName = "httphost" + description = "HTTP Host plugin" + requirements = None + options = HTTPHostArgs + # Tells this to be blocking. + blocking = True + + def check_response(self, response): + soup = BeautifulSoup(response) + if soup.head.title.string == "Blocked": + # Response indicates censorship + return True + else: + # Response does not indicate censorship + return False + + def is_censored(self, response): + if response: + soup = BeautifulSoup(response) + censored = self.check_response(response) + else: + censored = "unreachable" + return censored + + def urllib2_test(self, control_server, host): + req = urllib2.Request(control_server) + req.add_header('Host', host) + try: + r = urllib2.urlopen(req) + response = r.read() + censored = self.is_censored(response) + except Exception, e: + censored = "Error! %s" % e + + return censored + + def httplib_test(self, control_server, host): + censored = None + response = None + try: + conn = httplib.HTTPConnection(control_server) + conn.putrequest("GET", "", skip_host=True, skip_accept_encoding=True) + conn.putheader("Host", host) + conn.putheader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1.6") + conn.endheaders() + r = conn.getresponse() + response = r.read() + censored = self.is_censored(response) + except Exception, e: + censored = "Error! %s" % e + + return (censored, response) + + def experiment(self, args): + control_server = self.local_options['controlserver'] + url = 'http://torproject.org/' if not 'asset' in args else args['asset'] + censored = self.httplib_test(control_server, url) + return {'control': control_server, + 'host': url, + 'censored': censored} + + def load_assets(self): + if self.local_options and self.local_options['asset']: + return {'asset': Asset(self.local_options['asset'])} + else: + return {} + +httphost = HTTPHostTest(None, None, None) diff --git a/ooni/nettest.py b/ooni/nettest.py index d88c044..a01050e 100644 --- a/ooni/nettest.py +++ b/ooni/nettest.py @@ -80,6 +80,8 @@ class TestCase(unittest.TestCase): report = {} report['errors'] = []
+ optParameters = None + def getOptions(self): if self.inputFile: fp = open(self.inputFile) diff --git a/ooni/plugins/httphost.py b/ooni/plugins/httphost.py deleted file mode 100644 index 7c783a1..0000000 --- a/ooni/plugins/httphost.py +++ /dev/null @@ -1,124 +0,0 @@ -""" - HTTP Host based filtering - ************************* - - This test detect HTTP Host field - based filtering. -""" -import os -from datetime import datetime - -import urllib2 -import httplib -try: - from BeautifulSoup import BeautifulSoup -except: - print "Beautiful Soup not installed. HTTPHost may not work" - -# XXX reduce boilerplating. -from zope.interface import implements -from twisted.python import usage -from twisted.plugin import IPlugin - -from plugoo.assets import Asset -from plugoo.tests import ITest, OONITest - -class HTTPHostArgs(usage.Options): - optParameters = [['asset', 'a', None, 'Asset file'], - ['controlserver', 'c', 'google.com', 'Specify the control server'], - ['resume', 'r', 0, 'Resume at this index'], - ['other', 'o', None, 'Other arguments']] - def control(self, experiment_result, args): - print "Experiment Result:", experiment_result - print "Args", args - return experiment_result - - def experiment(self, args): - import urllib - req = urllib.urlopen(args['asset']) - return {'page': req.readlines()} - -class HTTPHostAsset(Asset): - """ - This is the asset that should be used by the Test. It will - contain all the code responsible for parsing the asset file - and should be passed on instantiation to the test. - """ - def __init__(self, file=None): - self = Asset.__init__(self, file) - - def parse_line(self, line): - return line.split(',')[1].replace('\n','') - - -class HTTPHostTest(OONITest): - implements(IPlugin, ITest) - - shortName = "httphost" - description = "HTTP Host plugin" - requirements = None - options = HTTPHostArgs - # Tells this to be blocking. - blocking = True - - def check_response(self, response): - soup = BeautifulSoup(response) - if soup.head.title.string == "Blocked": - # Response indicates censorship - return True - else: - # Response does not indicate censorship - return False - - def is_censored(self, response): - if response: - soup = BeautifulSoup(response) - censored = self.check_response(response) - else: - censored = "unreachable" - return censored - - def urllib2_test(self, control_server, host): - req = urllib2.Request(control_server) - req.add_header('Host', host) - try: - r = urllib2.urlopen(req) - response = r.read() - censored = self.is_censored(response) - except Exception, e: - censored = "Error! %s" % e - - return censored - - def httplib_test(self, control_server, host): - censored = None - response = None - try: - conn = httplib.HTTPConnection(control_server) - conn.putrequest("GET", "", skip_host=True, skip_accept_encoding=True) - conn.putheader("Host", host) - conn.putheader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1.6") - conn.endheaders() - r = conn.getresponse() - response = r.read() - censored = self.is_censored(response) - except Exception, e: - censored = "Error! %s" % e - - return (censored, response) - - def experiment(self, args): - control_server = self.local_options['controlserver'] - url = 'http://torproject.org/' if not 'asset' in args else args['asset'] - censored = self.httplib_test(control_server, url) - return {'control': control_server, - 'host': url, - 'censored': censored} - - def load_assets(self): - if self.local_options and self.local_options['asset']: - return {'asset': Asset(self.local_options['asset'])} - else: - return {} - -httphost = HTTPHostTest(None, None, None) diff --git a/ooni/runner.py b/ooni/runner.py index 8ed844d..c6958bc 100644 --- a/ooni/runner.py +++ b/ooni/runner.py @@ -5,7 +5,7 @@ import time import inspect
from twisted.internet import defer, reactor -from twisted.python import reflect, failure +from twisted.python import reflect, failure, usage
from twisted.trial import unittest from twisted.trial.runner import TrialRunner, TestLoader @@ -91,6 +91,16 @@ def adaptLegacyTest(obj, config):
return LegacyOONITest
+def processTest(obj, config): + if obj.optParameters: + class Options(usage.Options): + optParameters = obj.optParameters + + options = Options() + options.parseOptions(config['subArgs']) + + obj.localOptions = options + return obj
def findTestClassesFromConfig(config): """ @@ -106,7 +116,7 @@ def findTestClassesFromConfig(config): module = filenameToModule(filename) for name, val in inspect.getmembers(module): if isTestCase(val): - classes.append(val) + classes.append(processTest(val, config)) elif isLegacyTest(val): classes.append(adaptLegacyTest(val, config)) return classes @@ -135,7 +145,8 @@ def loadTestsAndOptions(classes): for klass in classes: try: k = klass() - options.append(k.getOptions()) + opts = k.getOptions() + options.append(opts) except AttributeError: options.append([])
tor-commits@lists.torproject.org