[tor-commits] [ooni-probe/develop] Implement starting and stopping of tests via the HTTP API

isis at torproject.org isis at torproject.org
Wed Jun 26 01:02:10 UTC 2013


commit 6f8ee232576dc3a983dcafcdd42a71c0c1cfc0c2
Author: Arturo Filastò <art at fuffa.org>
Date:   Wed Apr 24 21:14:59 2013 +0200

    Implement starting and stopping of tests via the HTTP API
---
 ooni/api/spec.py           |   66 +++++++++++++++++++++++++++++++++++++++++---
 ooni/director.py           |    7 ++---
 ooni/nettest.py            |    5 ++--
 ooni/oonicli.py            |    4 ++-
 ooni/settings.py           |    6 ++++
 ooni/tests/test_nettest.py |    2 +-
 6 files changed, 78 insertions(+), 12 deletions(-)

diff --git a/ooni/api/spec.py b/ooni/api/spec.py
index 5b538b2..ec4cf4b 100644
--- a/ooni/api/spec.py
+++ b/ooni/api/spec.py
@@ -1,10 +1,15 @@
 import os
 import re
+import copy
 import json
 import types
 
+from twisted.python import usage
 from cyclone import web, escape
 
+from ooni.reporter import YAMLReporter, OONIBReporter
+from ooni import errors
+from ooni.nettest import NetTestLoader, MissingRequiredOption
 from ooni.settings import config
 
 class InvalidInputFilename(Exception):
@@ -39,6 +44,7 @@ def list_inputs():
 
 class Inputs(ORequestHandler):
     def get(self):
+        input_list = list_inputs()
         self.write(input_list)
 
     def post(self):
@@ -59,23 +65,75 @@ class Inputs(ORequestHandler):
 
 class ListTests(ORequestHandler):
     def get(self):
-        self.write(oonidApplication.director.netTests)
+        test_list = copy.deepcopy(oonidApplication.director.netTests)
+        for test_id in test_list.keys():
+            test_list[test_id].pop('path')
+        self.write(test_list)
+
+def get_net_test_loader(test_options, test_file):
+    options = []
+    for k, v in test_options.items():
+        options.append('--'+k)
+        options.append(v)
+
+    net_test_loader = NetTestLoader(options,
+            test_file=test_file)
+    return net_test_loader
+
+def get_reporters(net_test_loader):
+    test_details = net_test_loader.testDetails
+    yaml_reporter = YAMLReporter(test_details, config.reports_directory)
+    #oonib_reporter = OONIBReporter(test_details, collector)
+    return [yaml_reporter]
 
 class StartTest(ORequestHandler):
     def post(self, test_name):
         """
         Starts a test with the specified options.
         """
-        json.decode(self.request.body)
+        test_file = oonidApplication.director.netTests[test_name]['path']
+        test_options = json.loads(self.request.body)
+        net_test_loader = get_net_test_loader(test_options, test_file)
+        try:
+            net_test_loader.checkOptions()
+            oonidApplication.director.startNetTest(net_test_loader,
+                                                   get_reporters(net_test_loader))
+        except MissingRequiredOption, option_name:
+            self.write({'error':
+                        'Missing required option: "%s"' % option_name})
+        except usage.UsageError, e:
+            self.write({'error':
+                        'Error in parsing options'})
+        except errors.InsufficientPrivileges:
+            self.write({'error':
+                        'Insufficient priviledges'})
 
 class StopTest(ORequestHandler):
     def delete(self, test_name):
         pass
 
+def get_test_results(test_id):
+    test_results = []
+    for test_result in os.listdir(config.reports_directory):
+        if test_result.startswith('report-'+test_id):
+            with open(os.path.join(config.reports_directory, test_result)) as f:
+                test_content = ''.join(f.readlines())
+            test_results.append({'name': test_result,
+                                 'content': test_content})
+    return test_results
+
 class TestStatus(ORequestHandler):
     def get(self, test_id):
-        pass
-
+        try:
+            test = copy.deepcopy(oonidApplication.director.netTests[test_id])
+            test.pop('path')
+            test['results'] = get_test_results(test_id)
+            self.write(test)
+        except KeyError:
+            self.write({'error':
+                        'Test with such ID not found!'})
+
+config.read_config_file()
 oonidAPI = [
     (r"/status", Status),
     (r"/inputs", Inputs),
diff --git a/ooni/director.py b/ooni/director.py
index 1ef878c..bb02201 100644
--- a/ooni/director.py
+++ b/ooni/director.py
@@ -65,7 +65,6 @@ class Director(object):
 
     def __init__(self):
         self.activeNetTests = []
-        self.netTests = self.getNetTests()
 
         self.measurementManager = MeasurementManager()
         self.measurementManager.director = self
@@ -114,6 +113,8 @@ class Director(object):
 
     @defer.inlineCallbacks
     def start(self):
+        self.netTests = self.getNetTests()
+
         if config.privacy.includepcap:
             log.msg("Starting")
             if not config.reports.pcap:
@@ -207,15 +208,13 @@ class Director(object):
             self.allTestsDone = defer.Deferred()
 
     @defer.inlineCallbacks
-    def startNetTest(self, _, net_test_loader, reporters):
+    def startNetTest(self, net_test_loader, reporters):
         """
         Create the Report for the NetTest and start the report NetTest.
 
         Args:
             net_test_loader:
                 an instance of :class:ooni.nettest.NetTestLoader
-
-            _: #XXX very dirty hack
         """
         report = Report(reporters, self.reportEntryManager)
 
diff --git a/ooni/nettest.py b/ooni/nettest.py
index 0d0e889..964bee3 100644
--- a/ooni/nettest.py
+++ b/ooni/nettest.py
@@ -115,7 +115,7 @@ def getOption(opt_parameter, required_options, type='text'):
         required = False
 
     return {'description': description,
-        'default': default, 'required': required,
+        'value': default, 'required': required,
         'type': type
     }
 
@@ -157,7 +157,8 @@ def getNetTestInformation(net_test_file):
         'name': test_class.name,
         'description': test_class.description,
         'version': test_class.version,
-        'arguments': getArguments(test_class)
+        'arguments': getArguments(test_class),
+        'path': net_test_file
     }
     return information
 
diff --git a/ooni/oonicli.py b/ooni/oonicli.py
index 40453b1..16c02e8 100644
--- a/ooni/oonicli.py
+++ b/ooni/oonicli.py
@@ -178,7 +178,9 @@ def runWithDirector():
                     raise e
 
             log.debug("adding callback for startNetTest")
-            d.addCallback(director.startNetTest, net_test_loader, reporters)
+            @d.addCallback
+            def cb(res):
+                director.startNetTest(net_test_loader, reporters)
         director.allTestsDone.addBoth(shutdown)
 
     def start():
diff --git a/ooni/settings.py b/ooni/settings.py
index acb7502..846fc10 100644
--- a/ooni/settings.py
+++ b/ooni/settings.py
@@ -29,12 +29,15 @@ class OConfig(object):
     def set_paths(self):
         if self.global_options.get('datadir'):
             self.data_directory = abspath(expanduser(self.global_options['datadir']))
+        elif self.advanced.get('data_dir'):
+            self.data_directory = self.advanced['data_dir']
         else:
             self.data_directory = '/usr/share/ooni/'
         self.nettest_directory = os.path.join(self.data_directory, 'nettests')
 
         self.ooni_home = os.path.join(expanduser('~'), '.ooni')
         self.inputs_directory = os.path.join(self.ooni_home, 'inputs')
+        self.reports_directory = os.path.join(self.ooni_home, 'reports')
 
         if self.global_options.get('configfile'):
             config_file = global_options['configfile']
@@ -48,6 +51,8 @@ class OConfig(object):
             print "Creating it in '%s'." % self.ooni_home
             os.mkdir(self.ooni_home)
             os.mkdir(self.inputs_directory)
+        if not os.path.isdir(self.reports_directory):
+            os.mkdir(self.reports_directory)
 
     def _create_config_file(self):
         sample_config_file = os.path.join(self.data_directory,
@@ -75,6 +80,7 @@ class OConfig(object):
                         getattr(self, setting)[k] = v
                 except AttributeError:
                     pass
+        self.set_paths()
 
     def generate_pcap_filename():
         if self.global_options.get('pcapfile'):
diff --git a/ooni/tests/test_nettest.py b/ooni/tests/test_nettest.py
index 77b8a1c..eb909d9 100644
--- a/ooni/tests/test_nettest.py
+++ b/ooni/tests/test_nettest.py
@@ -224,7 +224,7 @@ class TestNetTest(unittest.TestCase):
         ntl.checkOptions()
         director = Director()
 
-        d = director.startNetTest('', ntl, [MockReporter()])
+        d = director.startNetTest(ntl, [MockReporter()])
 
         @d.addCallback
         def complete(result):





More information about the tor-commits mailing list