[tor-commits] [ooni-probe/master] Refactor lantern test to use the ProcessTest template

art at torproject.org art at torproject.org
Fri Apr 29 09:42:25 UTC 2016


commit c1ff7516d35b7f76fb6638ae2bce04db5c4b3864
Author: Arturo Filastò <arturo at 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





More information about the tor-commits mailing list