[tor-commits] [ooni-probe/master] add processTest to NetTest class

isis at torproject.org isis at torproject.org
Sun Mar 10 01:57:01 UTC 2013


commit f7a6a5229c859aa2cc66f307c0b2363ca00346db
Author: aagbsn <aagbsn at extc.org>
Date:   Sat Jan 12 20:35:19 2013 +0000

    add processTest to NetTest class
    
    ripped out of runner.py and needs testing
---
 ooni/nettest.py     |   98 ++++++++++++++++++++++++++++++++++++++++--
 ooni/nettesttask.py |  118 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 212 insertions(+), 4 deletions(-)

diff --git a/ooni/nettest.py b/ooni/nettest.py
index ecf7765..511c3da 100644
--- a/ooni/nettest.py
+++ b/ooni/nettest.py
@@ -30,6 +30,12 @@ class NetTest(object):
 
         self.report = report
 
+    def start(self):
+        """
+        Start tests and generate measurements.
+        """
+        raise NotImplementedError
+
     def loadNetTest(self, net_test_object):
         """
         Creates all the necessary test_cases (a list of tuples containing the
@@ -52,11 +58,16 @@ class NetTest(object):
         """
         try:
             if os.path.isfile(net_test_object):
-                return self._loadNetTestFile(net_test_object)
+                test_cases = self._loadNetTestFile(net_test_object)
         except TypeError:
             if isinstance(net_test_object, StringIO) or \
                 isinstance(net_test_object, str):
-                return self._loadNetTestString(net_test_object)
+                test_cases = self._loadNetTestString(net_test_object)
+
+        if not test_cases:
+            raise NoTestCasesFound
+
+        return test_cases
 
     def _loadNetTestString(self, net_test_string):
         """
@@ -110,8 +121,79 @@ class NetTest(object):
                 measurement.netTest = self
                 yield measurement
 
-class NoPostProcessor(Exception):
-    pass
+    def processTestCasesOptions(self):
+        self.options #XXX is this cmd_line_options?
+
+        # get set of unique classes
+        test_classes = set([])
+        for test_class, test_method in self.test_cases:
+            test_classes.add(test_class)
+
+        #XXX where should the options bound to a test_class get stashed?
+        for test_class in test_classes:
+            options = self._processOptions()
+
+    #XXX: is options passed to init the same as cmd_line_options???
+    def _processTest(self, nettest_test_case, cmd_line_options):
+        """
+        Process the parameters and :class:`twisted.python.usage.Options` of a
+        :class:`ooni.nettest.Nettest`.
+
+        :param obj:
+            An uninstantiated old test, which should be a subclass of
+            :class:`ooni.plugoo.tests.OONITest`.
+
+        :param cmd_line_options:
+            A configured and instantiated :class:`twisted.python.usage.Options`
+            class.
+
+        """
+        obj = nettest_test_case
+        if not hasattr(obj.usageOptions, 'optParameters'):
+            obj.usageOptions.optParameters = []
+
+        if obj.inputFile:
+            obj.usageOptions.optParameters.append(obj.inputFile)
+
+        if obj.baseParameters:
+            for parameter in obj.baseParameters:
+                obj.usageOptions.optParameters.append(parameter)
+
+        if obj.baseFlags:
+            if not hasattr(obj.usageOptions, 'optFlags'):
+                obj.usageOptions.optFlags = []
+            for flag in obj.baseFlags:
+                obj.usageOptions.optFlags.append(flag)
+
+        options = obj.usageOptions()
+
+        options.parseOptions(cmd_line_options['subargs'])
+        obj.localOptions = options
+
+        if obj.inputFile:
+            obj.inputFilename = options[obj.inputFile[0]]
+
+        try:
+            log.debug("processing options")
+            tmp_test_case_object = obj()
+            tmp_test_case_object._checkRequiredOptions()
+
+        except usage.UsageError, e:
+            test_name = tmp_test_case_object.name
+            log.err("There was an error in running %s!" % test_name)
+            log.err("%s" % e)
+            options.opt_help()
+            raise usage.UsageError("Error in parsing command line args for %s" % test_name)
+
+        # who checks for root?
+        if obj.requiresRoot:
+            try:
+                checkForRoot()
+            except NotRootError:
+                log.err("%s requires root to run" % obj.name)
+                sys.exit(1)
+
+        return obj
 
 class NetTestCase(object):
     """
@@ -261,3 +343,11 @@ class NetTestCase(object):
     def __repr__(self):
         return "<%s inputs=%s>" % (self.__class__, self.inputs)
 
+class FailureToLoadNetTest(Exception):
+    pass
+class NoPostProcessor(Exception):
+    pass
+class InvalidOption(Exception):
+    pass
+class MissingRequiredOption(Exception):
+    pass
diff --git a/ooni/nettesttask.py b/ooni/nettesttask.py
new file mode 100644
index 0000000..48c5108
--- /dev/null
+++ b/ooni/nettesttask.py
@@ -0,0 +1,118 @@
+from twisted.internet.task import CooperativeTask
+from twisted.internet import defer
+from ooni.reporter import OONIBReporter, YAMLReporter, OONIBReportError
+from ooni.utils import log
+import time
+from twisted.internet.task import cooperate
+
+class NetTestTask(CooperativeTask):
+    """
+    The object produced by a NetTestTaskFactory.
+
+    A NetTestTask wraps a test_ callable with its options and input unit.
+
+    """
+    def __init__(self, test_case, test_input, oonib_reporter=None, yaml_reporter=None):
+        test_class, test_method = test_case
+        #log.debug("Running %s with %s..." % (test_method, test_input))
+        self.oonib_reporter = oonib_reporter
+        self.oonib_reporter = yaml_reporter
+        self.test_instance = test_class()
+        self.test_instance.input = test_input
+        self.test_instance.report = {}
+        self.test_instance._start_time = time.time()
+        self.test_instance._setUp()
+        self.test_instance.setUp()
+        self.test = getattr(self.test_instance, test_method)
+
+    # XXX: override CoordinatedTask methods
+    def start(self):  #???
+        d = defer.maybeDeferred(self.test)
+        d.addCallback(self.test_done)
+        d.addErrback(self.test_error)
+        return d
+
+    def write_report(self):
+        if not self.oonib_reporter:
+            return self.yaml_reporter.testDone(self.test_instance, str(self.test))
+        d1 = self.oonib_reporter.testDone(self.test_instance, str(self.test))
+        d2 = self.yaml_reporter.testDone(self.test_instance, str(self.test))
+        dl = defer.DeferredList([d1, d2])
+        @dl.addErrback
+        def reportingFailed(failure):
+            log.err("Error in reporting %s" % self.test)
+            log.exception(failure)
+        return dl
+
+    def test_done(self, result):
+        log.msg("Finished running %s" % self.test)
+        log.debug("Deferred callback result: %s" % result)
+        return self.write_report()
+
+    def test_error(self, failure):
+        log.err("Error in running %s" % self.test)
+        log.exception(failure)
+        return self.write_report()
+
+    #XXX: does not implement tests_done!
+
+class NetTestTaskFactory(object):
+    def __init__(self, test_cases, input_unit_list):
+        self.input_unit_list = input_unit_list
+        self.inputs = self.generate_inputs()
+        self.test_cases = test_cases
+
+    def __iter__(self):
+        return self
+
+    def next(self):
+        return self.inputs.next()
+        # XXX: raise exception or fire callback when inputs are exhausted
+
+    def generate_inputs(self):
+        for input_unit in self.input_unit_list:
+            for test_case in self.test_cases:
+                yield NetTestTask(test_case, input_unit)
+
+ at defer.inlineCallbacks
+def runTestCases(test_cases, options, cmd_line_options):
+
+    log.debug("Running %s" % test_cases)
+    log.debug("Options %s" % options)
+    log.debug("cmd_line_options %s" % dict(cmd_line_options))
+
+    test_inputs = options['inputs']
+
+    oonib_reporter = OONIBReporter(cmd_line_options)
+    yaml_reporter = YAMLReporter(cmd_line_options)
+
+    if cmd_line_options['collector']:
+        log.msg("Using remote collector, please be patient while we create the report.")
+        try:
+            yield oonib_reporter.createReport(options)
+        except OONIBReportError:
+            log.err("Error in creating new report")
+            log.msg("We will only create reports to a file")
+            oonib_reporter = None
+    else:
+        oonib_reporter = None
+
+    yield yaml_reporter.createReport(options)
+    log.msg("Reporting to file %s" % yaml_reporter._stream.name)
+
+    nettest_task_factory = NetTestTaskFactory(test_cases, test_inputs)
+
+    #XXX: resume is not supported!
+    try:
+        #XXX: override the default cooperator, set up own scheduler
+        #XXX: add callback when tasks are all exhausted
+        for nettest_task in nettest_task_factory.generate_inputs():
+            nettest_task.yaml_reporter = yaml_reporter
+            nettest_task.oonib_reporter = oonib_reporter
+            log.debug("Running %s with input unit %s" % (nettest_task,
+                        nettest_task.test_instance.input))
+            # feed the cooperator
+            nettest_task.start()
+
+    except Exception:
+        log.exception("Problem in running test")





More information about the tor-commits mailing list