[tor-commits] [ooni-probe/master] Reorganization of code tree
art at torproject.org
art at torproject.org
Wed Jun 19 12:32:45 UTC 2013
commit 7393a4e3eb57bcf3c14685b240e3ab5eebfe97d3
Author: Arturo Filastò <art at fuffa.org>
Date: Wed Mar 6 15:48:48 2013 +0100
Reorganization of code tree
* Move unittests into ooni directory
---
bin/ooniprobe | 4 +-
nettests/examples/example_myip.py | 4 +
nettests/tls-handshake.py | 32 -----
ooni/api/spec.py | 92 +++++++++++++
ooni/config.py | 134 ++++++++-----------
ooni/director.py | 29 +++-
ooni/nettest.py | 208 ++++++++++++++++++++--------
ooni/oonicli.py | 7 +-
ooni/oonid.py | 20 +++
ooni/reporter.py | 2 +-
ooni/runner.py | 241 ---------------------------------
ooni/tests/mocks.py | 172 ++++++++++++++++++++++++
ooni/tests/test-class-design.py | 101 ++++++++++++++
ooni/tests/test_director.py | 58 ++++++++
ooni/tests/test_dns.py | 24 ++++
ooni/tests/test_managers.py | 215 +++++++++++++++++++++++++++++
ooni/tests/test_mutate.py | 15 +++
ooni/tests/test_nettest.py | 268 +++++++++++++++++++++++++++++++++++++
ooni/tests/test_otime.py | 15 +++
ooni/tests/test_reporter.py | 238 ++++++++++++++++++++++++++++++++
ooni/tests/test_safe_represent.py | 14 ++
ooni/tests/test_trueheaders.py | 41 ++++++
ooni/tests/test_utils.py | 20 +++
ooni/utils/log.py | 8 +-
ooniprobe.conf.sample | 2 +
tests/mocks.py | 168 -----------------------
tests/test-class-design.py | 101 --------------
tests/test_director.py | 59 --------
tests/test_dns.py | 24 ----
tests/test_inputunit.py | 29 ----
tests/test_managers.py | 215 -----------------------------
tests/test_mutate.py | 15 ---
tests/test_nettest.py | 268 -------------------------------------
tests/test_otime.py | 15 ---
tests/test_reporter.py | 238 --------------------------------
tests/test_safe_represent.py | 14 --
tests/test_trueheaders.py | 41 ------
tests/test_utils.py | 20 ---
38 files changed, 1545 insertions(+), 1626 deletions(-)
diff --git a/bin/ooniprobe b/bin/ooniprobe
index 695b137..ba537ab 100755
--- a/bin/ooniprobe
+++ b/bin/ooniprobe
@@ -8,10 +8,10 @@ sys.path[:] = map(os.path.abspath, sys.path)
sys.path.insert(0, os.path.abspath(os.getcwd()))
# This is a hack to overcome a bug in python
-from ooni.utils.hacks import patched_reduce_ex
+from ooniprobe.utils.hacks import patched_reduce_ex
copy_reg._reduce_ex = patched_reduce_ex
# from ooni.oonicli import run
# run()
-from ooni.oonicli import runWithDirector
+from ooniprobe.oonicli import runWithDirector
runWithDirector()
diff --git a/nettests/examples/example_myip.py b/nettests/examples/example_myip.py
index 40a4849..70cf773 100644
--- a/nettests/examples/example_myip.py
+++ b/nettests/examples/example_myip.py
@@ -6,6 +6,10 @@
from ooni.templates import httpt
class MyIP(httpt.HTTPTest):
inputs = ['https://check.torproject.org']
+
+ def test_lookup(self):
+ return self.doRequest(self.input)
+
def processResponseBody(self, body):
import re
regexp = "Your IP address appears to be: <b>(.+?)<\/b>"
diff --git a/nettests/tls-handshake.py b/nettests/tls-handshake.py
deleted file mode 100644
index eba950e..0000000
--- a/nettests/tls-handshake.py
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/env python
-
-import subprocess
-from subprocess import PIPE
-serverport = "129.21.124.215:443"
-# a subset of those from firefox
-ciphers = [
- "ECDHE-ECDSA-AES256-SHA",
- "ECDHE-RSA-AES256-SHA",
- "DHE-RSA-CAMELLIA256-SHA",
- "DHE-DSS-CAMELLIA256-SHA",
- "DHE-RSA-AES256-SHA",
- "DHE-DSS-AES256-SHA",
- "ECDH-ECDSA-AES256-CBC-SHA",
- "ECDH-RSA-AES256-CBC-SHA",
- "CAMELLIA256-SHA",
- "AES256-SHA",
- "ECDHE-ECDSA-RC4-SHA",
- "ECDHE-ECDSA-AES128-SHA",
- "ECDHE-RSA-RC4-SHA",
- "ECDHE-RSA-AES128-SHA",
- "DHE-RSA-CAMELLIA128-SHA",
- "DHE-DSS-CAMELLIA128-SHA"
-]
-def checkBridgeConnection(host, port)
- cipher_arg = ":".join(ciphers)
- cmd = ["openssl", "s_client", "-connect", "%s:%s" % (host,port)]
- cmd += ["-cipher", cipher_arg]
- proc = subprocess.Popen(cmd, stdout=PIPE, stderr=PIPE,stdin=PIPE)
- out, error = proc.communicate()
- success = "Cipher is DHE-RSA-AES256-SHA" in out
- return success
diff --git a/ooni/api/__init__.py b/ooni/api/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/ooni/api/spec.py b/ooni/api/spec.py
new file mode 100644
index 0000000..af238f4
--- /dev/null
+++ b/ooni/api/spec.py
@@ -0,0 +1,92 @@
+import os
+import re
+import json
+import types
+
+from cyclone import web, escape
+
+from ooni import config
+
+class InvalidInputFilename(Exception):
+ pass
+
+class FilenameExists(Exception):
+ pass
+
+class ORequestHandler(web.RequestHandler):
+ serialize_lists = True
+
+ def write(self, chunk):
+ """
+ XXX This is a patch that can be removed once
+ https://github.com/fiorix/cyclone/pull/92 makes it into a release.
+ """
+ if isinstance(chunk, types.ListType):
+ chunk = escape.json_encode(chunk)
+ self.set_header("Content-Type", "application/json")
+ web.RequestHandler.write(self, chunk)
+
+class Status(ORequestHandler):
+ def get(self):
+ result = {'active_tests': oonidApplication.director.activeNetTests}
+ self.write(result)
+
+def list_inputs():
+ input_list = []
+ for filename in os.listdir(config.inputs_directory):
+ input_list.append({'filename': filename})
+ return input_list
+
+class Inputs(ORequestHandler):
+ def get(self):
+ self.write(input_list)
+
+ def post(self):
+ filename = self.get_argument("fullname", None)
+ if not filename or not re.match('(\w.*\.\w.*).*', filename):
+ raise InvalidInputFilename
+
+ if os.path.exists(filename):
+ raise FilenameExists
+
+ input_file = self.request.files.get("input_file")
+ content_type = input_file["content_type"]
+ body = input_file["body"]
+
+ fn = os.path.join(config.inputs_directory, filename)
+ with open(os.path.abspath(fn), "w") as fp:
+ fp.write(body)
+
+class ListTests(ORequestHandler):
+ def get(self):
+ self.write(oonidApplication.director.netTests)
+
+class StartTest(ORequestHandler):
+ def post(self, test_name):
+ """
+ Starts a test with the specified options.
+ """
+ json.decode(self.request.body)
+
+class StopTest(ORequestHandler):
+ def delete(self, test_name):
+ pass
+
+class TestStatus(ORequestHandler):
+ def get(self, test_id):
+ pass
+
+oonidAPI = [
+ (r"/status", Status),
+ (r"/inputs", Inputs),
+ (r"/test", ListTests),
+ (r"/test/(.*)/start", StartTest),
+ (r"/test/(.*)/stop", StopTest),
+ (r"/test/(.*)", TestStatus),
+ (r"/(.*)", web.StaticFileHandler,
+ {"path": os.path.join(config.data_directory, 'ui', 'app'),
+ "default_filename": "index.html"})
+]
+
+oonidApplication = web.Application(oonidAPI, debug=True)
+
diff --git a/ooni/config.py b/ooni/config.py
index 74a1668..5aeb49d 100644
--- a/ooni/config.py
+++ b/ooni/config.py
@@ -6,33 +6,8 @@ from twisted.internet import reactor, threads, defer
from ooni import otime
from ooni.utils import Storage
-reports = Storage()
-scapyFactory = None
-stateDict = None
-state = Storage()
-
-# XXX refactor this to use a database
-resume_lock = defer.DeferredLock()
-
-basic = None
-cmd_line_options = None
-resume_filename = None
-
-# XXX-Twisted this is used to check if we have started the reactor or not. It
-# is necessary because if the tests are already concluded because we have
-# resumed a test session then it will call reactor.run() even though there is
-# no condition that will ever stop it.
-# There should be a more twisted way of doing this.
-start_reactor = True
-
-tor_state = None
-tor_control = None
-
-config_file = None
-sample_config_file = None
-
-# This is used to store the probes IP address obtained via Tor
-probe_ip = None
+class TestFilenameNotSet(Exception):
+ pass
def get_root_path():
this_directory = os.path.dirname(__file__)
@@ -46,50 +21,6 @@ def createConfigFile():
"""
sample_config_file = os.path.join(get_root_path(), 'ooniprobe.conf.sample')
-def loadConfigFile():
- """
- This is a helper function that makes sure that the configuration attributes
- are singletons.
- """
- config_file = os.path.join(get_root_path(), 'ooniprobe.conf')
- try:
- f = open(config_file)
- except IOError:
- createConfigFile()
- raise Exception("Unable to open config file. "\
- "Copy ooniprobe.conf.sample to ooniprobe.conf")
-
- config_file_contents = '\n'.join(f.readlines())
- configuration = yaml.safe_load(config_file_contents)
-
- # Process the basic configuration options
- basic = Storage()
- for k, v in configuration['basic'].items():
- basic[k] = v
-
- # Process the privacy configuration options
- privacy = Storage()
- for k, v in configuration['privacy'].items():
- privacy[k] = v
-
- # Process the advanced configuration options
- advanced = Storage()
- for k, v in configuration['advanced'].items():
- advanced[k] = v
-
- # Process the tor configuration options
- tor = Storage()
- try:
- for k, v in configuration['tor'].items():
- tor[k] = v
- except AttributeError:
- pass
-
- return basic, privacy, advanced, tor
-
-class TestFilenameNotSet(Exception):
- pass
-
def generatePcapFilename():
if cmd_line_options['pcapfile']:
reports.pcap = cmd_line_options['pcapfile']
@@ -103,9 +34,61 @@ def generatePcapFilename():
frm_str = "report_%s_"+otime.timestamp()+".%s"
reports.pcap = frm_str % (test_name, "pcap")
-if not basic:
- # Here we make sure that we instance the config file attributes only once
- basic, privacy, advanced, tor = loadConfigFile()
+class ConfigurationSetting(Storage):
+ def __init__(self, key):
+ config_file = os.path.join(get_root_path(), 'ooniprobe.conf')
+ try:
+ f = open(config_file)
+ except IOError:
+ createConfigFile()
+ raise Exception("Unable to open config file. "\
+ "Copy ooniprobe.conf.sample to ooniprobe.conf")
+
+ config_file_contents = '\n'.join(f.readlines())
+ configuration = yaml.safe_load(config_file_contents)
+
+ try:
+ for k, v in configuration[key].items():
+ self[k] = v
+ except AttributeError:
+ pass
+
+basic = ConfigurationSetting('basic')
+advanced = ConfigurationSetting('advanced')
+privacy = ConfigurationSetting('privacy')
+tor = ConfigurationSetting('tor')
+
+data_directory = os.path.join(get_root_path(), 'data')
+nettest_directory = os.path.join(get_root_path(), 'nettests')
+inputs_directory = os.path.join(get_root_path(), 'inputs')
+
+reports = Storage()
+state = Storage()
+scapyFactory = None
+stateDict = None
+
+# XXX refactor this to use a database
+resume_lock = defer.DeferredLock()
+
+cmd_line_options = None
+resume_filename = None
+
+# XXX-Twisted this is used to check if we have started the reactor or not. It
+# is necessary because if the tests are already concluded because we have
+# resumed a test session then it will call reactor.run() even though there is
+# no condition that will ever stop it.
+# There should be a more twisted way of doing this.
+start_reactor = True
+tor_state = None
+tor_control = None
+config_file = None
+sample_config_file = None
+# This is used to store the probes IP address obtained via Tor
+probe_ip = None
+# This is used to keep track of the state of the sniffer
+sniffer_running = None
+
+logging = True
if not resume_filename:
resume_filename = os.path.join(get_root_path(), 'ooniprobe.resume')
@@ -113,6 +96,3 @@ if not resume_filename:
with open(resume_filename) as f: pass
except IOError as e:
with open(resume_filename, 'w+') as f: pass
-
-# This is used to keep track of the state of the sniffer
-sniffer_running = None
diff --git a/ooni/director.py b/ooni/director.py
index 8365ebd..a9daf84 100644
--- a/ooni/director.py
+++ b/ooni/director.py
@@ -6,7 +6,7 @@ from ooni.managers import ReportEntryManager, MeasurementManager
from ooni.reporter import Report
from ooni.utils import log, checkForRoot, NotRootError
from ooni.utils.net import randomFreePort
-from ooni.nettest import NetTest
+from ooni.nettest import NetTest, getNetTestInformation
from ooni.errors import UnableToStartTor
from txtorcon import TorConfig
@@ -57,10 +57,12 @@ class Director(object):
"""
_scheduledTests = 0
+ # Only list NetTests belonging to these categories
+ categories = ['blocking', 'manipulation']
def __init__(self):
- self.netTests = []
self.activeNetTests = []
+ self.netTests = self.getNetTests()
self.measurementManager = MeasurementManager()
self.measurementManager.director = self
@@ -80,6 +82,29 @@ class Director(object):
self.torControlProtocol = None
+ def getNetTests(self):
+ nettests = {}
+ def is_nettest(filename):
+ return not filename == '__init__.py' \
+ and filename.endswith('.py')
+
+ for category in self.categories:
+ dirname = os.path.join(config.nettest_directory, category)
+ # print path to all filenames.
+ for filename in os.listdir(dirname):
+ if is_nettest(filename):
+ net_test_file = os.path.join(dirname, filename)
+ nettest = getNetTestInformation(net_test_file)
+
+ if nettest['id'] in nettests:
+ log.err("Found a two tests with the same name %s, %s" %
+ (nettest_path, nettests[nettest['id']]['path']))
+ else:
+ category = dirname.replace(config.nettest_directory, '')
+ nettests[nettest['id']] = nettest
+
+ return nettests
+
def start(self):
if config.privacy.includepcap:
log.msg("Starting")
diff --git a/ooni/nettest.py b/ooni/nettest.py
index 1fe19f1..dc72ce8 100644
--- a/ooni/nettest.py
+++ b/ooni/nettest.py
@@ -18,15 +18,162 @@ from StringIO import StringIO
class NoTestCasesFound(Exception):
pass
+def get_test_methods(item, method_prefix="test_"):
+ """
+ Look for test_ methods in subclasses of NetTestCase
+ """
+ test_cases = []
+ try:
+ assert issubclass(item, NetTestCase)
+ methods = reflect.prefixedMethodNames(item, method_prefix)
+ test_methods = []
+ for method in methods:
+ test_methods.append(method_prefix + method)
+ if test_methods:
+ test_cases.append((item, test_methods))
+ except (TypeError, AssertionError):
+ pass
+ return test_cases
+
+def loadNetTestString(net_test_string):
+ """
+ Load NetTest from a string.
+ WARNING input to this function *MUST* be sanitized and *NEVER* be
+ untrusted.
+ Failure to do so will result in code exec.
+
+ net_test_string:
+
+ a string that contains the net test to be run.
+ """
+ net_test_file_object = StringIO(net_test_string)
+
+ ns = {}
+ test_cases = []
+ exec net_test_file_object.read() in ns
+ for item in ns.itervalues():
+ test_cases.extend(get_test_methods(item))
+
+ if not test_cases:
+ raise NoTestCasesFound
+
+ return test_cases
+
+def loadNetTestFile(net_test_file):
+ """
+ Load NetTest from a file.
+ """
+ test_cases = []
+ module = filenameToModule(net_test_file)
+ for __, item in getmembers(module):
+ test_cases.extend(get_test_methods(item))
+
+ if not test_cases:
+ raise NoTestCasesFound
+
+ return test_cases
+
+def getTestClassFromFile(net_test_file):
+ """
+ Will return the first class that is an instance of NetTestCase.
+
+ XXX this means that if inside of a test there are more than 1 test case
+ then we will only run the first one.
+ """
+ module = filenameToModule(net_test_file)
+ for __, item in getmembers(module):
+ try:
+ assert issubclass(item, NetTestCase)
+ return item
+ except (TypeError, AssertionError):
+ pass
+
+def getOption(opt_parameter, required_options, type='text'):
+ """
+ Arguments:
+ usage_options: a list as should be the optParameters of an UsageOptions class.
+
+ required_options: a list containing the strings of the options that are
+ required.
+
+ type: a string containing the type of the option.
+
+ Returns:
+ a dict containing
+ {
+ 'description': the description of the option,
+ 'default': the default value of the option,
+ 'required': True|False if the option is required or not,
+ 'type': the type of the option ('text' or 'file')
+ }
+ """
+ option_name, _, default, description = opt_parameter
+ if option_name in required_options:
+ required = True
+ else:
+ required = False
+
+ return {'description': description,
+ 'default': default, 'required': required,
+ 'type': type
+ }
+
+def getArguments(test_class):
+ arguments = {}
+ if test_class.inputFile:
+ option_name = test_class.inputFile[0]
+ arguments[option_name] = getOption(test_class.inputFile,
+ test_class.requiredOptions, type='file')
+ try:
+ list(test_class.usageOptions.optParameters)
+ except AttributeError:
+ return arguments
+
+ for opt_parameter in test_class.usageOptions.optParameters:
+ option_name = opt_parameter[0]
+ arguments[option_name] = getOption(opt_parameter,
+ test_class.requiredOptions)
+
+ return arguments
+
+def getNetTestInformation(net_test_file):
+ """
+ Returns a dict containing:
+
+ {
+ 'id': the test filename excluding the .py extension,
+ 'name': the full name of the test,
+ 'description': the description of the test,
+ 'version': version number of this test,
+ 'arguments': a dict containing as keys the supported arguments and as
+ values the argument description.
+ }
+ """
+ test_class = getTestClassFromFile(net_test_file)
+
+ test_id = os.path.basename(net_test_file).replace('.py', '')
+ information = {'id': test_id,
+ 'name': test_class.name,
+ 'description': test_class.description,
+ 'version': test_class.version,
+ 'arguments': getArguments(test_class)
+ }
+ return information
+
class NetTestLoader(object):
method_prefix = 'test'
def __init__(self, options, test_file=None, test_string=None):
self.options = options
+ test_cases = None
+
if test_file:
- self.loadNetTestFile(test_file)
+ test_cases = loadNetTestFile(test_file)
elif test_string:
- self.loadNetTestString(test_string)
+ test_cases = loadNetTestString(test_string)
+
+ if test_cases:
+ self.setupTestCases(test_cases)
@property
def testDetails(self):
@@ -115,44 +262,6 @@ class NetTestLoader(object):
assert usage_options == test_class.usageOptions
return usage_options
- def loadNetTestString(self, net_test_string):
- """
- Load NetTest from a string.
- WARNING input to this function *MUST* be sanitized and *NEVER* be
- untrusted.
- Failure to do so will result in code exec.
-
- net_test_string:
-
- a string that contains the net test to be run.
- """
- net_test_file_object = StringIO(net_test_string)
-
- ns = {}
- test_cases = []
- exec net_test_file_object.read() in ns
- for item in ns.itervalues():
- test_cases.extend(self._get_test_methods(item))
-
- if not test_cases:
- raise NoTestCasesFound
-
- self.setupTestCases(test_cases)
-
- def loadNetTestFile(self, net_test_file):
- """
- Load NetTest from a file.
- """
- test_cases = []
- module = filenameToModule(net_test_file)
- for __, item in getmembers(module):
- test_cases.extend(self._get_test_methods(item))
-
- if not test_cases:
- raise NoTestCasesFound
-
- self.setupTestCases(test_cases)
-
def setupTestCases(self, test_cases):
"""
Creates all the necessary test_cases (a list of tuples containing the
@@ -205,22 +314,6 @@ class NetTestLoader(object):
inputs = [None]
klass.inputs = inputs
- def _get_test_methods(self, item):
- """
- Look for test_ methods in subclasses of NetTestCase
- """
- test_cases = []
- try:
- assert issubclass(item, NetTestCase)
- methods = reflect.prefixedMethodNames(item, self.method_prefix)
- test_methods = []
- for method in methods:
- test_methods.append(self.method_prefix + method)
- if test_methods:
- test_cases.append((item, test_methods))
- except (TypeError, AssertionError):
- pass
- return test_cases
class NetTestState(object):
def __init__(self, allTasksDone):
@@ -409,9 +502,10 @@ class NetTestCase(object):
Quirks:
Every class that is prefixed with test *must* return a twisted.internet.defer.Deferred.
"""
- name = "I Did Not Change The Name"
+ name = "This test is nameless"
author = "Jane Doe <foo at example.com>"
version = "0.0.0"
+ description = "Sorry, this test has no description :("
inputs = [None]
inputFile = None
diff --git a/ooni/oonicli.py b/ooni/oonicli.py
index 06aa20c..a99386d 100644
--- a/ooni/oonicli.py
+++ b/ooni/oonicli.py
@@ -10,12 +10,11 @@ from twisted.internet import reactor
from twisted.python import usage
from twisted.python.util import spewer
-from ooni.errors import InvalidOONIBCollectorAddress
-
+from ooni import errors
from ooni import config
+
from ooni.director import Director
from ooni.reporter import YAMLReporter, OONIBReporter
-
from ooni.nettest import NetTestLoader, MissingRequiredOption
from ooni.utils import log
@@ -147,7 +146,7 @@ def runWithDirector():
oonib_reporter = OONIBReporter(test_details,
global_options['collector'])
reporters.append(oonib_reporter)
- except InvalidOONIBCollectorAddress:
+ except errors.InvalidOONIBCollectorAddress:
log.err("Invalid format for oonib collector address.")
log.msg("Should be in the format http://<collector_address>:<port>")
log.msg("for example: ooniprobe -c httpo://nkvphnp3p6agi5qq.onion")
diff --git a/ooni/oonid.py b/ooni/oonid.py
new file mode 100644
index 0000000..dde768e
--- /dev/null
+++ b/ooni/oonid.py
@@ -0,0 +1,20 @@
+import os
+import random
+
+from twisted.application import service, internet
+from twisted.web import static, server
+
+from ooni import config
+from ooni.api.spec import oonidApplication
+from ooni.director import Director
+from ooni.reporter import YAMLReporter, OONIBReporter
+
+def getOonid():
+ director = Director()
+ director.start()
+ oonidApplication.director = director
+ return internet.TCPServer(int(config.advanced.oonid_api_port), oonidApplication)
+
+application = service.Application("ooniprobe")
+service = getOonid()
+service.setServiceParent(application)
diff --git a/ooni/reporter.py b/ooni/reporter.py
index 84dad2f..a7bd933 100644
--- a/ooni/reporter.py
+++ b/ooni/reporter.py
@@ -26,7 +26,7 @@ except ImportError:
log.err("Scapy is not installed.")
-from ooni.errors import InvalidOONIBCollectorAddress
+from ooni.errors import InvalidOONIBCollectorAddress, NoMoreReporters
from ooni.errors import ReportNotCreated, ReportAlreadyClosed
from ooni import otime
diff --git a/ooni/runner.py b/ooni/runner.py
deleted file mode 100644
index 080db18..0000000
--- a/ooni/runner.py
+++ /dev/null
@@ -1,241 +0,0 @@
-import os
-import time
-import random
-
-import yaml
-
-from twisted.internet import defer
-from twisted.internet import reactor
-
-from txtorcon import TorConfig
-from txtorcon import TorState, launch_tor
-
-from ooni import config
-from ooni.reporter import OONIBReporter, YAMLReporter, OONIBReportError
-from ooni.inputunit import InputUnitFactory
-from ooni.nettest import NetTestCase, NoPostProcessor
-from ooni.utils import log, checkForRoot, pushFilenameStack
-from ooni.utils import NotRootError, Storage
-from ooni.utils.net import randomFreePort
-
-class InvalidResumeFile(Exception):
- pass
-
-class noResumeSession(Exception):
- pass
-
-def loadResumeFile():
- """
- Sets the singleton stateDict object to the content of the resume file.
- If the file is empty then it will create an empty one.
-
- Raises:
-
- :class:ooni.runner.InvalidResumeFile if the resume file is not valid
-
- """
- if not config.stateDict:
- try:
- with open(config.resume_filename) as f:
- config.stateDict = yaml.safe_load(f)
- except:
- log.err("Error loading YAML file")
- raise InvalidResumeFile
-
- if not config.stateDict:
- with open(config.resume_filename, 'w+') as f:
- yaml.safe_dump(dict(), f)
- config.stateDict = dict()
-
- elif isinstance(config.stateDict, dict):
- return
- else:
- log.err("The resume file is of the wrong format")
- raise InvalidResumeFile
-
-def resumeTest(test_filename, input_unit_factory):
- """
- Returns the an input_unit_factory that is at the index of the previous run of the test
- for the specified test_filename.
-
- Args:
-
- test_filename (str): the filename of the test that is being run
- including the .py extension.
-
- input_unit_factory (:class:ooni.inputunit.InputUnitFactory): with the
- same input of the past run.
-
- Returns:
-
- :class:ooni.inputunit.InputUnitFactory that is at the index of the
- previous test run.
-
- """
- try:
- idx = config.stateDict[test_filename]
- for x in range(idx):
- try:
- input_unit_factory.next()
- except StopIteration:
- log.msg("Previous run was complete")
- return input_unit_factory
-
- return input_unit_factory
-
- except KeyError:
- log.debug("No resume key found for selected test name. It is therefore 0")
- config.stateDict[test_filename] = 0
- return input_unit_factory
-
- at defer.inlineCallbacks
-def updateResumeFile(test_filename):
- """
- update the resume file with the current stateDict state.
- """
- log.debug("Acquiring lock for %s" % test_filename)
- yield config.resume_lock.acquire()
-
- current_resume_state = yaml.safe_load(open(config.resume_filename))
- current_resume_state = config.stateDict
- yaml.safe_dump(current_resume_state, open(config.resume_filename, 'w+'))
-
- log.debug("Releasing lock for %s" % test_filename)
- config.resume_lock.release()
- defer.returnValue(config.stateDict[test_filename])
-
- at defer.inlineCallbacks
-def increaseInputUnitIdx(test_filename):
- """
- Args:
-
- test_filename (str): the filename of the test that is being run
- including the .py extension.
-
- input_unit_idx (int): the current input unit index for the test.
-
- """
- config.stateDict[test_filename] += 1
- yield updateResumeFile(test_filename)
-
-def updateProgressMeters(test_filename, input_unit_factory,
- test_case_number):
- """
- Update the progress meters for keeping track of test state.
- """
- if not config.state.test_filename:
- config.state[test_filename] = Storage()
-
- config.state[test_filename].per_item_average = 2.0
-
- input_unit_idx = float(config.stateDict[test_filename])
- input_unit_items = len(input_unit_factory)
- test_case_number = float(test_case_number)
- total_iterations = input_unit_items * test_case_number
- current_iteration = input_unit_idx * test_case_number
-
- log.debug("input_unit_items: %s" % input_unit_items)
- log.debug("test_case_number: %s" % test_case_number)
-
- log.debug("Test case number: %s" % test_case_number)
- log.debug("Total iterations: %s" % total_iterations)
- log.debug("Current iteration: %s" % current_iteration)
-
- def progress():
- return (current_iteration / total_iterations) * 100.0
-
- config.state[test_filename].progress = progress
-
- def eta():
- return (total_iterations - current_iteration) \
- * config.state[test_filename].per_item_average
- config.state[test_filename].eta = eta
-
- config.state[test_filename].input_unit_idx = input_unit_idx
- config.state[test_filename].input_unit_items = input_unit_items
-
-
- 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']
-
- # Set a default reporter
- if not cmd_line_options['collector'] and not \
- cmd_line_options['no-default-reporter']:
- with open('collector') as f:
- reporter_url = random.choice(f.readlines())
- reporter_url = reporter_url.split('#')[0].strip()
- cmd_line_options['collector'] = reporter_url
-
- 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)
-
- try:
- input_unit_factory = InputUnitFactory(test_inputs)
- input_unit_factory.inputUnitSize = int(cmd_line_options['parallelism'])
- except Exception, e:
- log.exception(e)
-
- try:
- loadResumeFile()
- except InvalidResumeFile:
- log.err("Error in loading resume file %s" % config.resume_filename)
- log.err("Try deleting the resume file")
- raise InvalidResumeFile
-
- test_filename = os.path.basename(cmd_line_options['test'])
-
- if cmd_line_options['resume']:
- log.debug("Resuming %s" % test_filename)
- resumeTest(test_filename, input_unit_factory)
- else:
- log.debug("Not going to resume %s" % test_filename)
- config.stateDict[test_filename] = 0
-
- updateProgressMeters(test_filename, input_unit_factory, len(test_cases))
-
- try:
- for input_unit in input_unit_factory:
- log.debug("Running %s with input unit %s" % (test_filename, input_unit))
-
- yield runTestCasesWithInputUnit(test_cases, input_unit,
- yaml_reporter, oonib_reporter)
-
- yield increaseInputUnitIdx(test_filename)
-
- updateProgressMeters(test_filename, input_unit_factory, len(test_cases))
-
- except Exception:
- log.exception("Problem in running test")
- yaml_reporter.finish()
-
-def loadTest(cmd_line_options):
- """
- Takes care of parsing test command line arguments and loading their
- options.
- """
- # XXX here there is too much strong coupling with cmd_line_options
- # Ideally this would get all wrapped in a nice little class that get's
- # instanced with it's cmd_line_options as an instance attribute
- classes = findTestClassesFromFile(cmd_line_options)
- test_cases, options = loadTestsAndOptions(classes, cmd_line_options)
-
- return test_cases, options, cmd_line_options
diff --git a/ooni/tests/__init__.py b/ooni/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/ooni/tests/mocks.py b/ooni/tests/mocks.py
new file mode 100644
index 0000000..99e5200
--- /dev/null
+++ b/ooni/tests/mocks.py
@@ -0,0 +1,172 @@
+from twisted.python import failure
+from twisted.internet import defer
+
+from ooni import config
+from ooni.tasks import BaseTask, TaskWithTimeout
+from ooni.nettest import NetTest
+from ooni.managers import TaskManager
+
+config.logging = False
+
+class MockMeasurementFailOnce(BaseTask):
+ def run(self):
+ f = open('dummyTaskFailOnce.txt', 'w')
+ f.write('fail')
+ f.close()
+ if self.failure >= 1:
+ return defer.succeed(self)
+ else:
+ return defer.fail(failure.Failure)
+
+class MockMeasurementManager(TaskManager):
+ def __init__(self):
+ self.successes = []
+ TaskManager.__init__(self)
+
+ def failed(self, failure, task):
+ pass
+
+ def succeeded(self, result, task):
+ self.successes.append((result, task))
+
+class MockReporter(object):
+ def __init__(self):
+ self.created = defer.Deferred()
+
+ def writeReportEntry(self, entry):
+ pass
+
+ def createReport(self):
+ self.created.callback(self)
+
+ def finish(self):
+ pass
+
+class MockFailure(Exception):
+ pass
+
+## from test_managers
+mockFailure = failure.Failure(MockFailure('mock'))
+
+class MockSuccessTask(BaseTask):
+ def run(self):
+ return defer.succeed(42)
+
+class MockFailTask(BaseTask):
+ def run(self):
+ return defer.fail(mockFailure)
+
+class MockFailOnceTask(BaseTask):
+ def run(self):
+ if self.failures >= 1:
+ return defer.succeed(42)
+ else:
+ return defer.fail(mockFailure)
+
+class MockSuccessTaskWithTimeout(TaskWithTimeout):
+ def run(self):
+ return defer.succeed(42)
+
+class MockFailTaskThatTimesOut(TaskWithTimeout):
+ def run(self):
+ return defer.Deferred()
+
+class MockTimeoutOnceTask(TaskWithTimeout):
+ def run(self):
+ if self.failures >= 1:
+ return defer.succeed(42)
+ else:
+ return defer.Deferred()
+
+class MockFailTaskWithTimeout(TaskWithTimeout):
+ def run(self):
+ return defer.fail(mockFailure)
+
+
+class MockNetTest(object):
+ def __init__(self):
+ self.successes = []
+
+ def succeeded(self, measurement):
+ self.successes.append(measurement)
+
+class MockMeasurement(TaskWithTimeout):
+ def __init__(self, net_test):
+ TaskWithTimeout.__init__(self)
+ self.netTest = net_test
+
+ def succeeded(self, result):
+ return self.netTest.succeeded(42)
+
+class MockSuccessMeasurement(MockMeasurement):
+ def run(self):
+ return defer.succeed(42)
+
+class MockFailMeasurement(MockMeasurement):
+ def run(self):
+ return defer.fail(mockFailure)
+
+class MockFailOnceMeasurement(MockMeasurement):
+ def run(self):
+ if self.failures >= 1:
+ return defer.succeed(42)
+ else:
+ return defer.fail(mockFailure)
+
+class MockDirector(object):
+ def __init__(self):
+ self.successes = []
+
+ def measurementFailed(self, failure, measurement):
+ pass
+
+ def measurementSucceeded(self, measurement):
+ self.successes.append(measurement)
+
+## from test_reporter.py
+class MockOReporter(object):
+ def __init__(self):
+ self.created = defer.Deferred()
+
+ def writeReportEntry(self, entry):
+ return defer.succeed(42)
+
+ def finish(self):
+ pass
+
+ def createReport(self):
+ from ooni.utils import log
+ log.debug("Creating report with %s" % self)
+ self.created.callback(self)
+
+class MockOReporterThatFailsWrite(MockOReporter):
+ def writeReportEntry(self, entry):
+ raise MockFailure
+
+class MockOReporterThatFailsOpen(MockOReporter):
+ def createReport(self):
+ self.created.errback(failure.Failure(MockFailure()))
+
+class MockOReporterThatFailsWriteOnce(MockOReporter):
+ def __init__(self):
+ self.failure = 0
+ MockOReporter.__init__(self)
+
+ def writeReportEntry(self, entry):
+ if self.failure >= 1:
+ return defer.succeed(42)
+ else:
+ self.failure += 1
+ raise MockFailure
+
+class MockTaskManager(TaskManager):
+ def __init__(self):
+ self.successes = []
+ TaskManager.__init__(self)
+
+ def failed(self, failure, task):
+ pass
+
+ def succeeded(self, result, task):
+ self.successes.append((result, task))
+
diff --git a/ooni/tests/test-class-design.py b/ooni/tests/test-class-design.py
new file mode 100644
index 0000000..bb80cd3
--- /dev/null
+++ b/ooni/tests/test-class-design.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+#
+# testing classes to test multiple inheritance.
+# these are not meant to be run by trial, though they could be made to be so.
+# i didn't know where to put them. --isis
+
+import abc
+from pprint import pprint
+from inspect import classify_class_attrs
+
+class PluginBase(object):
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractproperty
+ def name(self):
+ return 'you should not see this'
+
+ @name.setter
+ def name(self, value):
+ return 'you should not set this'
+
+ @name.deleter
+ def name(self):
+ return 'you should not del this'
+
+ @abc.abstractmethod
+ def inputParser(self, line):
+ """Do something to parse something."""
+ return
+
+class Foo(object):
+ woo = "this class has some shit in it"
+ def bar(self):
+ print "i'm a Foo.bar()!"
+ print woo
+
+class KwargTest(Foo):
+ _name = "isis"
+
+ #def __new__(cls, *a, **kw):
+ # return super(KwargTest, cls).__new__(cls, *a, **kw)
+
+ @property
+ def name(self):
+ return self._name
+
+ @name.setter
+ def name(self, value):
+ self._name = value
+
+ def __init__(self, *a, **kw):
+ super(KwargTest, self).__init__()
+
+ ## this causes the instantion args to override the class attrs
+ for key, value in kw.items():
+ setattr(self.__class__, key, value)
+
+ print "%s.__init__(): self.__dict__ = %s" \
+ % (type(self), pprint(type(self).__dict__))
+
+ for attr in classify_class_attrs(self):
+ print attr
+
+ @classmethod
+ def sayname(cls):
+ print cls.name
+
+class KwargTestChild(KwargTest):
+ name = "arturo"
+ def __init__(self):
+ super(KwargTestChild, self).__init__()
+ print self.name
+
+class KwargTestChildOther(KwargTest):
+ def __init__(self, name="robot", does="lasers"):
+ super(KwargTestChildOther, self).__init__()
+ print self.name
+
+
+if __name__ == "__main__":
+ print "class KwargTest attr name: %s" % KwargTest.name
+ kwargtest = KwargTest()
+ print "KwargTest instantiated wo args"
+ print "kwargtest.name: %s" % kwargtest.name
+ print "kwargtest.sayname(): %s" % kwargtest.sayname()
+ kwargtest2 = KwargTest(name="lovecruft", does="hacking")
+ print "KwargTest instantiated with name args"
+ print "kwargtest.name: %s" % kwargtest2.name
+ print "kwargtest.sayname(): %s" % kwargtest2.sayname()
+
+ print "class KwargTestChild attr name: %s" % KwargTestChild.name
+ kwargtestchild = KwargTestChild()
+ print "KwargTestChild instantiated wo args"
+ print "kwargtestchild.name: %s" % kwargtestchild.name
+ print "kwargtestchild.sayname(): %s" % kwargtestchild.sayname()
+
+ print "class KwargTestChildOther attr name: %s" % KwargTestChildOther.name
+ kwargtestchildother = KwargTestChildOther()
+ print "KwargTestChildOther instantiated wo args"
+ print "kwargtestchildother.name: %s" % kwargtestchildother.name
+ print "kwargtestchildother.sayname(): %s" % kwargtestchildother.sayname()
diff --git a/ooni/tests/test_director.py b/ooni/tests/test_director.py
new file mode 100644
index 0000000..7920fcb
--- /dev/null
+++ b/ooni/tests/test_director.py
@@ -0,0 +1,58 @@
+from twisted.internet import defer, base
+from twisted.trial import unittest
+
+from ooni.director import Director
+from ooni.nettest import NetTestLoader
+from ooni.tests.mocks import MockReporter
+base.DelayedCall.debug = True
+
+net_test_string = """
+from twisted.python import usage
+from ooni.nettest import NetTestCase
+
+class UsageOptions(usage.Options):
+ optParameters = [['spam', 's', None, 'ham']]
+
+class DummyTestCase(NetTestCase):
+ inputFile = ['file', 'f', None, 'The input File']
+
+ usageOptions = UsageOptions
+
+ def test_a(self):
+ self.report['bar'] = 'bar'
+
+ def test_b(self):
+ self.report['foo'] = 'foo'
+"""
+
+
+dummyArgs = ('--spam', 1, '--file', 'dummyInputFile.txt')
+
+class TestDirector(unittest.TestCase):
+ timeout = 1
+ def setUp(self):
+ with open('dummyInputFile.txt', 'w') as f:
+ for i in range(10):
+ f.write("%s\n" % i)
+
+ self.reporters = [MockReporter()]
+ self.director = Director()
+
+ def tearDown(self):
+ pass
+
+ def test_start_net_test(self):
+ ntl = NetTestLoader(dummyArgs, test_string=net_test_string)
+
+ ntl.checkOptions()
+ d = self.director.startNetTest('', ntl, self.reporters)
+
+ @d.addCallback
+ def done(result):
+ self.assertEqual(self.director.successfulMeasurements, 20)
+
+ return d
+
+ def test_stop_net_test(self):
+ pass
+
diff --git a/ooni/tests/test_dns.py b/ooni/tests/test_dns.py
new file mode 100644
index 0000000..e9bb524
--- /dev/null
+++ b/ooni/tests/test_dns.py
@@ -0,0 +1,24 @@
+#
+# This unittest is to verify that our usage of the twisted DNS resolver does
+# not break with new versions of twisted.
+
+import pdb
+from twisted.trial import unittest
+
+from twisted.internet import reactor
+
+from twisted.names import dns
+from twisted.names.client import Resolver
+
+class DNSTest(unittest.TestCase):
+ def test_a_lookup_ooni_query(self):
+ def done_query(message, *arg):
+ answer = message.answers[0]
+ self.assertEqual(answer.type, 1)
+
+ dns_query = [dns.Query('ooni.nu', type=dns.A)]
+ resolver = Resolver(servers=[('8.8.8.8', 53)])
+ d = resolver.queryUDP(dns_query)
+ d.addCallback(done_query)
+ return d
+
diff --git a/ooni/tests/test_managers.py b/ooni/tests/test_managers.py
new file mode 100644
index 0000000..e2af7b3
--- /dev/null
+++ b/ooni/tests/test_managers.py
@@ -0,0 +1,215 @@
+from twisted.trial import unittest
+from twisted.python import failure
+from twisted.internet import defer, task
+
+from ooni.tasks import BaseTask, TaskWithTimeout, TaskTimedOut
+from ooni.managers import TaskManager, MeasurementManager
+
+from ooni.tests.mocks import MockSuccessTask, MockFailTask, MockFailOnceTask, MockFailure
+from ooni.tests.mocks import MockSuccessTaskWithTimeout, MockFailTaskThatTimesOut
+from ooni.tests.mocks import MockTimeoutOnceTask, MockFailTaskWithTimeout
+from ooni.tests.mocks import MockTaskManager, mockFailure, MockDirector
+from ooni.tests.mocks import MockNetTest, MockMeasurement, MockSuccessMeasurement
+from ooni.tests.mocks import MockFailMeasurement, MockFailOnceMeasurement
+
+class TestTaskManager(unittest.TestCase):
+ timeout = 1
+ def setUp(self):
+ self.measurementManager = MockTaskManager()
+ self.measurementManager.concurrency = 20
+ self.measurementManager.retries = 2
+
+ self.measurementManager.start()
+
+ self.clock = task.Clock()
+
+ def schedule_successful_tasks(self, task_type, number=1):
+ all_done = []
+ for x in range(number):
+ mock_task = task_type()
+ all_done.append(mock_task.done)
+ self.measurementManager.schedule(mock_task)
+
+ d = defer.DeferredList(all_done)
+ @d.addCallback
+ def done(res):
+ for task_result, task_instance in self.measurementManager.successes:
+ self.assertEqual(task_result, 42)
+ self.assertIsInstance(task_instance, task_type)
+
+ return d
+
+ def schedule_failing_tasks(self, task_type, number=1):
+ all_done = []
+ for x in range(number):
+ mock_task = task_type()
+ all_done.append(mock_task.done)
+ self.measurementManager.schedule(mock_task)
+
+ d = defer.DeferredList(all_done)
+ @d.addCallback
+ def done(res):
+ # 10*2 because 2 is the number of retries
+ self.assertEqual(len(self.measurementManager.failures), number*3)
+ for task_result, task_instance in self.measurementManager.failures:
+ self.assertEqual(task_result, mockFailure)
+ self.assertIsInstance(task_instance, task_type)
+
+ return d
+
+ def test_schedule_failing_with_mock_failure_task(self):
+ mock_task = MockFailTask()
+ self.measurementManager.schedule(mock_task)
+ self.assertFailure(mock_task.done, MockFailure)
+ return mock_task.done
+
+ def test_schedule_successful_one_task(self):
+ return self.schedule_successful_tasks(MockSuccessTask)
+
+ def test_schedule_successful_one_task_with_timeout(self):
+ return self.schedule_successful_tasks(MockSuccessTaskWithTimeout)
+
+ def test_schedule_failing_tasks_that_timesout(self):
+ self.measurementManager.retries = 0
+
+ task_type = MockFailTaskThatTimesOut
+ task_timeout = 5
+
+ mock_task = task_type()
+ mock_task.timeout = task_timeout
+ mock_task.clock = self.clock
+
+ self.measurementManager.schedule(mock_task)
+
+ self.clock.advance(task_timeout)
+
+ @mock_task.done.addBoth
+ def done(res):
+ self.assertEqual(len(self.measurementManager.failures), 1)
+ for task_result, task_instance in self.measurementManager.failures:
+ self.assertIsInstance(task_instance, task_type)
+
+ return mock_task.done
+
+ def test_schedule_time_out_once(self):
+ task_type = MockTimeoutOnceTask
+ task_timeout = 5
+
+ mock_task = task_type()
+ mock_task.timeout = task_timeout
+ mock_task.clock = self.clock
+
+ self.measurementManager.schedule(mock_task)
+
+ self.clock.advance(task_timeout)
+
+ @mock_task.done.addBoth
+ def done(res):
+ self.assertEqual(len(self.measurementManager.failures), 1)
+ for task_result, task_instance in self.measurementManager.failures:
+ self.assertIsInstance(task_instance, task_type)
+
+ for task_result, task_instance in self.measurementManager.successes:
+ self.assertEqual(task_result, 42)
+ self.assertIsInstance(task_instance, task_type)
+
+ return mock_task.done
+
+
+ def test_schedule_failing_one_task(self):
+ return self.schedule_failing_tasks(MockFailTask)
+
+ def test_schedule_failing_one_task_with_timeout(self):
+ return self.schedule_failing_tasks(MockFailTaskWithTimeout)
+
+ def test_schedule_successful_ten_tasks(self):
+ return self.schedule_successful_tasks(MockSuccessTask, number=10)
+
+ def test_schedule_failing_ten_tasks(self):
+ return self.schedule_failing_tasks(MockFailTask, number=10)
+
+ def test_schedule_successful_27_tasks(self):
+ return self.schedule_successful_tasks(MockSuccessTask, number=27)
+
+ def test_schedule_failing_27_tasks(self):
+ return self.schedule_failing_tasks(MockFailTask, number=27)
+
+ def test_task_retry_and_succeed(self):
+ mock_task = MockFailOnceTask()
+ self.measurementManager.schedule(mock_task)
+
+ @mock_task.done.addCallback
+ def done(res):
+ self.assertEqual(len(self.measurementManager.failures), 1)
+
+ self.assertEqual(self.measurementManager.failures,
+ [(mockFailure, mock_task)])
+ self.assertEqual(self.measurementManager.successes,
+ [(42, mock_task)])
+
+ return mock_task.done
+
+ def dd_test_task_retry_and_succeed_56_tasks(self):
+ """
+ XXX this test fails in a non-deterministic manner.
+ """
+ all_done = []
+ number = 56
+ for x in range(number):
+ mock_task = MockFailOnceTask()
+ all_done.append(mock_task.done)
+ self.measurementManager.schedule(mock_task)
+
+ d = defer.DeferredList(all_done)
+
+ @d.addCallback
+ def done(res):
+ self.assertEqual(len(self.measurementManager.failures), number)
+
+ for task_result, task_instance in self.measurementManager.successes:
+ self.assertEqual(task_result, 42)
+ self.assertIsInstance(task_instance, MockFailOnceTask)
+
+ return d
+
+class TestMeasurementManager(unittest.TestCase):
+ def setUp(self):
+ mock_director = MockDirector()
+
+ self.measurementManager = MeasurementManager()
+ self.measurementManager.director = mock_director
+
+ self.measurementManager.concurrency = 10
+ self.measurementManager.retries = 2
+
+ self.measurementManager.start()
+
+ self.mockNetTest = MockNetTest()
+
+ def test_schedule_and_net_test_notified(self, number=1):
+ # XXX we should probably be inheriting from the base test class
+ mock_task = MockSuccessMeasurement(self.mockNetTest)
+ self.measurementManager.schedule(mock_task)
+
+ @mock_task.done.addCallback
+ def done(res):
+ self.assertEqual(self.mockNetTest.successes,
+ [42])
+
+ self.assertEqual(len(self.mockNetTest.successes), 1)
+ return mock_task.done
+
+ def test_schedule_failing_one_measurement(self):
+ mock_task = MockFailMeasurement(self.mockNetTest)
+ self.measurementManager.schedule(mock_task)
+
+ @mock_task.done.addErrback
+ def done(failure):
+ self.assertEqual(len(self.measurementManager.failures), 3)
+
+ self.assertEqual(failure, mockFailure)
+ self.assertEqual(len(self.mockNetTest.successes), 0)
+
+ return mock_task.done
+
+
diff --git a/ooni/tests/test_mutate.py b/ooni/tests/test_mutate.py
new file mode 100644
index 0000000..7e30586
--- /dev/null
+++ b/ooni/tests/test_mutate.py
@@ -0,0 +1,15 @@
+import unittest
+from ooni.kit import daphn3
+
+class TestDaphn3(unittest.TestCase):
+ def test_mutate_string(self):
+ original_string = '\x00\x00\x00'
+ mutated = daphn3.daphn3MutateString(original_string, 1)
+ self.assertEqual(mutated, '\x00\x01\x00')
+ def test_mutate_daphn3(self):
+ original_dict = [{'client': '\x00\x00\x00'},
+ {'server': '\x00\x00\x00'}]
+ mutated_dict = daphn3.daphn3Mutate(original_dict, 1, 1)
+ self.assertEqual(mutated_dict, [{'client': '\x00\x00\x00'},
+ {'server': '\x00\x01\x00'}])
+
diff --git a/ooni/tests/test_nettest.py b/ooni/tests/test_nettest.py
new file mode 100644
index 0000000..4d72a84
--- /dev/null
+++ b/ooni/tests/test_nettest.py
@@ -0,0 +1,268 @@
+import os
+from StringIO import StringIO
+from tempfile import TemporaryFile, mkstemp
+
+from twisted.trial import unittest
+from twisted.internet import defer, reactor
+from twisted.python.usage import UsageError
+
+from ooni.nettest import NetTest, InvalidOption, MissingRequiredOption
+from ooni.nettest import NetTestLoader, FailureToLoadNetTest, loadNetTestString, loadNetTestFile
+from ooni.tasks import BaseTask
+from ooni.utils import NotRootError
+
+from ooni.director import Director
+
+from ooni.managers import TaskManager
+
+from ooni.tests.mocks import MockMeasurement, MockMeasurementFailOnce
+from ooni.tests.mocks import MockNetTest, MockDirector, MockReporter
+from ooni.tests.mocks import MockMeasurementManager
+defer.setDebugging(True)
+
+net_test_string = """
+from twisted.python import usage
+from ooni.nettest import NetTestCase
+
+class UsageOptions(usage.Options):
+ optParameters = [['spam', 's', None, 'ham']]
+
+class DummyTestCase(NetTestCase):
+
+ usageOptions = UsageOptions
+
+ def test_a(self):
+ self.report['bar'] = 'bar'
+
+ def test_b(self):
+ self.report['foo'] = 'foo'
+"""
+
+net_test_root_required = net_test_string+"""
+ requiresRoot = True
+"""
+
+net_test_string_with_file = """
+from twisted.python import usage
+from ooni.nettest import NetTestCase
+
+class UsageOptions(usage.Options):
+ optParameters = [['spam', 's', None, 'ham']]
+
+class DummyTestCase(NetTestCase):
+ inputFile = ['file', 'f', None, 'The input File']
+
+ usageOptions = UsageOptions
+
+ def test_a(self):
+ self.report['bar'] = 'bar'
+
+ def test_b(self):
+ self.report['foo'] = 'foo'
+"""
+
+net_test_string_with_required_option = """
+from twisted.python import usage
+from ooni.nettest import NetTestCase
+
+class UsageOptions(usage.Options):
+ optParameters = [['spam', 's', None, 'ham'],
+ ['foo', 'o', None, 'moo'],
+ ['bar', 'o', None, 'baz'],
+ ]
+
+class DummyTestCase(NetTestCase):
+ inputFile = ['file', 'f', None, 'The input File']
+
+ usageOptions = UsageOptions
+
+ def test_a(self):
+ self.report['bar'] = 'bar'
+
+ def test_b(self):
+ self.report['foo'] = 'foo'
+
+ requiredOptions = ['foo', 'bar']
+"""
+
+dummyInputs = range(1)
+dummyArgs = ('--spam', 'notham')
+dummyOptions = {'spam':'notham'}
+dummyInvalidArgs = ('--cram', 'jam')
+dummyInvalidOptions= {'cram':'jam'}
+dummyArgsWithRequiredOptions = ('--foo', 'moo', '--bar', 'baz')
+dummyRequiredOptions = {'foo':'moo', 'bar':'baz'}
+dummyArgsWithFile = ('--spam', 'notham', '--file', 'dummyInputFile.txt')
+
+class TestNetTest(unittest.TestCase):
+ timeout = 1
+ def setUp(self):
+ with open('dummyInputFile.txt', 'w') as f:
+ for i in range(10):
+ f.write("%s\n" % i)
+
+ def assertCallable(self, thing):
+ self.assertIn('__call__', dir(thing))
+
+ def verifyMethods(self, testCases):
+ uniq_test_methods = set()
+ for test_class, test_methods in testCases:
+ instance = test_class()
+ for test_method in test_methods:
+ c = getattr(instance, test_method)
+ self.assertCallable(c)
+ uniq_test_methods.add(test_method)
+ self.assertEqual(set(['test_a', 'test_b']), uniq_test_methods)
+
+ def test_load_net_test_from_file(self):
+ """
+ Given a file verify that the net test cases are properly
+ generated.
+ """
+ __, net_test_file = mkstemp()
+ with open(net_test_file, 'w') as f:
+ f.write(net_test_string)
+ f.close()
+
+ ntl = NetTestLoader(dummyArgs)
+ ntl.setupTestCases(loadNetTestFile(net_test_file))
+
+ self.verifyMethods(ntl.testCases)
+ os.unlink(net_test_file)
+
+ def test_load_net_test_from_str(self):
+ """
+ Given a file like object verify that the net test cases are properly
+ generated.
+ """
+ ntl = NetTestLoader(dummyArgs)
+ ntl.setupTestCases(loadNetTestString(net_test_string))
+
+ self.verifyMethods(ntl.testCases)
+
+ def test_load_net_test_from_StringIO(self):
+ """
+ Given a file like object verify that the net test cases are properly
+ generated.
+ """
+ ntl = NetTestLoader(dummyArgs)
+ ntl.setupTestCases(loadNetTestString(net_test_string))
+
+ self.verifyMethods(ntl.testCases)
+
+ def test_load_with_option(self):
+ ntl = NetTestLoader(dummyArgs)
+ ntl.setupTestCases(loadNetTestString(net_test_string))
+
+ self.assertIsInstance(ntl, NetTestLoader)
+ for test_klass, test_meth in ntl.testCases:
+ for option in dummyOptions.keys():
+ self.assertIn(option, test_klass.usageOptions())
+
+ def test_load_with_invalid_option(self):
+ try:
+ ntl = NetTestLoader(dummyInvalidArgs)
+ ntl.setupTestCases(loadNetTestString(net_test_string))
+
+ ntl.checkOptions()
+ raise Exception
+ except UsageError:
+ pass
+
+ def test_load_with_required_option(self):
+ ntl = NetTestLoader(dummyArgsWithRequiredOptions)
+ ntl.setupTestCases(loadNetTestString(net_test_string_with_required_option))
+
+ self.assertIsInstance(ntl, NetTestLoader)
+
+ def test_load_with_missing_required_option(self):
+ try:
+ ntl = NetTestLoader(dummyArgs)
+ ntl.setupTestCases(loadNetTestString(net_test_string_with_required_option))
+
+ except MissingRequiredOption:
+ pass
+
+ def test_net_test_inputs(self):
+ ntl = NetTestLoader(dummyArgsWithFile)
+ ntl.setupTestCases(loadNetTestString(net_test_string_with_file))
+
+ ntl.checkOptions()
+
+ # XXX: if you use the same test_class twice you will have consumed all
+ # of its inputs!
+ tested = set([])
+ for test_class, test_method in ntl.testCases:
+ if test_class not in tested:
+ tested.update([test_class])
+ self.assertEqual(len(list(test_class.inputs)), 10)
+
+ def test_setup_local_options_in_test_cases(self):
+ ntl = NetTestLoader(dummyArgs)
+ ntl.setupTestCases(loadNetTestString(net_test_string))
+
+ ntl.checkOptions()
+
+ for test_class, test_method in ntl.testCases:
+ self.assertEqual(test_class.localOptions, dummyOptions)
+
+ def test_generate_measurements_size(self):
+ ntl = NetTestLoader(dummyArgsWithFile)
+ ntl.setupTestCases(loadNetTestString(net_test_string_with_file))
+
+ ntl.checkOptions()
+ net_test = NetTest(ntl, None)
+
+ measurements = list(net_test.generateMeasurements())
+ self.assertEqual(len(measurements), 20)
+
+ def test_net_test_completed_callback(self):
+ ntl = NetTestLoader(dummyArgsWithFile)
+ ntl.setupTestCases(loadNetTestString(net_test_string_with_file))
+
+ ntl.checkOptions()
+ director = Director()
+
+ d = director.startNetTest('', ntl, [MockReporter()])
+
+ @d.addCallback
+ def complete(result):
+ #XXX: why is the return type (True, None) ?
+ self.assertEqual(result, [(True,None)])
+ self.assertEqual(director.successfulMeasurements, 20)
+
+ return d
+
+ def test_require_root_succeed(self):
+ #XXX: will require root to run
+ ntl = NetTestLoader(dummyArgs)
+ ntl.setupTestCases(loadNetTestString(net_test_root_required))
+
+ for test_class, method in ntl.testCases:
+ self.assertTrue(test_class.requiresRoot)
+
+ #def test_require_root_failed(self):
+ # #XXX: will fail if you run as root
+ # try:
+ # net_test = NetTestLoader(StringIO(net_test_root_required),
+ # dummyArgs)
+ # except NotRootError:
+ # pass
+
+ #def test_create_report_succeed(self):
+ # pass
+
+ #def test_create_report_failed(self):
+ # pass
+
+ #def test_run_all_test(self):
+ # raise NotImplementedError
+
+ #def test_resume_test(self):
+ # pass
+
+ #def test_progress(self):
+ # pass
+
+ #def test_time_out(self):
+ # raise NotImplementedError
diff --git a/ooni/tests/test_otime.py b/ooni/tests/test_otime.py
new file mode 100644
index 0000000..80979f2
--- /dev/null
+++ b/ooni/tests/test_otime.py
@@ -0,0 +1,15 @@
+import unittest
+from datetime import datetime
+from ooni import otime
+
+test_date = datetime(2002, 6, 26, 22, 45, 49)
+
+class TestOtime(unittest.TestCase):
+ def test_timestamp(self):
+ self.assertEqual(otime.timestamp(test_date), "2002-06-26T224549Z")
+
+ def test_fromTimestamp(self):
+ time_stamp = otime.timestamp(test_date)
+ self.assertEqual(test_date, otime.fromTimestamp(time_stamp))
+
+
diff --git a/ooni/tests/test_reporter.py b/ooni/tests/test_reporter.py
new file mode 100644
index 0000000..d7ee907
--- /dev/null
+++ b/ooni/tests/test_reporter.py
@@ -0,0 +1,238 @@
+from twisted.internet import defer
+from twisted.trial import unittest
+
+from ooni.reporter import Report, YAMLReporter, OONIBReporter, safe_dump
+from ooni.managers import ReportEntryManager, TaskManager
+from ooni.nettest import NetTest, NetTestState
+from ooni.errors import ReportNotCreated, ReportAlreadyClosed
+
+from ooni.tasks import TaskWithTimeout
+from ooni.tests.mocks import MockOReporter, MockTaskManager
+from ooni.tests.mocks import MockMeasurement, MockNetTest
+from ooni.tests.mocks import MockOReporterThatFailsWrite
+from ooni.tests.mocks import MockOReporterThatFailsWriteOnce
+from ooni.tests.mocks import MockOReporterThatFailsOpen
+
+from twisted.python import failure
+import yaml
+
+class TestReport(unittest.TestCase):
+ def setUp(self):
+ pass
+ def tearDown(self):
+ pass
+ def test_create_report_with_no_reporter(self):
+ report = Report([],ReportEntryManager())
+ self.assertIsInstance(report, Report)
+
+ def test_create_report_with_single_reporter(self):
+ report = Report([MockOReporter()], ReportEntryManager())
+ self.assertIsInstance(report, Report)
+
+ def test_create_report_with_multiple_reporters(self):
+ report = Report([MockOReporter() for x in xrange(3)],
+ ReportEntryManager())
+ self.assertIsInstance(report, Report)
+
+ def test_report_open_with_single_reporter(self):
+ report = Report([MockOReporter()],ReportEntryManager())
+ d = report.open()
+ return d
+
+ def test_report_open_with_multiple_reporter(self):
+ report = Report([MockOReporter() for x in xrange(3)],
+ ReportEntryManager())
+ d = report.open()
+ return d
+
+ def test_fail_to_open_report_with_single_reporter(self):
+ report = Report([MockOReporterThatFailsOpen()],
+ ReportEntryManager())
+ d = report.open()
+ def f(x):
+ self.assertEquals(len(report.reporters), 0)
+ d.addCallback(f)
+ return d
+
+ def test_fail_to_open_single_report_with_multiple_reporter(self):
+ report = Report([MockOReporterThatFailsOpen(), MockOReporter(),
+ MockOReporter()], ReportEntryManager())
+ d = report.open()
+ def f(x):
+ self.assertEquals(len(report.reporters),2)
+ d.addCallback(f)
+ return d
+
+ def test_fail_to_open_all_reports_with_multiple_reporter(self):
+ report = Report([MockOReporterThatFailsOpen() for x in xrange(3)],
+ ReportEntryManager())
+ d = report.open()
+ def f(x):
+ self.assertEquals(len(report.reporters),0)
+ d.addCallback(f)
+ return d
+
+ def test_write_report_with_single_reporter_and_succeed(self):
+ #XXX: verify that the MockOReporter writeReportEntry succeeds
+ report = Report([MockOReporter()], ReportEntryManager())
+ report.open()
+ d = report.write(MockMeasurement(MockNetTest()))
+ return d
+
+ def test_write_report_with_single_reporter_and_fail_after_timeout(self):
+ report = Report([MockOReporterThatFailsWrite()], ReportEntryManager())
+ report.open()
+ d = report.write(MockMeasurement(MockNetTest()))
+ def f(err):
+ self.assertEquals(len(report.reporters),0)
+ d.addBoth(f)
+ return d
+
+ def test_write_report_with_single_reporter_and_succeed_after_timeout(self):
+ report = Report([MockOReporterThatFailsWriteOnce()], ReportEntryManager())
+ report.open()
+ d = report.write(MockMeasurement(MockNetTest()))
+ return d
+
+ def test_write_report_with_multiple_reporter_and_succeed(self):
+ report = Report([MockOReporter() for x in xrange(3)], ReportEntryManager())
+ report.open()
+ d = report.write(MockMeasurement(MockNetTest()))
+ return d
+
+ def test_write_report_with_multiple_reporter_and_fail_a_single_reporter(self):
+ report = Report([MockOReporter(), MockOReporter(), MockOReporterThatFailsWrite()], ReportEntryManager())
+ d = report.open()
+
+ self.assertEquals(len(report.reporters),3)
+ d = report.write(MockMeasurement(MockNetTest()))
+
+ def f(x):
+ # one of the reporters should have been removed
+ self.assertEquals(len(report.reporters), 2)
+ d.addBoth(f)
+ return d
+
+ def test_write_report_with_multiple_reporter_and_fail_all_reporter(self):
+ report = Report([MockOReporterThatFailsWrite() for x in xrange(3)], ReportEntryManager())
+ report.open()
+ d = report.write(MockMeasurement(MockNetTest()))
+ def f(err):
+ self.assertEquals(len(report.reporters),0)
+ d.addErrback(f)
+ return d
+
+class TestYAMLReporter(unittest.TestCase):
+ def setUp(self):
+ self.testDetails = {'software_name': 'ooniprobe', 'options':
+ {'pcapfile': None, 'help': 0, 'subargs': ['-f', 'alexa_10'], 'resume':
+ 0, 'parallelism': '10', 'no-default-reporter': 0, 'testdeck': None,
+ 'test': 'nettests/blocking/http_requests.py', 'logfile': None,
+ 'collector': None, 'reportfile': None}, 'test_version': '0.2.3',
+ 'software_version': '0.0.10', 'test_name': 'http_requests_test',
+ 'start_time': 1362054343.0, 'probe_asn': 'AS0', 'probe_ip':
+ '127.0.0.1', 'probe_cc': 'US'}
+
+ def tearDown(self):
+ pass
+ def test_create_yaml_reporter(self):
+ self.assertIsInstance(YAMLReporter(self.testDetails),
+ YAMLReporter)
+
+ def test_open_yaml_report_and_succeed(self):
+ r = YAMLReporter(self.testDetails)
+ r.createReport()
+ # verify that testDetails was written to report properly
+ def f(r):
+ r._stream.seek(0)
+ details, = yaml.safe_load_all(r._stream)
+ self.assertEqual(details, self.testDetails)
+ r.created.addCallback(f)
+ return r.created
+
+ #def test_open_yaml_report_and_fail(self):
+ # #XXX: YAMLReporter does not handle failures of this type
+ # pass
+
+ def test_write_yaml_report_entry(self):
+ r = YAMLReporter(self.testDetails)
+ r.createReport()
+
+ report_entry = {'foo':'bar', 'bin':'baz'}
+ r.writeReportEntry(report_entry)
+
+ # verify that details and entry were written to report
+ def f(r):
+ r._stream.seek(0)
+ report = yaml.safe_load_all(r._stream)
+ details, entry = report
+ self.assertEqual(details, self.testDetails)
+ self.assertEqual(entry, report_entry)
+ r.created.addCallback(f)
+ return r.created
+
+ def test_write_multiple_yaml_report_entry(self):
+ r = YAMLReporter(self.testDetails)
+ r.createReport()
+ def reportEntry():
+ for x in xrange(10):
+ yield {'foo':'bar', 'bin':'baz', 'item':x}
+ for entry in reportEntry():
+ r.writeReportEntry(entry)
+ # verify that details and multiple entries were written to report
+ def f(r):
+ r._stream.seek(0)
+ report = yaml.safe_load_all(r._stream)
+ details = report.next()
+ self.assertEqual(details, self.testDetails)
+ self.assertEqual([r for r in report], [r for r in reportEntry()])
+ r.created.addCallback(f)
+ return r.created
+
+ def test_close_yaml_report(self):
+ r = YAMLReporter(self.testDetails)
+ r.createReport()
+ r.finish()
+ self.assertTrue(r._stream.closed)
+
+ def test_write_yaml_report_after_close(self):
+ r = YAMLReporter(self.testDetails)
+ r.createReport()
+ r.finish()
+ def f(r):
+ r.writeReportEntry("foo")
+ r.created.addCallback(f)
+ self.assertFailure(r.created, ReportAlreadyClosed)
+
+ def test_write_yaml_report_before_open(self):
+ r = YAMLReporter(self.testDetails)
+ def f(r):
+ r.writeReportEntry("foo")
+ r.created.addCallback(f)
+ self.assertFailure(r.created, ReportNotCreated)
+
+#class TestOONIBReporter(unittest.TestCase):
+# def setUp(self):
+# pass
+# def tearDown(self):
+# pass
+# def test_create_oonib_reporter(self):
+# raise NotImplementedError
+# def test_open_oonib_report_and_succeed(self):
+# raise NotImplementedError
+# def test_open_oonib_report_and_fail(self):
+# raise NotImplementedError
+# def test_write_oonib_report_entry_and_succeed(self):
+# raise NotImplementedError
+# def test_write_oonib_report_entry_and_succeed_after_timeout(self):
+# raise NotImplementedError
+# def test_write_oonib_report_entry_and_fail_after_timeout(self):
+# raise NotImplementedError
+# def test_write_oonib_report_after_close(self):
+# raise NotImplementedError
+# def test_write_oonib_report_before_open(self):
+# raise NotImplementedError
+# def test_close_oonib_report_and_succeed(self):
+# raise NotImplementedError
+# def test_close_oonib_report_and_fail(self):
+# raise NotImplementedError
diff --git a/ooni/tests/test_safe_represent.py b/ooni/tests/test_safe_represent.py
new file mode 100644
index 0000000..82a5196
--- /dev/null
+++ b/ooni/tests/test_safe_represent.py
@@ -0,0 +1,14 @@
+import yaml
+
+from twisted.trial import unittest
+
+from ooni.reporter import OSafeDumper
+
+from scapy.all import IP, UDP
+
+class TestScapyRepresent(unittest.TestCase):
+ def test_represent_scapy(self):
+ data = IP()/UDP()
+ yaml.dump_all([data], Dumper=OSafeDumper)
+
+
diff --git a/ooni/tests/test_trueheaders.py b/ooni/tests/test_trueheaders.py
new file mode 100644
index 0000000..9ac0a27
--- /dev/null
+++ b/ooni/tests/test_trueheaders.py
@@ -0,0 +1,41 @@
+from twisted.trial import unittest
+
+from ooni.utils.txagentwithsocks import TrueHeaders
+
+dummy_headers_dict = {
+ 'Header1': ['Value1', 'Value2'],
+ 'Header2': ['ValueA', 'ValueB']
+}
+
+dummy_headers_dict2 = {
+ 'Header1': ['Value1', 'Value2'],
+ 'Header2': ['ValueA', 'ValueB'],
+ 'Header3': ['ValueA', 'ValueB'],
+}
+
+dummy_headers_dict3 = {
+ 'Header1': ['Value1', 'Value2'],
+ 'Header2': ['ValueA', 'ValueB'],
+ 'Header4': ['ValueA', 'ValueB'],
+}
+
+
+class TestTrueHeaders(unittest.TestCase):
+ def test_names_match(self):
+ th = TrueHeaders(dummy_headers_dict)
+ self.assertEqual(th.getDiff(TrueHeaders(dummy_headers_dict)), set())
+
+ def test_names_not_match(self):
+ th = TrueHeaders(dummy_headers_dict)
+ self.assertEqual(th.getDiff(TrueHeaders(dummy_headers_dict2)), set(['Header3']))
+
+ th = TrueHeaders(dummy_headers_dict3)
+ self.assertEqual(th.getDiff(TrueHeaders(dummy_headers_dict2)), set(['Header3', 'Header4']))
+
+ def test_names_match_expect_ignore(self):
+ th = TrueHeaders(dummy_headers_dict)
+ self.assertEqual(th.getDiff(TrueHeaders(dummy_headers_dict2), ignore=['Header3']), set())
+
+
+
+
diff --git a/ooni/tests/test_utils.py b/ooni/tests/test_utils.py
new file mode 100644
index 0000000..cc648e0
--- /dev/null
+++ b/ooni/tests/test_utils.py
@@ -0,0 +1,20 @@
+import unittest
+from ooni.utils import pushFilenameStack
+
+class TestUtils(unittest.TestCase):
+ def test_pushFilenameStack(self):
+ f = open("dummyfile", "w+")
+ f.write("0\n")
+ f.close()
+ for i in xrange(1, 5):
+ f = open("dummyfile.%s" % i, "w+")
+ f.write("%s\n" % i)
+ f.close()
+
+ pushFilenameStack("dummyfile")
+ for i in xrange(1, 5):
+ f = open("dummyfile.%s" % i)
+ c = f.readlines()[0].strip()
+ self.assertEqual(str(i-1), str(c))
+ f.close()
+
diff --git a/ooni/utils/log.py b/ooni/utils/log.py
index 0740c10..141116e 100644
--- a/ooni/utils/log.py
+++ b/ooni/utils/log.py
@@ -45,14 +45,16 @@ def stop():
print "Stopping OONI"
def msg(msg, *arg, **kw):
- print "%s" % msg
+ if config.logging:
+ print "%s" % msg
def debug(msg, *arg, **kw):
- if config.advanced.debug:
+ if config.advanced.debug and config.logging:
print "[D] %s" % msg
def err(msg, *arg, **kw):
- print "[!] %s" % msg
+ if config.logging:
+ print "[!] %s" % msg
def exception(error):
"""
diff --git a/ooniprobe.conf.sample b/ooniprobe.conf.sample
index 51c60f5..8a6b825 100644
--- a/ooniprobe.conf.sample
+++ b/ooniprobe.conf.sample
@@ -30,6 +30,8 @@ advanced:
# If you do not specify start_tor, you will have to have Tor running and
# explicitly set the control port and SOCKS port
start_tor: true
+ # On which port the oonid API should be listening on
+ oonid_api_port: 50666
tor:
#socks_port: 9050
#control_port: 9051
diff --git a/tests/__init__.py b/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/mocks.py b/tests/mocks.py
deleted file mode 100644
index fed683e..0000000
--- a/tests/mocks.py
+++ /dev/null
@@ -1,168 +0,0 @@
-from ooni.tasks import BaseTask, TaskWithTimeout
-from twisted.python import failure
-from ooni.nettest import NetTest
-from ooni.managers import TaskManager
-from twisted.internet import defer
-
-class MockMeasurementFailOnce(BaseTask):
- def run(self):
- f = open('dummyTaskFailOnce.txt', 'w')
- f.write('fail')
- f.close()
- if self.failure >= 1:
- return defer.succeed(self)
- else:
- return defer.fail(failure.Failure)
-
-class MockMeasurementManager(TaskManager):
- def __init__(self):
- self.successes = []
- TaskManager.__init__(self)
-
- def failed(self, failure, task):
- pass
-
- def succeeded(self, result, task):
- self.successes.append((result, task))
-
-class MockReporter(object):
- def __init__(self):
- self.created = defer.Deferred()
-
- def writeReportEntry(self, entry):
- pass
-
- def createReport(self):
- self.created.callback(self)
-
- def finish(self):
- pass
-
-class MockFailure(Exception):
- pass
-
-## from test_managers
-mockFailure = failure.Failure(MockFailure('mock'))
-
-class MockSuccessTask(BaseTask):
- def run(self):
- return defer.succeed(42)
-
-class MockFailTask(BaseTask):
- def run(self):
- return defer.fail(mockFailure)
-
-class MockFailOnceTask(BaseTask):
- def run(self):
- if self.failures >= 1:
- return defer.succeed(42)
- else:
- return defer.fail(mockFailure)
-
-class MockSuccessTaskWithTimeout(TaskWithTimeout):
- def run(self):
- return defer.succeed(42)
-
-class MockFailTaskThatTimesOut(TaskWithTimeout):
- def run(self):
- return defer.Deferred()
-
-class MockTimeoutOnceTask(TaskWithTimeout):
- def run(self):
- if self.failures >= 1:
- return defer.succeed(42)
- else:
- return defer.Deferred()
-
-class MockFailTaskWithTimeout(TaskWithTimeout):
- def run(self):
- return defer.fail(mockFailure)
-
-
-class MockNetTest(object):
- def __init__(self):
- self.successes = []
-
- def succeeded(self, measurement):
- self.successes.append(measurement)
-
-class MockMeasurement(TaskWithTimeout):
- def __init__(self, net_test):
- TaskWithTimeout.__init__(self)
- self.netTest = net_test
-
- def succeeded(self, result):
- return self.netTest.succeeded(42)
-
-class MockSuccessMeasurement(MockMeasurement):
- def run(self):
- return defer.succeed(42)
-
-class MockFailMeasurement(MockMeasurement):
- def run(self):
- return defer.fail(mockFailure)
-
-class MockFailOnceMeasurement(MockMeasurement):
- def run(self):
- if self.failures >= 1:
- return defer.succeed(42)
- else:
- return defer.fail(mockFailure)
-
-class MockDirector(object):
- def __init__(self):
- self.successes = []
-
- def measurementFailed(self, failure, measurement):
- pass
-
- def measurementSucceeded(self, measurement):
- self.successes.append(measurement)
-
-## from test_reporter.py
-class MockOReporter(object):
- def __init__(self):
- self.created = defer.Deferred()
-
- def writeReportEntry(self, entry):
- return defer.succeed(42)
-
- def finish(self):
- pass
-
- def createReport(self):
- from ooni.utils import log
- log.debug("Creating report with %s" % self)
- self.created.callback(self)
-
-class MockOReporterThatFailsWrite(MockOReporter):
- def writeReportEntry(self, entry):
- raise MockFailure
-
-class MockOReporterThatFailsOpen(MockOReporter):
- def createReport(self):
- self.created.errback(failure.Failure(MockFailure()))
-
-class MockOReporterThatFailsWriteOnce(MockOReporter):
- def __init__(self):
- self.failure = 0
- MockOReporter.__init__(self)
-
- def writeReportEntry(self, entry):
- if self.failure >= 1:
- return defer.succeed(42)
- else:
- self.failure += 1
- raise MockFailure
-
-class MockTaskManager(TaskManager):
- def __init__(self):
- self.successes = []
- TaskManager.__init__(self)
-
- def failed(self, failure, task):
- pass
-
- def succeeded(self, result, task):
- self.successes.append((result, task))
-
diff --git a/tests/test-class-design.py b/tests/test-class-design.py
deleted file mode 100644
index bb80cd3..0000000
--- a/tests/test-class-design.py
+++ /dev/null
@@ -1,101 +0,0 @@
-#!/usr/bin/env python
-#
-# testing classes to test multiple inheritance.
-# these are not meant to be run by trial, though they could be made to be so.
-# i didn't know where to put them. --isis
-
-import abc
-from pprint import pprint
-from inspect import classify_class_attrs
-
-class PluginBase(object):
- __metaclass__ = abc.ABCMeta
-
- @abc.abstractproperty
- def name(self):
- return 'you should not see this'
-
- @name.setter
- def name(self, value):
- return 'you should not set this'
-
- @name.deleter
- def name(self):
- return 'you should not del this'
-
- @abc.abstractmethod
- def inputParser(self, line):
- """Do something to parse something."""
- return
-
-class Foo(object):
- woo = "this class has some shit in it"
- def bar(self):
- print "i'm a Foo.bar()!"
- print woo
-
-class KwargTest(Foo):
- _name = "isis"
-
- #def __new__(cls, *a, **kw):
- # return super(KwargTest, cls).__new__(cls, *a, **kw)
-
- @property
- def name(self):
- return self._name
-
- @name.setter
- def name(self, value):
- self._name = value
-
- def __init__(self, *a, **kw):
- super(KwargTest, self).__init__()
-
- ## this causes the instantion args to override the class attrs
- for key, value in kw.items():
- setattr(self.__class__, key, value)
-
- print "%s.__init__(): self.__dict__ = %s" \
- % (type(self), pprint(type(self).__dict__))
-
- for attr in classify_class_attrs(self):
- print attr
-
- @classmethod
- def sayname(cls):
- print cls.name
-
-class KwargTestChild(KwargTest):
- name = "arturo"
- def __init__(self):
- super(KwargTestChild, self).__init__()
- print self.name
-
-class KwargTestChildOther(KwargTest):
- def __init__(self, name="robot", does="lasers"):
- super(KwargTestChildOther, self).__init__()
- print self.name
-
-
-if __name__ == "__main__":
- print "class KwargTest attr name: %s" % KwargTest.name
- kwargtest = KwargTest()
- print "KwargTest instantiated wo args"
- print "kwargtest.name: %s" % kwargtest.name
- print "kwargtest.sayname(): %s" % kwargtest.sayname()
- kwargtest2 = KwargTest(name="lovecruft", does="hacking")
- print "KwargTest instantiated with name args"
- print "kwargtest.name: %s" % kwargtest2.name
- print "kwargtest.sayname(): %s" % kwargtest2.sayname()
-
- print "class KwargTestChild attr name: %s" % KwargTestChild.name
- kwargtestchild = KwargTestChild()
- print "KwargTestChild instantiated wo args"
- print "kwargtestchild.name: %s" % kwargtestchild.name
- print "kwargtestchild.sayname(): %s" % kwargtestchild.sayname()
-
- print "class KwargTestChildOther attr name: %s" % KwargTestChildOther.name
- kwargtestchildother = KwargTestChildOther()
- print "KwargTestChildOther instantiated wo args"
- print "kwargtestchildother.name: %s" % kwargtestchildother.name
- print "kwargtestchildother.sayname(): %s" % kwargtestchildother.sayname()
diff --git a/tests/test_director.py b/tests/test_director.py
deleted file mode 100644
index a9dfbe8..0000000
--- a/tests/test_director.py
+++ /dev/null
@@ -1,59 +0,0 @@
-from twisted.internet import defer, base
-from twisted.trial import unittest
-
-from ooni.director import Director
-from ooni.nettest import NetTestLoader
-from tests.mocks import MockReporter
-base.DelayedCall.debug = True
-
-net_test_string = """
-from twisted.python import usage
-from ooni.nettest import NetTestCase
-
-class UsageOptions(usage.Options):
- optParameters = [['spam', 's', None, 'ham']]
-
-class DummyTestCase(NetTestCase):
- inputFile = ['file', 'f', None, 'The input File']
-
- usageOptions = UsageOptions
-
- def test_a(self):
- self.report['bar'] = 'bar'
-
- def test_b(self):
- self.report['foo'] = 'foo'
-"""
-
-
-dummyArgs = ('--spam', 1, '--file', 'dummyInputFile.txt')
-
-class TestDirector(unittest.TestCase):
- timeout = 1
- def setUp(self):
- with open('dummyInputFile.txt', 'w') as f:
- for i in range(10):
- f.write("%s\n" % i)
-
- self.reporters = [MockReporter()]
- self.director = Director()
-
- def tearDown(self):
- pass
-
- def test_start_net_test(self):
- ntl = NetTestLoader(dummyArgs)
- ntl.loadNetTestString(net_test_string)
-
- ntl.checkOptions()
- d = self.director.startNetTest('', ntl, self.reporters)
-
- @d.addCallback
- def done(result):
- self.assertEqual(self.director.successfulMeasurements, 20)
-
- return d
-
- def test_stop_net_test(self):
- pass
-
diff --git a/tests/test_dns.py b/tests/test_dns.py
deleted file mode 100644
index e9bb524..0000000
--- a/tests/test_dns.py
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# This unittest is to verify that our usage of the twisted DNS resolver does
-# not break with new versions of twisted.
-
-import pdb
-from twisted.trial import unittest
-
-from twisted.internet import reactor
-
-from twisted.names import dns
-from twisted.names.client import Resolver
-
-class DNSTest(unittest.TestCase):
- def test_a_lookup_ooni_query(self):
- def done_query(message, *arg):
- answer = message.answers[0]
- self.assertEqual(answer.type, 1)
-
- dns_query = [dns.Query('ooni.nu', type=dns.A)]
- resolver = Resolver(servers=[('8.8.8.8', 53)])
- d = resolver.queryUDP(dns_query)
- d.addCallback(done_query)
- return d
-
diff --git a/tests/test_inputunit.py b/tests/test_inputunit.py
deleted file mode 100644
index 1f9043c..0000000
--- a/tests/test_inputunit.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import unittest
-from ooni.inputunit import InputUnit, InputUnitFactory
-
-def dummyGenerator():
- for x in range(100):
- yield x
-
-class TestInputUnit(unittest.TestCase):
- def test_input_unit_factory(self):
- inputUnit = InputUnitFactory(range(100))
- for i in inputUnit:
- self.assertEqual(len(list(i)), inputUnit.inputUnitSize)
-
- def test_input_unit(self):
- inputs = range(100)
- inputUnit = InputUnit(inputs)
- idx = 0
- for i in inputUnit:
- idx += 1
-
- self.assertEqual(idx, 100)
-
- def test_input_unit_factory_length(self):
- inputUnitFactory = InputUnitFactory(range(100))
- l1 = len(inputUnitFactory)
- l2 = sum(1 for _ in inputUnitFactory)
- self.assertEqual(l1, 10)
- self.assertEqual(l2, 10)
-
diff --git a/tests/test_managers.py b/tests/test_managers.py
deleted file mode 100644
index 39f0881..0000000
--- a/tests/test_managers.py
+++ /dev/null
@@ -1,215 +0,0 @@
-from twisted.trial import unittest
-from twisted.python import failure
-from twisted.internet import defer, task
-
-from ooni.tasks import BaseTask, TaskWithTimeout, TaskTimedOut
-from ooni.managers import TaskManager, MeasurementManager
-
-from tests.mocks import MockSuccessTask, MockFailTask, MockFailOnceTask, MockFailure
-from tests.mocks import MockSuccessTaskWithTimeout, MockFailTaskThatTimesOut
-from tests.mocks import MockTimeoutOnceTask, MockFailTaskWithTimeout
-from tests.mocks import MockTaskManager, mockFailure, MockDirector
-from tests.mocks import MockNetTest, MockMeasurement, MockSuccessMeasurement
-from tests.mocks import MockFailMeasurement, MockFailOnceMeasurement
-
-class TestTaskManager(unittest.TestCase):
- timeout = 1
- def setUp(self):
- self.measurementManager = MockTaskManager()
- self.measurementManager.concurrency = 20
- self.measurementManager.retries = 2
-
- self.measurementManager.start()
-
- self.clock = task.Clock()
-
- def schedule_successful_tasks(self, task_type, number=1):
- all_done = []
- for x in range(number):
- mock_task = task_type()
- all_done.append(mock_task.done)
- self.measurementManager.schedule(mock_task)
-
- d = defer.DeferredList(all_done)
- @d.addCallback
- def done(res):
- for task_result, task_instance in self.measurementManager.successes:
- self.assertEqual(task_result, 42)
- self.assertIsInstance(task_instance, task_type)
-
- return d
-
- def schedule_failing_tasks(self, task_type, number=1):
- all_done = []
- for x in range(number):
- mock_task = task_type()
- all_done.append(mock_task.done)
- self.measurementManager.schedule(mock_task)
-
- d = defer.DeferredList(all_done)
- @d.addCallback
- def done(res):
- # 10*2 because 2 is the number of retries
- self.assertEqual(len(self.measurementManager.failures), number*3)
- for task_result, task_instance in self.measurementManager.failures:
- self.assertEqual(task_result, mockFailure)
- self.assertIsInstance(task_instance, task_type)
-
- return d
-
- def test_schedule_failing_with_mock_failure_task(self):
- mock_task = MockFailTask()
- self.measurementManager.schedule(mock_task)
- self.assertFailure(mock_task.done, MockFailure)
- return mock_task.done
-
- def test_schedule_successful_one_task(self):
- return self.schedule_successful_tasks(MockSuccessTask)
-
- def test_schedule_successful_one_task_with_timeout(self):
- return self.schedule_successful_tasks(MockSuccessTaskWithTimeout)
-
- def test_schedule_failing_tasks_that_timesout(self):
- self.measurementManager.retries = 0
-
- task_type = MockFailTaskThatTimesOut
- task_timeout = 5
-
- mock_task = task_type()
- mock_task.timeout = task_timeout
- mock_task.clock = self.clock
-
- self.measurementManager.schedule(mock_task)
-
- self.clock.advance(task_timeout)
-
- @mock_task.done.addBoth
- def done(res):
- self.assertEqual(len(self.measurementManager.failures), 1)
- for task_result, task_instance in self.measurementManager.failures:
- self.assertIsInstance(task_instance, task_type)
-
- return mock_task.done
-
- def test_schedule_time_out_once(self):
- task_type = MockTimeoutOnceTask
- task_timeout = 5
-
- mock_task = task_type()
- mock_task.timeout = task_timeout
- mock_task.clock = self.clock
-
- self.measurementManager.schedule(mock_task)
-
- self.clock.advance(task_timeout)
-
- @mock_task.done.addBoth
- def done(res):
- self.assertEqual(len(self.measurementManager.failures), 1)
- for task_result, task_instance in self.measurementManager.failures:
- self.assertIsInstance(task_instance, task_type)
-
- for task_result, task_instance in self.measurementManager.successes:
- self.assertEqual(task_result, 42)
- self.assertIsInstance(task_instance, task_type)
-
- return mock_task.done
-
-
- def test_schedule_failing_one_task(self):
- return self.schedule_failing_tasks(MockFailTask)
-
- def test_schedule_failing_one_task_with_timeout(self):
- return self.schedule_failing_tasks(MockFailTaskWithTimeout)
-
- def test_schedule_successful_ten_tasks(self):
- return self.schedule_successful_tasks(MockSuccessTask, number=10)
-
- def test_schedule_failing_ten_tasks(self):
- return self.schedule_failing_tasks(MockFailTask, number=10)
-
- def test_schedule_successful_27_tasks(self):
- return self.schedule_successful_tasks(MockSuccessTask, number=27)
-
- def test_schedule_failing_27_tasks(self):
- return self.schedule_failing_tasks(MockFailTask, number=27)
-
- def test_task_retry_and_succeed(self):
- mock_task = MockFailOnceTask()
- self.measurementManager.schedule(mock_task)
-
- @mock_task.done.addCallback
- def done(res):
- self.assertEqual(len(self.measurementManager.failures), 1)
-
- self.assertEqual(self.measurementManager.failures,
- [(mockFailure, mock_task)])
- self.assertEqual(self.measurementManager.successes,
- [(42, mock_task)])
-
- return mock_task.done
-
- def dd_test_task_retry_and_succeed_56_tasks(self):
- """
- XXX this test fails in a non-deterministic manner.
- """
- all_done = []
- number = 56
- for x in range(number):
- mock_task = MockFailOnceTask()
- all_done.append(mock_task.done)
- self.measurementManager.schedule(mock_task)
-
- d = defer.DeferredList(all_done)
-
- @d.addCallback
- def done(res):
- self.assertEqual(len(self.measurementManager.failures), number)
-
- for task_result, task_instance in self.measurementManager.successes:
- self.assertEqual(task_result, 42)
- self.assertIsInstance(task_instance, MockFailOnceTask)
-
- return d
-
-class TestMeasurementManager(unittest.TestCase):
- def setUp(self):
- mock_director = MockDirector()
-
- self.measurementManager = MeasurementManager()
- self.measurementManager.director = mock_director
-
- self.measurementManager.concurrency = 10
- self.measurementManager.retries = 2
-
- self.measurementManager.start()
-
- self.mockNetTest = MockNetTest()
-
- def test_schedule_and_net_test_notified(self, number=1):
- # XXX we should probably be inheriting from the base test class
- mock_task = MockSuccessMeasurement(self.mockNetTest)
- self.measurementManager.schedule(mock_task)
-
- @mock_task.done.addCallback
- def done(res):
- self.assertEqual(self.mockNetTest.successes,
- [42])
-
- self.assertEqual(len(self.mockNetTest.successes), 1)
- return mock_task.done
-
- def test_schedule_failing_one_measurement(self):
- mock_task = MockFailMeasurement(self.mockNetTest)
- self.measurementManager.schedule(mock_task)
-
- @mock_task.done.addErrback
- def done(failure):
- self.assertEqual(len(self.measurementManager.failures), 3)
-
- self.assertEqual(failure, mockFailure)
- self.assertEqual(len(self.mockNetTest.successes), 0)
-
- return mock_task.done
-
-
diff --git a/tests/test_mutate.py b/tests/test_mutate.py
deleted file mode 100644
index 7e30586..0000000
--- a/tests/test_mutate.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import unittest
-from ooni.kit import daphn3
-
-class TestDaphn3(unittest.TestCase):
- def test_mutate_string(self):
- original_string = '\x00\x00\x00'
- mutated = daphn3.daphn3MutateString(original_string, 1)
- self.assertEqual(mutated, '\x00\x01\x00')
- def test_mutate_daphn3(self):
- original_dict = [{'client': '\x00\x00\x00'},
- {'server': '\x00\x00\x00'}]
- mutated_dict = daphn3.daphn3Mutate(original_dict, 1, 1)
- self.assertEqual(mutated_dict, [{'client': '\x00\x00\x00'},
- {'server': '\x00\x01\x00'}])
-
diff --git a/tests/test_nettest.py b/tests/test_nettest.py
deleted file mode 100644
index 78240d5..0000000
--- a/tests/test_nettest.py
+++ /dev/null
@@ -1,268 +0,0 @@
-import os
-from StringIO import StringIO
-from tempfile import TemporaryFile, mkstemp
-
-from twisted.trial import unittest
-from twisted.internet import defer, reactor
-from twisted.python.usage import UsageError
-
-from ooni.nettest import NetTest, InvalidOption, MissingRequiredOption
-from ooni.nettest import NetTestLoader, FailureToLoadNetTest
-from ooni.tasks import BaseTask
-from ooni.utils import NotRootError
-
-from ooni.director import Director
-
-from ooni.managers import TaskManager
-
-from tests.mocks import MockMeasurement, MockMeasurementFailOnce
-from tests.mocks import MockNetTest, MockDirector, MockReporter
-from tests.mocks import MockMeasurementManager
-defer.setDebugging(True)
-
-net_test_string = """
-from twisted.python import usage
-from ooni.nettest import NetTestCase
-
-class UsageOptions(usage.Options):
- optParameters = [['spam', 's', None, 'ham']]
-
-class DummyTestCase(NetTestCase):
-
- usageOptions = UsageOptions
-
- def test_a(self):
- self.report['bar'] = 'bar'
-
- def test_b(self):
- self.report['foo'] = 'foo'
-"""
-
-net_test_root_required = net_test_string+"""
- requiresRoot = True
-"""
-
-net_test_string_with_file = """
-from twisted.python import usage
-from ooni.nettest import NetTestCase
-
-class UsageOptions(usage.Options):
- optParameters = [['spam', 's', None, 'ham']]
-
-class DummyTestCase(NetTestCase):
- inputFile = ['file', 'f', None, 'The input File']
-
- usageOptions = UsageOptions
-
- def test_a(self):
- self.report['bar'] = 'bar'
-
- def test_b(self):
- self.report['foo'] = 'foo'
-"""
-
-net_test_string_with_required_option = """
-from twisted.python import usage
-from ooni.nettest import NetTestCase
-
-class UsageOptions(usage.Options):
- optParameters = [['spam', 's', None, 'ham'],
- ['foo', 'o', None, 'moo'],
- ['bar', 'o', None, 'baz'],
- ]
-
-class DummyTestCase(NetTestCase):
- inputFile = ['file', 'f', None, 'The input File']
-
- usageOptions = UsageOptions
-
- def test_a(self):
- self.report['bar'] = 'bar'
-
- def test_b(self):
- self.report['foo'] = 'foo'
-
- requiredOptions = ['foo', 'bar']
-"""
-
-dummyInputs = range(1)
-dummyArgs = ('--spam', 'notham')
-dummyOptions = {'spam':'notham'}
-dummyInvalidArgs = ('--cram', 'jam')
-dummyInvalidOptions= {'cram':'jam'}
-dummyArgsWithRequiredOptions = ('--foo', 'moo', '--bar', 'baz')
-dummyRequiredOptions = {'foo':'moo', 'bar':'baz'}
-dummyArgsWithFile = ('--spam', 'notham', '--file', 'dummyInputFile.txt')
-
-class TestNetTest(unittest.TestCase):
- timeout = 1
- def setUp(self):
- with open('dummyInputFile.txt', 'w') as f:
- for i in range(10):
- f.write("%s\n" % i)
-
- def assertCallable(self, thing):
- self.assertIn('__call__', dir(thing))
-
- def verifyMethods(self, testCases):
- uniq_test_methods = set()
- for test_class, test_methods in testCases:
- instance = test_class()
- for test_method in test_methods:
- c = getattr(instance, test_method)
- self.assertCallable(c)
- uniq_test_methods.add(test_method)
- self.assertEqual(set(['test_a', 'test_b']), uniq_test_methods)
-
- def test_load_net_test_from_file(self):
- """
- Given a file verify that the net test cases are properly
- generated.
- """
- __, net_test_file = mkstemp()
- with open(net_test_file, 'w') as f:
- f.write(net_test_string)
- f.close()
-
- ntl = NetTestLoader(dummyArgs)
- ntl.loadNetTestFile(net_test_file)
-
- self.verifyMethods(ntl.testCases)
- os.unlink(net_test_file)
-
- def test_load_net_test_from_str(self):
- """
- Given a file like object verify that the net test cases are properly
- generated.
- """
- ntl = NetTestLoader(dummyArgs)
- ntl.loadNetTestString(net_test_string)
-
- self.verifyMethods(ntl.testCases)
-
- def test_load_net_test_from_StringIO(self):
- """
- Given a file like object verify that the net test cases are properly
- generated.
- """
- ntl = NetTestLoader(dummyArgs)
- ntl.loadNetTestString(net_test_string)
-
- self.verifyMethods(ntl.testCases)
-
- def test_load_with_option(self):
- ntl = NetTestLoader(dummyArgs)
- ntl.loadNetTestString(net_test_string)
-
- self.assertIsInstance(ntl, NetTestLoader)
- for test_klass, test_meth in ntl.testCases:
- for option in dummyOptions.keys():
- self.assertIn(option, test_klass.usageOptions())
-
- def test_load_with_invalid_option(self):
- try:
- ntl = NetTestLoader(dummyInvalidArgs)
- ntl.loadNetTestString(net_test_string)
-
- ntl.checkOptions()
- raise Exception
- except UsageError:
- pass
-
- def test_load_with_required_option(self):
- ntl = NetTestLoader(dummyArgsWithRequiredOptions)
- ntl.loadNetTestString(net_test_string_with_required_option)
-
- self.assertIsInstance(ntl, NetTestLoader)
-
- def test_load_with_missing_required_option(self):
- try:
- ntl = NetTestLoader(dummyArgs)
- ntl.loadNetTestString(net_test_string_with_required_option)
-
- except MissingRequiredOption:
- pass
-
- def test_net_test_inputs(self):
- ntl = NetTestLoader(dummyArgsWithFile)
- ntl.loadNetTestString(net_test_string_with_file)
-
- ntl.checkOptions()
-
- # XXX: if you use the same test_class twice you will have consumed all
- # of its inputs!
- tested = set([])
- for test_class, test_method in ntl.testCases:
- if test_class not in tested:
- tested.update([test_class])
- self.assertEqual(len(list(test_class.inputs)), 10)
-
- def test_setup_local_options_in_test_cases(self):
- ntl = NetTestLoader(dummyArgs)
- ntl.loadNetTestString(net_test_string)
-
- ntl.checkOptions()
-
- for test_class, test_method in ntl.testCases:
- self.assertEqual(test_class.localOptions, dummyOptions)
-
- def test_generate_measurements_size(self):
- ntl = NetTestLoader(dummyArgsWithFile)
- ntl.loadNetTestString(net_test_string_with_file)
-
- ntl.checkOptions()
- net_test = NetTest(ntl, None)
-
- measurements = list(net_test.generateMeasurements())
- self.assertEqual(len(measurements), 20)
-
- def test_net_test_completed_callback(self):
- ntl = NetTestLoader(dummyArgsWithFile)
- ntl.loadNetTestString(net_test_string_with_file)
-
- ntl.checkOptions()
- director = Director()
-
- d = director.startNetTest('', ntl, [MockReporter()])
-
- @d.addCallback
- def complete(result):
- #XXX: why is the return type (True, None) ?
- self.assertEqual(result, [(True,None)])
- self.assertEqual(director.successfulMeasurements, 20)
-
- return d
-
- def test_require_root_succeed(self):
- #XXX: will require root to run
- ntl = NetTestLoader(dummyArgs)
- ntl.loadNetTestString(net_test_root_required)
-
- for test_class, method in ntl.testCases:
- self.assertTrue(test_class.requiresRoot)
-
- #def test_require_root_failed(self):
- # #XXX: will fail if you run as root
- # try:
- # net_test = NetTestLoader(StringIO(net_test_root_required),
- # dummyArgs)
- # except NotRootError:
- # pass
-
- #def test_create_report_succeed(self):
- # pass
-
- #def test_create_report_failed(self):
- # pass
-
- #def test_run_all_test(self):
- # raise NotImplementedError
-
- #def test_resume_test(self):
- # pass
-
- #def test_progress(self):
- # pass
-
- #def test_time_out(self):
- # raise NotImplementedError
diff --git a/tests/test_otime.py b/tests/test_otime.py
deleted file mode 100644
index 80979f2..0000000
--- a/tests/test_otime.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import unittest
-from datetime import datetime
-from ooni import otime
-
-test_date = datetime(2002, 6, 26, 22, 45, 49)
-
-class TestOtime(unittest.TestCase):
- def test_timestamp(self):
- self.assertEqual(otime.timestamp(test_date), "2002-06-26T224549Z")
-
- def test_fromTimestamp(self):
- time_stamp = otime.timestamp(test_date)
- self.assertEqual(test_date, otime.fromTimestamp(time_stamp))
-
-
diff --git a/tests/test_reporter.py b/tests/test_reporter.py
deleted file mode 100644
index e21b7a1..0000000
--- a/tests/test_reporter.py
+++ /dev/null
@@ -1,238 +0,0 @@
-from twisted.internet import defer
-from twisted.trial import unittest
-
-from ooni.reporter import Report, YAMLReporter, OONIBReporter, safe_dump
-from ooni.managers import ReportEntryManager, TaskManager
-from ooni.nettest import NetTest, NetTestState
-from ooni.errors import ReportNotCreated, ReportAlreadyClosed
-
-from ooni.tasks import TaskWithTimeout
-from tests.mocks import MockOReporter, MockTaskManager
-from tests.mocks import MockMeasurement, MockNetTest
-from tests.mocks import MockOReporterThatFailsWrite
-from tests.mocks import MockOReporterThatFailsWriteOnce
-from tests.mocks import MockOReporterThatFailsOpen
-
-from twisted.python import failure
-import yaml
-
-class TestReport(unittest.TestCase):
- def setUp(self):
- pass
- def tearDown(self):
- pass
- def test_create_report_with_no_reporter(self):
- report = Report([],ReportEntryManager())
- self.assertIsInstance(report, Report)
-
- def test_create_report_with_single_reporter(self):
- report = Report([MockOReporter()], ReportEntryManager())
- self.assertIsInstance(report, Report)
-
- def test_create_report_with_multiple_reporters(self):
- report = Report([MockOReporter() for x in xrange(3)],
- ReportEntryManager())
- self.assertIsInstance(report, Report)
-
- def test_report_open_with_single_reporter(self):
- report = Report([MockOReporter()],ReportEntryManager())
- d = report.open()
- return d
-
- def test_report_open_with_multiple_reporter(self):
- report = Report([MockOReporter() for x in xrange(3)],
- ReportEntryManager())
- d = report.open()
- return d
-
- def test_fail_to_open_report_with_single_reporter(self):
- report = Report([MockOReporterThatFailsOpen()],
- ReportEntryManager())
- d = report.open()
- def f(x):
- self.assertEquals(len(report.reporters), 0)
- d.addCallback(f)
- return d
-
- def test_fail_to_open_single_report_with_multiple_reporter(self):
- report = Report([MockOReporterThatFailsOpen(), MockOReporter(),
- MockOReporter()], ReportEntryManager())
- d = report.open()
- def f(x):
- self.assertEquals(len(report.reporters),2)
- d.addCallback(f)
- return d
-
- def test_fail_to_open_all_reports_with_multiple_reporter(self):
- report = Report([MockOReporterThatFailsOpen() for x in xrange(3)],
- ReportEntryManager())
- d = report.open()
- def f(x):
- self.assertEquals(len(report.reporters),0)
- d.addCallback(f)
- return d
-
- def test_write_report_with_single_reporter_and_succeed(self):
- #XXX: verify that the MockOReporter writeReportEntry succeeds
- report = Report([MockOReporter()], ReportEntryManager())
- report.open()
- d = report.write(MockMeasurement(MockNetTest()))
- return d
-
- def test_write_report_with_single_reporter_and_fail_after_timeout(self):
- report = Report([MockOReporterThatFailsWrite()], ReportEntryManager())
- report.open()
- d = report.write(MockMeasurement(MockNetTest()))
- def f(err):
- self.assertEquals(len(report.reporters),0)
- d.addBoth(f)
- return d
-
- def test_write_report_with_single_reporter_and_succeed_after_timeout(self):
- report = Report([MockOReporterThatFailsWriteOnce()], ReportEntryManager())
- report.open()
- d = report.write(MockMeasurement(MockNetTest()))
- return d
-
- def test_write_report_with_multiple_reporter_and_succeed(self):
- report = Report([MockOReporter() for x in xrange(3)], ReportEntryManager())
- report.open()
- d = report.write(MockMeasurement(MockNetTest()))
- return d
-
- def test_write_report_with_multiple_reporter_and_fail_a_single_reporter(self):
- report = Report([MockOReporter(), MockOReporter(), MockOReporterThatFailsWrite()], ReportEntryManager())
- d = report.open()
-
- self.assertEquals(len(report.reporters),3)
- d = report.write(MockMeasurement(MockNetTest()))
-
- def f(x):
- # one of the reporters should have been removed
- self.assertEquals(len(report.reporters), 2)
- d.addBoth(f)
- return d
-
- def test_write_report_with_multiple_reporter_and_fail_all_reporter(self):
- report = Report([MockOReporterThatFailsWrite() for x in xrange(3)], ReportEntryManager())
- report.open()
- d = report.write(MockMeasurement(MockNetTest()))
- def f(err):
- self.assertEquals(len(report.reporters),0)
- d.addErrback(f)
- return d
-
-class TestYAMLReporter(unittest.TestCase):
- def setUp(self):
- self.testDetails = {'software_name': 'ooniprobe', 'options':
- {'pcapfile': None, 'help': 0, 'subargs': ['-f', 'alexa_10'], 'resume':
- 0, 'parallelism': '10', 'no-default-reporter': 0, 'testdeck': None,
- 'test': 'nettests/blocking/http_requests.py', 'logfile': None,
- 'collector': None, 'reportfile': None}, 'test_version': '0.2.3',
- 'software_version': '0.0.10', 'test_name': 'http_requests_test',
- 'start_time': 1362054343.0, 'probe_asn': 'AS0', 'probe_ip':
- '127.0.0.1', 'probe_cc': 'US'}
-
- def tearDown(self):
- pass
- def test_create_yaml_reporter(self):
- self.assertIsInstance(YAMLReporter(self.testDetails),
- YAMLReporter)
-
- def test_open_yaml_report_and_succeed(self):
- r = YAMLReporter(self.testDetails)
- r.createReport()
- # verify that testDetails was written to report properly
- def f(r):
- r._stream.seek(0)
- details, = yaml.safe_load_all(r._stream)
- self.assertEqual(details, self.testDetails)
- r.created.addCallback(f)
- return r.created
-
- #def test_open_yaml_report_and_fail(self):
- # #XXX: YAMLReporter does not handle failures of this type
- # pass
-
- def test_write_yaml_report_entry(self):
- r = YAMLReporter(self.testDetails)
- r.createReport()
-
- report_entry = {'foo':'bar', 'bin':'baz'}
- r.writeReportEntry(report_entry)
-
- # verify that details and entry were written to report
- def f(r):
- r._stream.seek(0)
- report = yaml.safe_load_all(r._stream)
- details, entry = report
- self.assertEqual(details, self.testDetails)
- self.assertEqual(entry, report_entry)
- r.created.addCallback(f)
- return r.created
-
- def test_write_multiple_yaml_report_entry(self):
- r = YAMLReporter(self.testDetails)
- r.createReport()
- def reportEntry():
- for x in xrange(10):
- yield {'foo':'bar', 'bin':'baz', 'item':x}
- for entry in reportEntry():
- r.writeReportEntry(entry)
- # verify that details and multiple entries were written to report
- def f(r):
- r._stream.seek(0)
- report = yaml.safe_load_all(r._stream)
- details = report.next()
- self.assertEqual(details, self.testDetails)
- self.assertEqual([r for r in report], [r for r in reportEntry()])
- r.created.addCallback(f)
- return r.created
-
- def test_close_yaml_report(self):
- r = YAMLReporter(self.testDetails)
- r.createReport()
- r.finish()
- self.assertTrue(r._stream.closed)
-
- def test_write_yaml_report_after_close(self):
- r = YAMLReporter(self.testDetails)
- r.createReport()
- r.finish()
- def f(r):
- r.writeReportEntry("foo")
- r.created.addCallback(f)
- self.assertFailure(r.created, ReportAlreadyClosed)
-
- def test_write_yaml_report_before_open(self):
- r = YAMLReporter(self.testDetails)
- def f(r):
- r.writeReportEntry("foo")
- r.created.addCallback(f)
- self.assertFailure(r.created, ReportNotCreated)
-
-#class TestOONIBReporter(unittest.TestCase):
-# def setUp(self):
-# pass
-# def tearDown(self):
-# pass
-# def test_create_oonib_reporter(self):
-# raise NotImplementedError
-# def test_open_oonib_report_and_succeed(self):
-# raise NotImplementedError
-# def test_open_oonib_report_and_fail(self):
-# raise NotImplementedError
-# def test_write_oonib_report_entry_and_succeed(self):
-# raise NotImplementedError
-# def test_write_oonib_report_entry_and_succeed_after_timeout(self):
-# raise NotImplementedError
-# def test_write_oonib_report_entry_and_fail_after_timeout(self):
-# raise NotImplementedError
-# def test_write_oonib_report_after_close(self):
-# raise NotImplementedError
-# def test_write_oonib_report_before_open(self):
-# raise NotImplementedError
-# def test_close_oonib_report_and_succeed(self):
-# raise NotImplementedError
-# def test_close_oonib_report_and_fail(self):
-# raise NotImplementedError
diff --git a/tests/test_safe_represent.py b/tests/test_safe_represent.py
deleted file mode 100644
index 82a5196..0000000
--- a/tests/test_safe_represent.py
+++ /dev/null
@@ -1,14 +0,0 @@
-import yaml
-
-from twisted.trial import unittest
-
-from ooni.reporter import OSafeDumper
-
-from scapy.all import IP, UDP
-
-class TestScapyRepresent(unittest.TestCase):
- def test_represent_scapy(self):
- data = IP()/UDP()
- yaml.dump_all([data], Dumper=OSafeDumper)
-
-
diff --git a/tests/test_trueheaders.py b/tests/test_trueheaders.py
deleted file mode 100644
index 9ac0a27..0000000
--- a/tests/test_trueheaders.py
+++ /dev/null
@@ -1,41 +0,0 @@
-from twisted.trial import unittest
-
-from ooni.utils.txagentwithsocks import TrueHeaders
-
-dummy_headers_dict = {
- 'Header1': ['Value1', 'Value2'],
- 'Header2': ['ValueA', 'ValueB']
-}
-
-dummy_headers_dict2 = {
- 'Header1': ['Value1', 'Value2'],
- 'Header2': ['ValueA', 'ValueB'],
- 'Header3': ['ValueA', 'ValueB'],
-}
-
-dummy_headers_dict3 = {
- 'Header1': ['Value1', 'Value2'],
- 'Header2': ['ValueA', 'ValueB'],
- 'Header4': ['ValueA', 'ValueB'],
-}
-
-
-class TestTrueHeaders(unittest.TestCase):
- def test_names_match(self):
- th = TrueHeaders(dummy_headers_dict)
- self.assertEqual(th.getDiff(TrueHeaders(dummy_headers_dict)), set())
-
- def test_names_not_match(self):
- th = TrueHeaders(dummy_headers_dict)
- self.assertEqual(th.getDiff(TrueHeaders(dummy_headers_dict2)), set(['Header3']))
-
- th = TrueHeaders(dummy_headers_dict3)
- self.assertEqual(th.getDiff(TrueHeaders(dummy_headers_dict2)), set(['Header3', 'Header4']))
-
- def test_names_match_expect_ignore(self):
- th = TrueHeaders(dummy_headers_dict)
- self.assertEqual(th.getDiff(TrueHeaders(dummy_headers_dict2), ignore=['Header3']), set())
-
-
-
-
diff --git a/tests/test_utils.py b/tests/test_utils.py
deleted file mode 100644
index cc648e0..0000000
--- a/tests/test_utils.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import unittest
-from ooni.utils import pushFilenameStack
-
-class TestUtils(unittest.TestCase):
- def test_pushFilenameStack(self):
- f = open("dummyfile", "w+")
- f.write("0\n")
- f.close()
- for i in xrange(1, 5):
- f = open("dummyfile.%s" % i, "w+")
- f.write("%s\n" % i)
- f.close()
-
- pushFilenameStack("dummyfile")
- for i in xrange(1, 5):
- f = open("dummyfile.%s" % i)
- c = f.readlines()[0].strip()
- self.assertEqual(str(i-1), str(c))
- f.close()
-
More information about the tor-commits
mailing list