commit 6f8ee232576dc3a983dcafcdd42a71c0c1cfc0c2 Author: Arturo Filastò art@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):