[tor-commits] [oonib/master] Add unittests for the report handlers.

art at torproject.org art at torproject.org
Wed Apr 30 17:33:44 UTC 2014


commit 699c26c018d0b19ee61c57d7c27207faee1e556c
Author: Arturo Filastò <art at fuffa.org>
Date:   Wed Apr 30 14:57:57 2014 +0200

    Add unittests for the report handlers.
    
    Add a useful base class for implementing any unittest.
---
 oonib/test/handler_helpers.py |   62 +++++++++++++++
 oonib/test/test_report.py     |  173 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 235 insertions(+)

diff --git a/oonib/test/__init__.py b/oonib/test/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/oonib/test/handler_helpers.py b/oonib/test/handler_helpers.py
new file mode 100644
index 0000000..2d704a2
--- /dev/null
+++ b/oonib/test/handler_helpers.py
@@ -0,0 +1,62 @@
+import socket
+import json
+
+from twisted.internet import reactor, defer
+from twisted.trial import unittest
+
+from cyclone import httpclient
+
+
+def random_unused_port(bind_address='127.0.0.1'):
+    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    s.bind(('127.0.0.1', 0))
+    port = s.getsockname()[1]
+    s.close()
+    return port
+
+reports = {}
+
+
+def mock_initialize(self):
+    self.report_dir = '.'
+    self.archive_dir = '.'
+    self.reports = reports
+    self.policy_file = None
+    self.helpers = {}
+    self.stale_time = 10
+
+
+class HandlerTestCase(unittest.TestCase):
+    app = None
+    _port = None
+    _listener = None
+
+    @property
+    def port(self):
+        if not self._port:
+            self._port = random_unused_port()
+        return self._port
+
+    def setUp(self, *args, **kw):
+        if self.app:
+            self._listener = reactor.listenTCP(self.port, self.app)
+        return unittest.TestCase.setUp(self, *args, **kw)
+
+    def tearDown(self):
+        if self._listener:
+            for report in reports.values():
+                try:
+                    report.delayed_call.cancel()
+                except:
+                    pass
+            self._listener.stopListening()
+
+    @defer.inlineCallbacks
+    def request(self, path, method="GET", postdata=None):
+        url = "http://localhost:%s%s" % (self.port, path)
+        if isinstance(postdata, dict):
+            postdata = json.dumps(postdata)
+
+        response = yield httpclient.fetch(url, method=method,
+                                          postdata=postdata)
+        defer.returnValue(response)
diff --git a/oonib/test/test_report.py b/oonib/test/test_report.py
new file mode 100644
index 0000000..9ed02de
--- /dev/null
+++ b/oonib/test/test_report.py
@@ -0,0 +1,173 @@
+import os
+import json
+import yaml
+
+from twisted.internet import defer
+
+from cyclone import web
+
+from oonib.report.handlers import report_file_name
+from oonib.report.api import reportAPI
+from oonib.test.handler_helpers import HandlerTestCase, mock_initialize
+
+sample_report_entry = """---
+agent: agent
+input: null
+requests:
+- request:
+    body: null
+    headers:
+    - - ACCePT-LAnGuagE
+    - ['en-US,en;q=0.8']
+    - - aCCEPT-ENcODInG
+    - ['gzip,deflate,sdch']
+    - - aCcEPT
+    - ['text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8']
+    - - User-AGeNt
+    - ['Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.7) Gecko/20091221
+        Firefox/3.5.7']
+    - - aCCEpt-cHArSEt
+    - ['ISO-8859-1,utf-8;q=0.7,*;q=0.3']
+    - - HOsT
+    - [KIXnnZDJfGKRNab.com]
+    method: GET
+    url: http://12.34.56.78
+response:
+    body: '{"headers_dict": {"ACCePT-LAnGuagE": ["en-US,en;q=0.8"], "aCCEPT-ENcODInG":
+    ["gzip,deflate,sdch"], "HOsT": ["KIXnnZDJfGKRNab.com"], "aCcEPT": ["text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"],
+    "User-AGeNt": ["Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.7)
+    Gecko/20091221 Firefox/3.5.7"], "aCCEpt-cHArSEt": ["ISO-8859-1,utf-8;q=0.7,*;q=0.3"],
+    "Connection": ["close"]}, "request_line": "GET / HTTP/1.1", "request_headers":
+    [["Connection", "close"], ["ACCePT-LAnGuagE", "en-US,en;q=0.8"], ["aCCEPT-ENcODInG",
+    "gzip,deflate,sdch"], ["aCcEPT", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"],
+    ["User-AGeNt", "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.7)
+    Gecko/20091221 Firefox/3.5.7"], ["aCCEpt-cHArSEt", "ISO-8859-1,utf-8;q=0.7,*;q=0.3"],
+    ["HOsT", "KIXnnZDJfGKRNab.com"]]}'
+    code: 200
+    headers: []
+socksproxy: null
+tampering:
+header_field_name: false
+header_field_number: false
+header_field_value: false
+header_name_capitalization: false
+header_name_diff: []
+request_line_capitalization: false
+total: false
+...
+"""
+
+for _, handler in reportAPI:
+    handler.initialize = mock_initialize
+
+
+class TestReport(HandlerTestCase):
+    app = web.Application(reportAPI, name='reportAPI')
+
+    @defer.inlineCallbacks
+    def update_report(self, report_id, content=sample_report_entry):
+        data = {
+            'content': content
+        }
+        response = yield self.request(
+            '/report/%s' % report_id,
+            "POST", data)
+        defer.returnValue(response)
+
+    @defer.inlineCallbacks
+    def test_create_valid_report(self):
+        data = {
+            'software_name': 'ooni-test',
+            'software_version': '0.1',
+            'test_name': 'some-test',
+            'test_version': '0.1',
+            'probe_asn': 'AS0'
+        }
+        response = yield self.request('/report', "POST", data)
+        response_body = json.loads(response.body)
+        self.assertIn('backend_version', response_body)
+        self.assertIn('report_id', response_body)
+
+    @defer.inlineCallbacks
+    def test_create_invalid_report(self):
+        data = {
+            'software_name': 'ooni-test',
+            'software_version': '0.1',
+            'test_name': 'some-test',
+            'test_version': '0.1',
+            'probe_asn': 'XXX'
+        }
+        response = yield self.request('/report', "POST", data)
+        response_body = json.loads(response.body)
+        self.assertIn('error', response_body)
+        self.assertEqual(response_body['error'], 'invalid-request-field probe_asn')
+
+    @defer.inlineCallbacks
+    def test_create_and_update_report(self):
+        report_header = {
+            'software_name': 'ooni-test',
+            'software_version': '0.1',
+            'test_name': 'some-test',
+            'test_version': '0.1',
+            'probe_asn': 'AS0'
+        }
+        response = yield self.request('/report', "POST", report_header)
+        response_body = json.loads(response.body)
+        self.assertIn('backend_version', response_body)
+        self.assertIn('report_id', response_body)
+
+        report_id = response_body['report_id']
+        response = yield self.update_report(report_id)
+        response_body = json.loads(response.body)
+
+        with open(report_id) as f:
+            written_report = yaml.safe_load_all(f)
+
+            written_report_header = written_report.next()
+            for key in report_header.keys():
+                self.assertEqual(written_report_header[key], report_header[key])
+            self.assertEqual(yaml.safe_load(sample_report_entry),
+                             written_report.next())
+
+    @defer.inlineCallbacks
+    def test_create_update_and_close_report(self):
+        report_header = {
+            'software_name': 'ooni-test',
+            'software_version': '0.1',
+            'test_name': 'some-test',
+            'test_version': '0.1',
+            'probe_asn': 'AS0'
+        }
+        response = yield self.request('/report', "POST", report_header)
+        response_body = json.loads(response.body)
+        self.assertIn('backend_version', response_body)
+        self.assertIn('report_id', response_body)
+
+        report_entry_count = 100
+
+        report_id = response_body['report_id']
+        for i in range(report_entry_count):
+            yield self.update_report(report_id)
+
+        with open(report_id) as f:
+            written_report = yaml.safe_load_all(f)
+
+            written_report_header = written_report.next()
+            for key in report_header.keys():
+                self.assertEqual(written_report_header[key],
+                                 report_header[key])
+
+            self.assertEqual(yaml.safe_load(sample_report_entry),
+                             written_report.next())
+
+        response = yield self.request('/report/%s/close' % report_id, "POST")
+
+        written_report_path = os.path.join(written_report_header['probe_cc'],
+                                           report_file_name(written_report_header))
+        with open(written_report_path) as f:
+            written_report = yaml.safe_load_all(f)
+            written_report.next()
+
+            for i in range(report_entry_count):
+                self.assertEqual(yaml.safe_load(sample_report_entry),
+                                 written_report.next())





More information about the tor-commits mailing list