commit 699c26c018d0b19ee61c57d7c27207faee1e556c Author: Arturo Filastò <a...@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())
_______________________________________________ tor-commits mailing list tor-commits@lists.torproject.org https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits