[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [ooni-probe/master] Import basic stuff from Twisted trial



commit c4ad2411046deb08f17902320cb8dd21cc25f367
Author: Arturo Filastò <arturo@xxxxxxxxxxx>
Date:   Tue Sep 11 10:38:35 2012 +0000

    Import basic stuff from Twisted trial
---
 .gitignore                  |    1 +
 README.md                   |   10 +
 bin/ooniprobe               |   16 ++-
 ooni/oonicli.py             |  397 +++++++++++++++++++++++++++++++++++++++++++
 ooni/oonitests/bridget.py   |  373 ----------------------------------------
 ooni/plugins/new_bridget.py |    2 +-
 ooni/protocols/http.py      |   13 +-
 ooni/reporter.py            |   13 ++
 ooni/runner.py              |    7 +
 9 files changed, 448 insertions(+), 384 deletions(-)

diff --git a/.gitignore b/.gitignore
index 7f270bb..6b1b9ce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ proxy-lists/italy-http-ips.txt
 private/*
 /ooni/plugins/dropin.cache
 oonib/oonibackend.conf
+ooni/assets/*
diff --git a/README.md b/README.md
index b39cb2b..123d837 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,16 @@ To list the help for a specific test:
 
     python ooniprobe.py httpt --help
 
+## Virtualenv way (Recommended)
+
+    virtualenv2 ENV/
+    source ENV/bin/activate
+    pip install twisted Scapy
+
+To install the most up to date scapy version (requires mercurial):
+
+    pip install hg+http://hg.secdev.org/scapy
+
 
 # More details
 
diff --git a/bin/ooniprobe b/bin/ooniprobe
index 5c87831..1f0c26d 100755
--- a/bin/ooniprobe
+++ b/bin/ooniprobe
@@ -1,5 +1,11 @@
-#!/bin/sh
-ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-echo $ROOT
-export PYTHONPATH=$PYTHONPATH:$ROOT
-python $ROOT/ooni/ooniprobe.py $1
+#!/usr/bin/python2
+# startup script based on twisted trial
+# See http://twistedmatrix.com/
+import os, sys
+
+sys.path[:] = map(os.path.abspath, sys.path)
+
+sys.path.insert(0, os.path.abspath(os.getcwd()))
+
+from ooni.oonicli import run
+run()
diff --git a/ooni/oonicli.py b/ooni/oonicli.py
new file mode 100644
index 0000000..8ace160
--- /dev/null
+++ b/ooni/oonicli.py
@@ -0,0 +1,397 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8
+#
+#    oonicli
+#    *********
+#
+#    oonicli is the next generation ooniprober. It based off of twisted's trial
+#    unit testing framework.
+#
+#    :copyright: (c) 2012 by Arturo Filastò
+#    :license: see LICENSE for more details.
+#
+#    original copyright (c) by Twisted Matrix Laboratories.
+
+
+import sys, os, random, gc, time, warnings
+
+from twisted.internet import defer
+from twisted.application import app
+from twisted.python import usage, reflect, failure
+from twisted.python.filepath import FilePath
+from twisted import plugin
+from twisted.python.util import spewer
+from twisted.python.compat import set
+from twisted.trial import runner, itrial, reporter
+
+
+# Yea, this is stupid.  Leave it for for command-line compatibility for a
+# while, though.
+TBFORMAT_MAP = {
+    'plain': 'default',
+    'default': 'default',
+    'emacs': 'brief',
+    'brief': 'brief',
+    'cgitb': 'verbose',
+    'verbose': 'verbose'
+    }
+
+
+def _parseLocalVariables(line):
+    """
+    Accepts a single line in Emacs local variable declaration format and
+    returns a dict of all the variables {name: value}.
+    Raises ValueError if 'line' is in the wrong format.
+
+    See http://www.gnu.org/software/emacs/manual/html_node/File-Variables.html
+    """
+    paren = '-*-'
+    start = line.find(paren) + len(paren)
+    end = line.rfind(paren)
+    if start == -1 or end == -1:
+        raise ValueError("%r not a valid local variable declaration" % (line,))
+    items = line[start:end].split(';')
+    localVars = {}
+    for item in items:
+        if len(item.strip()) == 0:
+            continue
+        split = item.split(':')
+        if len(split) != 2:
+            raise ValueError("%r contains invalid declaration %r"
+                             % (line, item))
+        localVars[split[0].strip()] = split[1].strip()
+    return localVars
+
+
+def loadLocalVariables(filename):
+    """
+    Accepts a filename and attempts to load the Emacs variable declarations
+    from that file, simulating what Emacs does.
+
+    See http://www.gnu.org/software/emacs/manual/html_node/File-Variables.html
+    """
+    f = file(filename, "r")
+    lines = [f.readline(), f.readline()]
+    f.close()
+    for line in lines:
+        try:
+            return _parseLocalVariables(line)
+        except ValueError:
+            pass
+    return {}
+
+
+def getTestModules(filename):
+    testCaseVar = loadLocalVariables(filename).get('test-case-name', None)
+    if testCaseVar is None:
+        return []
+    return testCaseVar.split(',')
+
+
+def isTestFile(filename):
+    """
+    Returns true if 'filename' looks like a file containing unit tests.
+    False otherwise.  Doesn't care whether filename exists.
+    """
+    basename = os.path.basename(filename)
+    return (basename.startswith('test_')
+            and os.path.splitext(basename)[1] == ('.py'))
+
+
+def _reporterAction():
+    return usage.CompleteList([p.longOpt for p in
+                               plugin.getPlugins(itrial.IReporter)])
+
+class Options(usage.Options):
+
+    optParameters = [
+        ['parallelism', 'n', 10, "Specify the number of parallel tests to run"],
+        ['output', 'o', 'report.log', "Specify output report file"],
+        ['log', 'l', 'oonicli.log', "Specify output log file"]
+    ]
+
+    def opt_version(self):
+        """
+        Display OONI version and exit.
+        """
+        print "OONI version:", __version__
+        sys.exit(0)
+
+
+class Options(usage.Options, app.ReactorSelectionMixin):
+    synopsis = """%s [options] [[file|package|module|TestCase|testmethod]...]
+    """ % (os.path.basename(sys.argv[0]),)
+
+    longdesc = ("ooniprobe loads and executes a suite or a set of suites of"
+                "network tests. These are loaded from modules, packages and"
+                "files listed on the command line")
+
+    optFlags = [["help", "h"],
+                ["rterrors", "e", "realtime errors, print out tracebacks as "
+                 "soon as they occur"],
+                ["debug", "b", "Run tests in the Python debugger. Will load "
+                 "'.pdbrc' from current directory if it exists."],
+                ["debug-stacktraces", "B", "Report Deferred creation and "
+                 "callback stack traces"],
+                ["nopm", None, "don't automatically jump into debugger for "
+                 "postmorteming of exceptions"],
+                ["dry-run", 'n', "do everything but run the tests"],
+                ["force-gc", None, "Have Trial run gc.collect() before and "
+                 "after each test case."],
+                ["profile", None, "Run tests under the Python profiler"],
+                ["unclean-warnings", None,
+                 "Turn dirty reactor errors into warnings"],
+                ["until-failure", "u", "Repeat test until it fails"],
+                ["no-recurse", "N", "Don't recurse into packages"],
+                ['help-reporters', None,
+                 "Help on available output plugins (reporters)"]
+                ]
+
+    optParameters = [
+        ["logfile", "l", "test.log", "log file name"],
+        ["random", "z", None,
+         "Run tests in random order using the specified seed"],
+        ['temp-directory', None, '_trial_temp',
+         'Path to use as working directory for tests.'],
+        ['reporter', None, 'verbose',
+         'The reporter to use for this test run.  See --help-reporters for '
+         'more info.']]
+
+    compData = usage.Completions(
+        optActions={"tbformat": usage.CompleteList(["plain", "emacs", "cgitb"]),
+                    "reporter": _reporterAction,
+                    "logfile": usage.CompleteFiles(descr="log file name"),
+                    "random": usage.Completer(descr="random seed")},
+        extraActions=[usage.CompleteFiles(
+                "*.py", descr="file | module | package | TestCase | testMethod",
+                repeat=True)],
+        )
+
+    fallbackReporter = reporter.TreeReporter
+    tracer = None
+
+    def __init__(self):
+        self['tests'] = set()
+        usage.Options.__init__(self)
+
+
+    def coverdir(self):
+        """
+        Return a L{FilePath} representing the directory into which coverage
+        results should be written.
+        """
+        coverdir = 'coverage'
+        result = FilePath(self['temp-directory']).child(coverdir)
+        print "Setting coverage directory to %s." % (result.path,)
+        return result
+
+
+    def opt_coverage(self):
+        """
+        Generate coverage information in the I{coverage} file in the
+        directory specified by the I{trial-temp} option.
+        """
+        import trace
+        self.tracer = trace.Trace(count=1, trace=0)
+        sys.settrace(self.tracer.globaltrace)
+
+
+    def opt_testmodule(self, filename):
+        """
+        Filename to grep for test cases (-*- test-case-name)
+        """
+        # If the filename passed to this parameter looks like a test module
+        # we just add that to the test suite.
+        #
+        # If not, we inspect it for an Emacs buffer local variable called
+        # 'test-case-name'.  If that variable is declared, we try to add its
+        # value to the test suite as a module.
+        #
+        # This parameter allows automated processes (like Buildbot) to pass
+        # a list of files to Trial with the general expectation of "these files,
+        # whatever they are, will get tested"
+        if not os.path.isfile(filename):
+            sys.stderr.write("File %r doesn't exist\n" % (filename,))
+            return
+        filename = os.path.abspath(filename)
+        if isTestFile(filename):
+            self['tests'].add(filename)
+        else:
+            self['tests'].update(getTestModules(filename))
+
+
+    def opt_spew(self):
+        """
+        Print an insanely verbose log of everything that happens.  Useful
+        when debugging freezes or locks in complex code.
+        """
+        sys.settrace(spewer)
+
+
+    def opt_help_reporters(self):
+        synopsis = ("OONI's output can be customized using plugins called "
+                    "Reporters. You can\nselect any of the following "
+                    "reporters using --reporter=<foo>\n")
+        print synopsis
+        for p in plugin.getPlugins(itrial.IReporter):
+            print '   ', p.longOpt, '\t', p.description
+        print
+        sys.exit(0)
+
+
+    def opt_disablegc(self):
+        """
+        Disable the garbage collector
+        """
+        gc.disable()
+
+
+    def opt_tbformat(self, opt):
+        """
+        Specify the format to display tracebacks with. Valid formats are
+        'plain', 'emacs', and 'cgitb' which uses the nicely verbose stdlib
+        cgitb.text function
+        """
+        try:
+            self['tbformat'] = TBFORMAT_MAP[opt]
+        except KeyError:
+            raise usage.UsageError(
+                "tbformat must be 'plain', 'emacs', or 'cgitb'.")
+
+
+    def opt_recursionlimit(self, arg):
+        """
+        see sys.setrecursionlimit()
+        """
+        try:
+            sys.setrecursionlimit(int(arg))
+        except (TypeError, ValueError):
+            raise usage.UsageError(
+                "argument to recursionlimit must be an integer")
+
+
+    def opt_random(self, option):
+        try:
+            self['random'] = long(option)
+        except ValueError:
+            raise usage.UsageError(
+                "Argument to --random must be a positive integer")
+        else:
+            if self['random'] < 0:
+                raise usage.UsageError(
+                    "Argument to --random must be a positive integer")
+            elif self['random'] == 0:
+                self['random'] = long(time.time() * 100)
+
+
+    def opt_without_module(self, option):
+        """
+        Fake the lack of the specified modules, separated with commas.
+        """
+        for module in option.split(","):
+            if module in sys.modules:
+                warnings.warn("Module '%s' already imported, "
+                              "disabling anyway." % (module,),
+                              category=RuntimeWarning)
+            sys.modules[module] = None
+
+
+    def parseArgs(self, *args):
+        self['tests'].update(args)
+
+
+    def _loadReporterByName(self, name):
+        for p in plugin.getPlugins(itrial.IReporter):
+            qual = "%s.%s" % (p.module, p.klass)
+            if p.longOpt == name:
+                return reflect.namedAny(qual)
+        raise usage.UsageError("Only pass names of Reporter plugins to "
+                               "--reporter. See --help-reporters for "
+                               "more info.")
+
+
+    def postOptions(self):
+        # Only load reporters now, as opposed to any earlier, to avoid letting
+        # application-defined plugins muck up reactor selecting by importing
+        # t.i.reactor and causing the default to be installed.
+        self['reporter'] = self._loadReporterByName(self['reporter'])
+
+        if 'tbformat' not in self:
+            self['tbformat'] = 'default'
+        if self['nopm']:
+            if not self['debug']:
+                raise usage.UsageError("you must specify --debug when using "
+                                       "--nopm ")
+            failure.DO_POST_MORTEM = False
+
+
+
+def _initialDebugSetup(config):
+    # do this part of debug setup first for easy debugging of import failures
+    if config['debug']:
+        failure.startDebugMode()
+    if config['debug'] or config['debug-stacktraces']:
+        defer.setDebugging(True)
+
+
+
+def _getSuite(config):
+    loader = _getLoader(config)
+    recurse = not config['no-recurse']
+    return loader.loadByNames(config['tests'], recurse)
+
+
+
+def _getLoader(config):
+    loader = runner.TestLoader()
+    if config['random']:
+        randomer = random.Random()
+        randomer.seed(config['random'])
+        loader.sorter = lambda x : randomer.random()
+        print 'Running tests shuffled with seed %d\n' % config['random']
+    if not config['until-failure']:
+        loader.suiteFactory = runner.DestructiveTestSuite
+    return loader
+
+
+
+def _makeRunner(config):
+    mode = None
+    if config['debug']:
+        mode = runner.TrialRunner.DEBUG
+    if config['dry-run']:
+        mode = runner.TrialRunner.DRY_RUN
+    return runner.TrialRunner(config['reporter'],
+                              mode=mode,
+                              profile=config['profile'],
+                              logfile=config['logfile'],
+                              tracebackFormat=config['tbformat'],
+                              realTimeErrors=config['rterrors'],
+                              uncleanWarnings=config['unclean-warnings'],
+                              workingDirectory=config['temp-directory'],
+                              forceGarbageCollection=config['force-gc'])
+
+
+
+def run():
+    if len(sys.argv) == 1:
+        sys.argv.append("--help")
+    config = Options()
+    try:
+        config.parseOptions()
+    except usage.error, ue:
+        raise SystemExit, "%s: %s" % (sys.argv[0], ue)
+    _initialDebugSetup(config)
+    trialRunner = _makeRunner(config)
+    suite = _getSuite(config)
+    if config['until-failure']:
+        test_result = trialRunner.runUntilFailure(suite)
+    else:
+        test_result = trialRunner.run(suite)
+    if config.tracer:
+        sys.settrace(None)
+        results = config.tracer.results()
+        results.write_results(show_missing=1, summary=False,
+                              coverdir=config.coverdir().path)
+    sys.exit(not test_result.wasSuccessful())
+
diff --git a/ooni/oonitests/bridget.py b/ooni/oonitests/bridget.py
deleted file mode 100644
index a613f61..0000000
--- a/ooni/oonitests/bridget.py
+++ /dev/null
@@ -1,373 +0,0 @@
-# -*- coding: UTF-8
-"""
-    bridgeT
-    *******
-
-    an OONI test (we call them Plugoos :P) aimed
-    at detecting if a set of Tor bridges are working or not.
-
-    :copyright: (c) 2012 by Arturo Filastò
-    :license: BSD, see LICENSE for more details.
-"""
-import os
-import sys
-import errno
-import time
-import random
-import re
-import glob
-import socks
-import socket
-from shutil import rmtree
-from subprocess import Popen, PIPE
-from datetime import datetime
-
-import shutil
-import gevent
-from gevent import socket
-import fcntl
-from plugoo.assets import Asset
-from plugoo.tests import Test
-import urllib2
-import httplib
-import json
-
-try:
-    from TorCtl import TorCtl
-except:
-    print "Error TorCtl not installed!"
-
-__plugoo__ = "BridgeT"
-__desc__ = "BridgeT, for testing Tor Bridge reachability"
-ONIONOO_URL="http://85.214.195.203/summary/search/";
-
-class SocksiPyConnection(httplib.HTTPConnection):
-    def __init__(self, proxytype, proxyaddr, proxyport = None, rdns = True,
-                 username = None, password = None, *args, **kwargs):
-        self.proxyargs = (proxytype, proxyaddr, proxyport, rdns, username, password)
-        httplib.HTTPConnection.__init__(self, *args, **kwargs)
-
-    def connect(self):
-        self.sock = socks.socksocket()
-        self.sock.setproxy(*self.proxyargs)
-        if isinstance(self.timeout, float):
-            self.sock.settimeout(self.timeout)
-        self.sock.connect((self.host, self.port))
-
-class SocksiPyHandler(urllib2.HTTPHandler):
-    def __init__(self, *args, **kwargs):
-        self.args = args
-        self.kw = kwargs
-        urllib2.HTTPHandler.__init__(self)
-
-    def http_open(self, req):
-        def build(host, port=None, strict=None, timeout=0):
-            conn = SocksiPyConnection(*self.args, host=host, port=port,
-                                      strict=strict, timeout=timeout, **self.kw)
-            return conn
-        return self.do_open(build, req)
-
-class BridgeTAsset(Asset):
-    def __init__(self, file=None):
-        self = Asset.__init__(self, file)
-
-class BridgeT(Test):
-    # This is the timeout value after which
-    # we will give up
-    timeout = 20
-    # These are the modules that should be torified
-    modules = [urllib2]
-
-    def tor_greater_than(self, version):
-        """
-        Checks if the currently installed version of Tor is greater
-        than the required version.
-
-        :version The version of Tor to check against for greater than or equal
-        """
-        fullstring = os.popen("tor --version").read().split('\n')[-2]
-        v_array = fullstring.split(' ')[2].split('-')
-        minor = v_array[1:]
-        v_array = v_array[0].split('.')
-        minor_p = version.split('-')[1:]
-        v_array_p = version.split('-')[0].split('.')
-
-        for i, x in enumerate(v_array):
-            try:
-                if i > len(v_array_p):
-                    break
-
-                if int(x) > int(v_array_p[i]):
-                    self.logger.debug("The Tor version is greater than %s" % version)
-                    return True
-                elif int(x) == int(v_array_p[i]):
-                    self.logger.debug("The Tor version is greater than %s" % version)
-                    continue
-                else:
-                    self.logger.debug("You run an outdated version of Tor: %s (< %s)" % (fullstring, version))
-                    return False
-            except:
-                self.logger.error("Error in parsing your Tor version string: %s" % fullstring)
-                return False
-
-        self.logger.debug("The Tor version is equal to %s" % version)
-        return True
-        # XXX currently don't consider the minor parts of the version
-        # (alpha, dev, beta, etc.)
-
-    def free_port(self, port):
-        s = socket.socket()
-        try:
-            s.bind(('127.0.0.1', port))
-            s.close()
-            return True
-        except:
-            self.logger.warn("The randomly chosen port was already taken!")
-            s.close()
-            return False
-
-    def writetorrc(self, bridge):
-        """
-        Write the torrc file for the tor process to be used
-        to test the bridge.
-
-        :bridge the bridge to be tested
-        """
-        self.failures = []
-        prange = (49152, 65535)
-
-        # register Tor to an ephemeral port
-        socksport = random.randint(prange[0], prange[1])
-        # Keep on trying to get a new port if the chosen one is already
-        # taken.
-        while not self.free_port(socksport):
-            socksport = random.randint(prange[0], prange[1])
-        controlport = random.randint(prange[0], prange[1])
-        while not self.free_port(controlport):
-            controlport = random.randint(prange[0], prange[1])
-
-        randomname = "tor_"+str(random.randint(0, 424242424242))
-        datadir = "/tmp/" + randomname
-        if bridge.startswith("obfs://"):
-            obfsbridge = bridge.split("//")[1]
-
-            self.logger.debug("Genearting torrc file for obfs bridge")
-            torrc = """SocksPort %s
-UseBridges 1
-Bridge obfs2 %s
-DataDirectory %s
-ClientTransportPlugin obfs2 exec /usr/local/bin/obfsproxy --managed
-ControlPort %s
-Log info file %s
-""" % (socksport, obfsbridge, datadir, controlport, os.path.join(datadir,'tor.log'))
-        else:
-            self.logger.debug("Generating torrc file for bridge")
-            if self.tor_greater_than('0.2.3.2'):
-
-                torrc = """SocksPort %s
-UseBridges 1
-bridge %s
-DataDirectory %s
-usemicrodescriptors 0
-ControlPort %s
-Log info file %s
-""" % (socksport, bridge, datadir, controlport, os.path.join(datadir,'tor.log'))
-            else:
-                torrc = """SocksPort %s
-UseBridges 1
-bridge %s
-DataDirectory %s
-ControlPort %s
-Log info file %s
-""" % (socksport, bridge, datadir, controlport, os.path.join(datadir,'tor.log'))
-
-        with open(randomname, "wb") as f:
-            f.write(torrc)
-
-        os.mkdir(datadir)
-        return (randomname, datadir, controlport, socksport)
-
-    def parsebridgeinfo(self, output):
-        ret = {}
-        fields = ['router', 'platform', 'opt', 'published', 'uptime', 'bandwidth']
-
-        for x in output.split("\n"):
-            cfield = x.split(' ')
-            if cfield[0] in fields:
-                #not sure if hellais did this on purpose, but this overwrites
-                #the previous entries. For ex, 'opt' has multiple entries and
-                #only the last value is stored
-                ret[cfield[0]] = ' '.join(cfield[1:])
-                if cfield[1] == 'fingerprint':
-                    ret['fingerprint'] = ''.join(cfield[2:])
-        return ret
-
-    #Can't use @torify as it doesn't support concurrency right now
-    def download_file(self, socksport):
-        opener = urllib2.build_opener(SocksiPyHandler(socks.PROXY_TYPE_SOCKS5,
-                                                      '127.0.0.1', int(socksport)))
-
-        time_start=time.time()
-        f = opener.open('http://38.229.72.16/bwauth.torproject.org/256k')
-        f.read()
-        time_end = time.time()
-        print (time_end-time_start)
-        return str(256/(time_end-time_start)) + " KB/s"
-
-    def is_public(self, fp, socksport):
-        opener = urllib2.build_opener(SocksiPyHandler(socks.PROXY_TYPE_SOCKS5,'127.0.0.1',int(socksport)))
-        response = opener.open(str(ONIONOO_URL)+str(fp))
-        reply = json.loads(response.read())
-        if reply['bridges'] or reply['relays']:
-            return True
-        return False
-
-    def connect(self, bridge, timeout=None):
-        bridgeinfo = None
-        bandwidth = None
-        public = None
-        if not timeout:
-            if self.config.tests.tor_bridges_timeout:
-                self.timeout = self.config.tests.tor_bridges_timeout
-            timeout = self.timeout
-        torrc, tordir, controlport, socksport = self.writetorrc(bridge)
-        cmd = ["tor", "-f", torrc]
-
-        tupdate = time.time()
-        debugupdate = time.time()
-
-        try:
-            p = Popen(cmd, stdout=PIPE)
-        except:
-            self.logger.error("Error in starting Tor (do you have tor installed?)")
-
-        self.logger.info("Testing bridge: %s" % bridge)
-        while True:
-            o = ""
-            try:
-                o = p.stdout.read(4096)
-                if o:
-                    self.logger.debug(str(o))
-                if re.search("100%", o):
-                    self.logger.info("Success in connecting to %s" % bridge)
-
-                    print "%s bridge works" % bridge
-                    # print "%s controlport" % controlport
-                    try:
-                        c = TorCtl.connect('127.0.0.1', controlport)
-                        bridgeinfo = self.parsebridgeinfo(c.get_info('dir/server/all')['dir/server/all'])
-                        c.close()
-                    except:
-                        self.logger.error("Error in connecting to Tor Control port")
-
-                    # XXX disable the public checking
-                    #public = self.is_public(bridgeinfo['fingerprint'], socksport)
-                    #self.logger.info("Public: %s" % public)
-
-                    bandwidth = self.download_file(socksport)
-                    self.logger.info("Bandwidth: %s" % bandwidth)
-
-                    try:
-                        p.stdout.close()
-                    except:
-                        self.logger.error("Error in closing stdout FD.")
-
-                    try:
-                        os.unlink(os.path.join(os.getcwd(), torrc))
-                        rmtree(tordir)
-                    except:
-                        self.logger.error("Error in unlinking files.")
-
-                    p.terminate()
-                    return {
-                            'Time': datetime.now(),
-                            'Bridge': bridge,
-                            'Working': True,
-                            'Descriptor': bridgeinfo,
-                            'Calculated bandwidth': bandwidth,
-                            'Public': public
-                            }
-
-                if re.search("%", o):
-                    # Keep updating the timeout if there is progress
-                    self.logger.debug("Updating time...")
-                    tupdate = time.time()
-                    #print o
-                    continue
-
-            except IOError:
-                ex = sys.exc_info()[1]
-                if ex[0] != errno.EAGAIN:
-                    self.logger.error("Error IOError: EAGAIN")
-                    raise
-                sys.exc_clear()
-                print "In this exception 1"
-
-            try:
-                # Set the timeout for the socket wait
-                ct = timeout-(time.time() - tupdate)
-                socket.wait_read(p.stdout.fileno(), timeout=ct)
-
-            except:
-                lfh = open(os.path.join(tordir, 'tor.log'), 'r')
-                log = lfh.readlines()
-                lfh.close()
-                self.logger.info("%s bridge does not work (%s s timeout)" % (bridge, timeout))
-                print "%s bridge does not work (%s s timeout)" % (bridge, timeout)
-                self.failures.append(bridge)
-                p.stdout.close()
-                os.unlink(os.path.join(os.getcwd(), torrc))
-                rmtree(tordir)
-                p.terminate()
-                return {
-                        'Time': datetime.now(),
-                        'Bridge': bridge,
-                        'Working': False,
-                        'Descriptor': {},
-                        'Log': log
-                        }
-
-    def experiment(self, *a, **kw):
-        # this is just a dirty hack
-        bridge = kw['data']
-        print "Experiment"
-        config = self.config
-
-        return self.connect(bridge)
-
-    def clean(self):
-        for infile in glob.glob('tor_*'):
-            os.remove(infile)
-
-    def print_failures(self):
-        if self.failures:
-            for item in self.failures:
-                print "Offline : %s" % item
-        else:
-            print "All online"
-
-    # For logging TorCtl event msgs
-    #class LogHandler:
-    #def msg(self, severity, message):
-    #   print "[%s] %s"%(severity, message)
-
-def run(ooni, assets=None):
-    """
-    Run the test
-    """
-
-    config = ooni.config
-    urls = []
-
-    bridges = BridgeTAsset(os.path.join(config.main.assetdir, \
-                                        config.tests.tor_bridges))
-
-    bridgelist = [bridges]
-
-    bridget = BridgeT(ooni)
-    ooni.logger.info("Starting bridget test")
-    bridget.run(bridgelist)
-    bridget.print_failures()
-    bridget.clean()
-    ooni.logger.info("Testing completed!")
-
diff --git a/ooni/plugins/new_bridget.py b/ooni/plugins/new_bridget.py
index 3e4db56..b26455e 100644
--- a/ooni/plugins/new_bridget.py
+++ b/ooni/plugins/new_bridget.py
@@ -27,7 +27,7 @@ class bridgetArgs(usage.Options):
 class bridgetTest(OONITest):
     implements(IPlugin, ITest)
 
-    shortName = "bridget"
+    shortName = "newbridget"
     description = "bridget"
     requirements = None
     options = bridgetArgs
diff --git a/ooni/protocols/http.py b/ooni/protocols/http.py
index 2b38f28..09bb9b9 100644
--- a/ooni/protocols/http.py
+++ b/ooni/protocols/http.py
@@ -84,11 +84,7 @@ class HTTPTest(OONITest):
         """
         pass
 
-
-    def experiment(self, args):
-        log.msg("Running experiment")
-        url = self.local_options['url'] if 'url' not in args else args['url']
-
+    def doRequest(self, url):
         d = self.build_request(url)
         def finished(data):
             return data
@@ -97,6 +93,13 @@ class HTTPTest(OONITest):
         d.addCallback(finished)
         return d
 
+    def experiment(self, args):
+        log.msg("Running experiment")
+        url = self.local_options['url'] if 'url' not in args else args['url']
+
+        d = self.doRequest(url)
+        return d
+
     def _cbResponse(self, response):
         self.response['headers'] = list(response.headers.getAllRawHeaders())
         self.response['code'] = response.code
diff --git a/ooni/reporter.py b/ooni/reporter.py
new file mode 100644
index 0000000..0ecf2ea
--- /dev/null
+++ b/ooni/reporter.py
@@ -0,0 +1,13 @@
+from twisted.trial import reporter
+
+class TestResult(reporter.TestResult):
+    """
+    Accumulates the results of several ooni.nettest.TestCases.
+
+    The output format of a TestResult is YAML and it will contain all the basic
+    information that a test result should contain.
+    """
+    def __init__(self):
+        super(TestResult, self).__init__()
+
+
diff --git a/ooni/runner.py b/ooni/runner.py
new file mode 100644
index 0000000..d7caa9d
--- /dev/null
+++ b/ooni/runner.py
@@ -0,0 +1,7 @@
+from twisted.trial import runner
+
+
+class TestLoader(runner.TestLoader):
+    pass
+
+



_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits