[tor-commits] [ooni-probe/master] Implement backward compatibility of new ooniprobe with legacy tests
isis at torproject.org
isis at torproject.org
Thu Oct 4 14:41:15 UTC 2012
commit 7643541a424655c689e252783a50037846368773
Author: Arturo Filastò <arturo at filasto.net>
Date: Fri Sep 21 10:40:41 2012 +0000
Implement backward compatibility of new ooniprobe with legacy tests
* Reporting system works with old tests
* Properly document some of the functions
---
ooni/input.py | 17 +++++-------
ooni/nettest.py | 44 ++++-----------------------------
ooni/oonicli.py | 8 ++++--
ooni/plugins/httpt.py | 9 ++++---
ooni/plugoo/tests.py | 7 ++---
ooni/reporter.py | 30 ++++++++++++++++++++---
ooni/runner.py | 64 +++++++++++++++++++++++++++++++++++++++----------
7 files changed, 102 insertions(+), 77 deletions(-)
diff --git a/ooni/input.py b/ooni/input.py
index b931b82..69507b4 100644
--- a/ooni/input.py
+++ b/ooni/input.py
@@ -9,7 +9,7 @@ class InputUnitFactory(object):
"""
inputUnitSize = 3
def __init__(self, inputs=[]):
- self._inputs = inputs
+ self._inputs = iter(inputs)
self._idx = 0
self._ended = False
@@ -21,16 +21,13 @@ class InputUnitFactory(object):
raise StopIteration
last_element_idx = self._idx + self.inputUnitSize
- input_unit_elements = self._inputs[self._idx:last_element_idx]
- try:
- # XXX hack to fail when we reach the end of the list
- antani = self._inputs[last_element_idx]
- except:
- if len(input_unit_elements) > 0:
+ input_unit_elements = []
+ for i in xrange(last_element_idx):
+ try:
+ input_unit_elements.append(self._inputs.next())
+ except:
self._ended = True
- return InputUnit(input_unit_elements)
- else:
- raise StopIteration
+ break
self._idx += self.inputUnitSize
diff --git a/ooni/nettest.py b/ooni/nettest.py
index 0302d25..f3476cf 100644
--- a/ooni/nettest.py
+++ b/ooni/nettest.py
@@ -4,44 +4,11 @@ from twisted.trial import unittest, itrial
pyunit = __import__('unittest')
-def _iterateTests(testSuiteOrCase):
+class InputTestSuite(pyunit.TestSuite):
"""
- Iterate through all of the test cases in C{testSuiteOrCase}.
+ This in an extension of a unittest test suite. It adds support for inputs
+ and the tracking of current index via idx.
"""
- try:
- suite = iter(testSuiteOrCase)
- except TypeError:
- yield testSuiteOrCase
- else:
- for test in suite:
- for subtest in _iterateTests(test):
- yield subtest
-
-
-class TestSuiteFactory(object):
- def __init__(self, inputUnit, tests, basesuite):
- self._baseSuite = basesuite
- self._inputUnit = inputUnit
- self._idx = 0
- self.tests = tests
-
- def __iter__(self):
- return self
-
- def next(self):
- try:
- next_input = self._inputUnit.next()
- print "Now dealing with %s %s" % (next_input, self._idx)
- except:
- raise StopIteration
- new_test_suite = self._baseSuite(self.tests)
- new_test_suite.input = next_input
- new_test_suite._idx = self._idx
-
- self._idx += 1
- return new_test_suite
-
-class InputTestSuite(pyunit.TestSuite):
def run(self, result, idx=0):
self._idx = idx
while self._tests:
@@ -51,7 +18,6 @@ class InputTestSuite(pyunit.TestSuite):
try:
test.input = self.input
test._idx = self._idx
- print "IDX: %s" % self._idx
test(result)
except:
test(result)
@@ -59,8 +25,8 @@ class InputTestSuite(pyunit.TestSuite):
return result
class TestCase(unittest.TestCase):
- name = "DefaultTestName"
- inputs = []
+ name = "DefaultOONITestCase"
+ inputs = [None]
def getOptions(self):
return {'inputs': self.inputs}
diff --git a/ooni/oonicli.py b/ooni/oonicli.py
index 1e7613b..f14bf6e 100644
--- a/ooni/oonicli.py
+++ b/ooni/oonicli.py
@@ -73,10 +73,10 @@ class Options(usage.Options, app.ReactorSelectionMixin):
def parseArgs(self, *args):
try:
self['test'] = args[0]
+ self['subArgs'] = args[1:]
except:
raise usage.UsageError("No test filename specified!")
-
def postOptions(self):
self['reporter'] = reporter.OONIReporter
@@ -90,9 +90,11 @@ def run():
except usage.error, ue:
raise SystemExit, "%s: %s" % (sys.argv[0], ue)
- classes = runner.findTestClassesFromFile(config['test'])
+ classes = runner.findTestClassesFromConfig(config)
+
casesList, options = runner.loadTestsAndOptions(classes)
for idx, cases in enumerate(casesList):
- orunner = runner.ORunner(cases, options[idx])
+ orunner = runner.ORunner(cases, options[idx], config)
orunner.run()
+
diff --git a/ooni/plugins/httpt.py b/ooni/plugins/httpt.py
index 46f3b17..358f1ea 100644
--- a/ooni/plugins/httpt.py
+++ b/ooni/plugins/httpt.py
@@ -65,13 +65,14 @@ class httptTest(http.HTTPTest):
def processRedirect(self, location):
self.result['redirect'] = None
- if self.local_options['rules']:
+ try:
+ rules_file = self.local_options['rules']
import yaml
- rules = yaml.load(open(self.local_options['rules']))
+ rules = yaml.load(open(rules_file))
log.msg("Testing rules %s" % rules)
redirect = self.testRules(rules, location)
self.result['redirect'] = redirect
- else:
+ except TypeError:
log.msg("No rules file. Got a redirect, but nothing to do.")
@@ -90,4 +91,4 @@ class httptTest(http.HTTPTest):
# We need to instantiate it otherwise getPlugins does not detect it
# XXX Find a way to load plugins without instantiating them.
-httpt = httptTest(None, None, None)
+#httpt = httptTest(None, None, None)
diff --git a/ooni/plugoo/tests.py b/ooni/plugoo/tests.py
index e4ee187..37e0664 100644
--- a/ooni/plugoo/tests.py
+++ b/ooni/plugoo/tests.py
@@ -25,19 +25,19 @@ class OONITest(object):
name = "oonitest"
# By default we set this to False, meaning that we don't block
blocking = False
- reactor = None
+ reactor = reactor
tool = False
ended = False
def __init__(self, local_options, global_options, report, ooninet=None,
- reactor=None):
+ my_reactor=reactor):
# These are the options that are read through the tests suboptions
self.local_options = local_options
# These are the options global to all of OONI
self.global_options = global_options
self.report = report
#self.ooninet = ooninet
- self.reactor = reactor
+ self.reactor = my_reactor
self.result = {}
self.initialize()
@@ -133,7 +133,6 @@ class OONITest(object):
@param args: the asset(s) lines that we are working on.
"""
self.start_time = date.now()
- print "FOWID"
log.msg("Starting test %s" % self.__class__)
return self._do_experiment(args)
diff --git a/ooni/reporter.py b/ooni/reporter.py
index 14297cd..4b3ed6f 100644
--- a/ooni/reporter.py
+++ b/ooni/reporter.py
@@ -11,6 +11,10 @@ from twisted.trial import unittest, reporter, runner
pyunit = __import__('unittest')
class OReporter(pyunit.TestResult):
+ """
+ This is an extension of the unittest TestResult. It adds support for
+ reporting to yaml format.
+ """
def __init__(self, stream=sys.stdout, tbformat='default', realtime=False,
publisher=None, testSuite=None):
super(OReporter, self).__init__()
@@ -45,6 +49,10 @@ class OReporter(pyunit.TestResult):
class ReporterFactory(OReporter):
+ """
+ This is a reporter factory. It emits new instances of Reports. It is also
+ responsible for writing the OONI Report headers.
+ """
def __init__(self, stream=sys.stdout, tbformat='default', realtime=False,
publisher=None, testSuite=None):
super(ReporterFactory, self).__init__(stream=stream,
@@ -77,6 +85,14 @@ class ReporterFactory(OReporter):
class OONIReporter(OReporter):
+ """
+ This is a special reporter that has knowledge about the fact that there can
+ exist more test runs of the same kind per run.
+ These multiple test runs are kept track of through idx.
+
+ An instance of such reporter should be created per InputUnit. Every input
+ unit will invoke size_of_input_unit * test_cases times startTest().
+ """
def __init__(self, stream=sys.stdout, tbformat='default', realtime=False,
publisher=None):
super(OONIReporter, self).__init__(stream=stream,
@@ -119,10 +135,16 @@ class OONIReporter(OReporter):
idx = self.getTestIndex(test)
self._tests[idx]['lastTime'] = self._getTime() - self._tests[idx]['testStarted']
- # XXX I put a dict() here so that the object is re-instantiated and I
- # actually end up with the report I want. This could either be a
- # python bug or a yaml bug.
- self._tests[idx]['report'] = dict(test.report)
+ # This is here for allowing reporting of legacy tests.
+ # XXX In the future this should be removed.
+ try:
+ self._tests[idx]['report'] = list(test.legacy_report)
+ except:
+ # XXX I put a dict() here so that the object is re-instantiated and I
+ # actually end up with the report I want. This could either be a
+ # python bug or a yaml bug.
+ self._tests[idx]['report'] = dict(test.report)
+
def done(self):
"""
diff --git a/ooni/runner.py b/ooni/runner.py
index ddde83b..0bcafb0 100644
--- a/ooni/runner.py
+++ b/ooni/runner.py
@@ -15,6 +15,7 @@ from ooni.reporter import ReporterFactory
from ooni.input import InputUnitFactory
from ooni.nettest import InputTestSuite
from ooni import nettest
+from ooni.utils import log
from ooni.plugoo import tests as oonitests
def isTestCase(thing):
@@ -37,7 +38,7 @@ def isLegacyTest(obj):
except TypeError:
return False
-def adaptLegacyTest(obj, inputs=[None]):
+def adaptLegacyTest(obj, config):
"""
We take a legacy OONITest class and convert it into a nettest.TestCase.
This allows backward compatibility of old OONI tests.
@@ -45,30 +46,62 @@ def adaptLegacyTest(obj, inputs=[None]):
XXX perhaps we could implement another extra layer that makes the even
older test cases compatible with the new OONI.
"""
+ class legacy_reporter(object):
+ def __init__(self, report_target):
+ self.report_target = report_target
+
+ def __call__(self, what):
+ self.report_target.append(what)
+
class LegacyOONITest(nettest.TestCase):
- inputs = [None]
- original_test = obj
+ try:
+ name = obj.shortName
+ except:
+ name = "LegacyOONITest"
+
+ originalTest = obj
+
+ subOptions = obj.options()
+ subOptions.parseOptions(config['subArgs'])
+
+ test_class = obj(None, None, None, None)
+ test_class.local_options = subOptions
+ assets = test_class.load_assets()
+
+ # XXX here we are only taking assets that are set to one item only.
+ for key, inputs in assets.items():
+ pass
+
+ inputs = inputs
+ local_options = subOptions
@defer.inlineCallbacks
def test_start_legacy_test(self):
- print "bla bla bla"
- print self.original_test
- my_test = self.original_test(None, None, None)
- yield my_test.startTest(self.input)
+
+ self.legacy_report = []
+
+ my_test = self.originalTest(None, None, None)
+ my_test.report = legacy_reporter(self.legacy_report)
+ args = {}
+ args[self.key] = self.input
+ result = yield my_test.startTest(args)
+ print "Finished!"
+ print result
return LegacyOONITest
-def findTestClassesFromFile(filename):
+def findTestClassesFromConfig(config):
+ filename = config['test']
+
classes = []
- print "FILENAME %s" % filename
module = filenameToModule(filename)
for name, val in inspect.getmembers(module):
if isTestCase(val):
classes.append(val)
elif isLegacyTest(val):
- classes.append(adaptLegacyTest(val))
+ classes.append(adaptLegacyTest(val, config))
return classes
def makeTestCases(klass, tests, methodPrefix):
@@ -99,13 +132,17 @@ def loadTestsAndOptions(classes):
return testCases, options
class ORunner(object):
- def __init__(self, cases, options=None):
+ def __init__(self, cases, options=None, config=None):
self.baseSuite = InputTestSuite
self.cases = cases
self.options = options
self.inputs = options['inputs']
- self.reporterFactory = ReporterFactory(open('foo.log', 'a+'),
- testSuite=self.baseSuite(self.cases))
+ try:
+ reportFile = open(config['reportfile'], 'a+')
+ except:
+ reportFile = open('report.yaml', 'a+')
+ self.reporterFactory = ReporterFactory(reportFile,
+ testSuite=self.baseSuite(self.cases))
def runWithInputUnit(self, inputUnit):
idx = 0
@@ -126,6 +163,7 @@ class ORunner(object):
result.done()
def run(self):
+ log.start()
self.reporterFactory.writeHeader()
for inputUnit in InputUnitFactory(self.inputs):
More information about the tor-commits
mailing list