commit 725f9ee90fb10997f57a5c1a5313ae7a84b68249 Author: Arturo Filastò art@fuffa.org Date: Mon Jan 14 20:42:31 2013 +0100
Basic testing and implementation of reporting task manager --- ooni/nettest.py | 6 ++- ooni/reporter.py | 7 ++- ooni/tasks.py | 27 +++++++++-- tests/test_reporter.py | 118 ++++++++++++++++++++--------------------------- 4 files changed, 81 insertions(+), 77 deletions(-)
diff --git a/ooni/nettest.py b/ooni/nettest.py index 67a793d..d6cadc3 100644 --- a/ooni/nettest.py +++ b/ooni/nettest.py @@ -144,10 +144,12 @@ class NetTest(object): yield measurement task_mediator.allTasksScheduled()
- # Once all the MeasurementsTasks have been completed all the report - # tasks will have been scheduled. @task_mediator.allTasksDone.addCallback def done(result): + """ + Once all the MeasurementsTasks have been completed all the report + tasks will have been scheduled. + """ self.report.report_mediator.allTasksScheduled()
def setUpNetTestCases(self): diff --git a/ooni/reporter.py b/ooni/reporter.py index 38e83c3..d24edcc 100644 --- a/ooni/reporter.py +++ b/ooni/reporter.py @@ -177,6 +177,7 @@ class OReporter(object): pass
def testDone(self, test, test_name): + # XXX log.msg("Finished running %s" % test_name) test_report = dict(test.report)
@@ -406,7 +407,8 @@ class Report(object): This will create all the reports that need to be created. """ for reporter in self.reporters: - reporter.createReport() + d = defer.maybeDeferred(reporter.createReport) + d.addCallback(reporter.created.callback)
def write(self, measurement): """ @@ -424,7 +426,8 @@ class Report(object): def cb(result): self.reportEntryManager.schedule(report_write_task)
- def finish(self): + def finish(self, result): + dl = [] for reporter in self.reporters: d = defer.maybeDeferred(reporter.finish) dl.append(d) diff --git a/ooni/tasks.py b/ooni/tasks.py index 3fdf083..f2a9bae 100644 --- a/ooni/tasks.py +++ b/ooni/tasks.py @@ -35,7 +35,7 @@ class BaseTask(object): return result
def start(self): - self.running = self.run() + self.running = defer.maybeDeferred(self.run) self.running.addErrback(self._failed) self.running.addCallback(self._succeeded) return self.running @@ -163,19 +163,36 @@ class TaskMediator(object): self.tasks = 0
self.completedScheduling = False - self.allTasksDone = allTasksDone
def created(self): self.tasks += 1
- def taskDone(self, result): - self.doneTasks += 1 + def checkAllTasksDone(self): if self.completedScheduling and \ self.doneTasks == self.tasks: - self.allTasksDone.callback(None) + self.allTasksDone.callback(self.doneTasks) + + def taskDone(self, result): + """ + This is called every time a task has finished running. + """ + self.doneTasks += 1 + self.checkAllTasksDone()
def allTasksScheduled(self): + """ + This should be called once all the tasks that need to run have been + scheduled. + + XXX this is ghetto. + The reason for which we are calling allTasksDone inside of the + allTasksScheduled method is called after all tasks are done, then we + will run into a race condition. The race is that we don't end up + checking that all the tasks are complete because no task is to be + scheduled. + """ self.completedScheduling = True + self.checkAllTasksDone()
diff --git a/tests/test_reporter.py b/tests/test_reporter.py index cfa0afd..1754ad0 100644 --- a/tests/test_reporter.py +++ b/tests/test_reporter.py @@ -1,76 +1,58 @@ +from twisted.internet import defer from twisted.trial import unittest + from ooni.reporter import Report, YAMLReporter, OONIBReporter -from ooni.managers import ReportEntryManager +from ooni.managers import ReportEntryManager, TaskManager from ooni.nettest import NetTest -from ooni.tasks import TaskMediator + +from ooni.tasks import TaskMediator, TaskWithTimeout
mockReportOptions = {'name':'foo_test', 'version': '0.1'}
-class TestYAMLReporter(unittest.TestCase): - def setUp(self): +class MockOReporter(object): + def __init__(self): + self.created = defer.Deferred() + + def writeReportEntry(self, entry): + pass + + def finish(self): + pass + + def createReport(self): + pass + +class MockMeasurement(TaskWithTimeout): + def __init__(self): + TaskWithTimeout.__init__(self) + + def succeeded(self, result): pass
- def test_create_yaml_reporter(self): - - YAMLReporter.reportFilePrefix = "spam" - YAMLReporter.options = mockReportOptions - report = Report([YAMLReporter]) - #XXX: calls createReport on init. is that what we want? - report.reportEntryManager = ReportEntryManager() - allTasksDone = defer.Deferred() - report.taskmediator = TaskMediator() - - #def test_create_yaml_report(self): - # # should create a YAML report - # raise NotImplementedError - - def test_write_yaml_report(self): - YAMLReporter.reportFilePrefix = "spam" - YAMLReporter.options = mockReportOptions - report = Report([YAMLReporter]) - #XXX: fire createReport on init. is that what we want? - report.reportEntryManager = ReportEntryManager() - report.write("HAI") - - def test_write_yaml_report_before_create(self): - # should write to YAML report before it has been created - # the write should not occur until after the created callback has fired - raise NotImplementedError - - def test_yaml_report_completed(self): - # should test that a report will complete successfully - # it should fire a callback after the report.finish method is called, - # XXX: a report should not be finalized until after all pending - # writes have completed - raise NotImplementedError - - def test_write_after_completed(self): - # try to call write after a report is completed/finalized. it must fail - # it should also fail in the sense that as long as the finalize-report has - # been called no additional reports entries can be added, but - # existing/pending entries should be completed before the report - # finalized callback is fired - raise NotImplementedError - - -#class OONIBReporter(unittest.TestCase): -# def setUp(self): -# #XXX set up a dummy OONIB backend -# pass -# -# def test_create_oonib_reporter(self): -# # should instance a OONIB reporter -# raise NotImplementedError -# -# def test_create_oonib_report(self): -# # should create a YAML report -# raise NotImplementedError -# -# def test_write_oonib_report(self): -# # should write to YAML report -# raise NotImplementedError -# -# def test_write_oonib_report_before_create(self): -# # should write to YAML report before it has been created -# # the write should not occur until after the created callback has fired -# raise NotImplementedError +class MockTaskManager(TaskManager): + def __init__(self): + self.successes = [] + + def failed(self, failure, task): + pass + + def succeeded(self, result, task): + self.successes.append((result, task)) + +class TestReport(unittest.TestCase): + def setUp(self): + self.report = Report([MockOReporter]) + self.report.reportEntryManager = MockTaskManager() + + def test_report_alltasksdone_callback_fires(self): + for m in range(10): + measurement = MockMeasurement() + self.report.write(measurement) + + self.report.report_mediator.allTasksScheduled() + + @self.report.done.addCallback + def done(reporters): + self.assertEqual(len(reporters), 1) + + return self.report.done
tor-commits@lists.torproject.org