commit c1ff7516d35b7f76fb6638ae2bce04db5c4b3864 Author: Arturo Filastò arturo@filasto.net Date: Fri Mar 11 17:55:16 2016 +0100
Refactor lantern test to use the ProcessTest template
* Improve blocking detection --- ooni/nettests/third_party/lantern.py | 98 ++++++++++++++---------------------- 1 file changed, 38 insertions(+), 60 deletions(-)
diff --git a/ooni/nettests/third_party/lantern.py b/ooni/nettests/third_party/lantern.py index 1f1b3b0..187e210 100644 --- a/ooni/nettests/third_party/lantern.py +++ b/ooni/nettests/third_party/lantern.py @@ -1,47 +1,13 @@ +import os from twisted.internet import defer, reactor from twisted.internet.endpoints import TCP4ClientEndpoint -from twisted.python import usage from twisted.web.client import ProxyAgent, readBody from ooni.templates.process import ProcessTest, ProcessDirector from ooni.utils import log from ooni.errors import handleAllFailures -import os.path -from os import getenv - -class UsageOptions(usage.Options): - optParameters = [ - ['url', 'u', None, 'Specify a single URL to test.'],] - -class LanternProcessDirector(ProcessDirector): - """ - This Process Director monitors Lantern during its - bootstrap and fires a callback if bootstrap is - successful or an errback if it fails to bootstrap - before timing out. - """ - - def __init__(self, d, timeout=None): - self.d = d - self.stderr = "" - self.stdout = "" - self.finished = None - self.timeout = timeout - self.stdin = None - self.timer = None - self.exit_reason = None - self.bootstrapped = defer.Deferred() - - def outReceived(self, data): - self.stdout += data - # output received, see if we have bootstrapped - if not self.bootstrapped.called and "Connected to proxy on localhost" in self.stdout: - log.debug("Bootstrap Detected") - self.cancelTimer() - self.bootstrapped.callback("bootstrapped") - +import distutils.spawn
class LanternTest(ProcessTest): - """ This class tests Lantern (https://getlantern.org).
@@ -54,47 +20,59 @@ class LanternTest(ProcessTest): """
name = "Lantern Circumvention Tool Test" - description = "Bootstraps Lantern and does a HTTP GET for the specified URL" + description = "Bootstraps Lantern, connects to a URL and verifies if it contains the expected input" author = "Aaron Gibson" - version = "0.0.1" - timeout = 20 - usageOptions = UsageOptions - requiredOptions = ['url'] + version = "0.1.0" + timeout = 120
def setUp(self): - self.command = ["lantern", "--headless"] - self.d = defer.Deferred() - self.processDirector = LanternProcessDirector(self.d, timeout=self.timeout) - self.d.addCallback(self.processEnded, self.command) - if self.localOptions['url']: - self.url = self.localOptions['url'] - - def runLantern(self): - paths = filter(os.path.exists,[os.path.join(os.path.expanduser(x), self.command[0]) for x in getenv('PATH').split(':')]) - log.debug("Spawning Lantern") - reactor.spawnProcess(self.processDirector, paths[0], self.command) + self.command = [distutils.spawn.find_executable("lantern"), "--headless"] + self.bootstrapped = defer.Deferred() + self.exited = False + self.url = 'http://www.google.com/humans.txt' + + def stop(self, reason=None): + if not self.exited: + self.processDirector.close() + self.processDirector.transport.signalProcess('TERM') + self.exited = True + + def handleRead(self, stdout=None, stderr=None): + """ + This is called with each chunk of data from stdout and stderr. + """ + if not self.bootstrapped.called and "Successfully dialed via" in self.processDirector.stdout: + log.msg("Lantern connection successful") + self.processDirector.cancelTimer() + self.bootstrapped.callback("bootstrapped")
def test_lantern_circumvent(self): - proxyEndpoint=TCP4ClientEndpoint(reactor, '127.0.0.1', 8787) - agent = ProxyAgent(proxyEndpoint, reactor) - def addResultToReport(result): self.report['body'] = result - self.report['success'] = True + if result.startswith('Google is built by a large'): + log.msg("Got the HTTP response body I expected!") + self.report['success'] = True + else: + self.report['success'] = False
def addFailureToReport(failure): + log.err("Failed to connect to lantern") + log.failure(failure) self.report['failure'] = handleAllFailures(failure) self.report['success'] = False
def doRequest(noreason): - log.debug("Doing HTTP request via Lantern (127.0.0.1:8787) for %s" % self.url) + proxyEndpoint = TCP4ClientEndpoint(reactor, '127.0.0.1', 8787) + agent = ProxyAgent(proxyEndpoint, reactor) + log.msg("Doing HTTP request via Lantern (127.0.0.1:8787) for %s" % self.url) request = agent.request("GET", self.url) request.addCallback(readBody) request.addCallback(addResultToReport) request.addCallback(self.processDirector.close) return request
- self.processDirector.bootstrapped.addCallback(doRequest) - self.processDirector.bootstrapped.addErrback(addFailureToReport) - self.runLantern() + self.bootstrapped.addCallback(doRequest) + self.bootstrapped.addErrback(addFailureToReport) + self.bootstrapped.addBoth(self.stop) + self.d = self.run(self.command, env=os.environ, usePTY=1) return self.d
tor-commits@lists.torproject.org