Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: sitescripts/filterhits/test/api_tests.py

Issue 4615801646612480: Issue 395 - Filter hits statistics backend (Closed)
Left Patch Set: Addressed further feedback from Sebastian. Created March 31, 2015, 9:46 a.m.
Right Patch Set: Addressed further comments from Sebastian. Created April 2, 2015, 10:13 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « sitescripts/filterhits/test/__init__.py ('k') | sitescripts/filterhits/test/db_tests.py » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # coding: utf-8 1 # coding: utf-8
2 2
3 # This file is part of the Adblock Plus web scripts, 3 # This file is part of the Adblock Plus web scripts,
4 # Copyright (C) 2006-2015 Eyeo GmbH 4 # Copyright (C) 2006-2015 Eyeo GmbH
5 # 5 #
6 # Adblock Plus is free software: you can redistribute it and/or modify 6 # Adblock Plus is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License version 3 as 7 # it under the terms of the GNU General Public License version 3 as
8 # published by the Free Software Foundation. 8 # published by the Free Software Foundation.
9 # 9 #
10 # Adblock Plus is distributed in the hope that it will be useful, 10 # Adblock Plus is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details. 13 # GNU General Public License for more details.
14 # 14 #
15 # You should have received a copy of the GNU General Public License 15 # You should have received a copy of the GNU General Public License
16 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 16 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
17 17
18 import json 18 import json
19 import sys 19 import sys
20 import StringIO 20 import StringIO
21 import unittest 21 import unittest
22 from urllib import urlencode 22 from urllib import urlencode
23
24 import MySQLdb
25 23
26 from sitescripts.filterhits.test import test_helpers 24 from sitescripts.filterhits.test import test_helpers
27 from sitescripts.filterhits import db 25 from sitescripts.filterhits import db
28 from sitescripts.filterhits.web.query import query_handler 26 from sitescripts.filterhits.web.query import query_handler
29 from sitescripts.filterhits.web.submit import submit as submit_handler 27 from sitescripts.filterhits.web.submit import submit as submit_handler
30 28
31 valid_data = """{ 29 valid_data = """{
32 "version": 1, 30 "version": 1,
33 "timeSincePush": 12345, 31 "timeSincePush": 12345,
34 "addonName": "adblockplus", 32 "addonName": "adblockplus",
35 "addonVersion": "2.3.4", 33 "addonVersion": "2.3.4",
36 "application": "firefox", 34 "application": "firefox",
37 "applicationVersion": "31", 35 "applicationVersion": "31",
38 "platform": "gecko", 36 "platform": "gecko",
39 "platformVersion": "31", 37 "platformVersion": "31",
40 "filters": { 38 "filters": {
41 "||example.com^": { 39 "||example.com^": {
42 "firstParty": { 40 "firstParty": {
43 "example.com": {"hits": 12, "latest": 1414817340948}, 41 "example.com": {"hits": 12, "latest": 1414817340948},
44 "example.org": {"hits": 4, "latest": 1414859271125} 42 "example.org": {"hits": 4, "latest": 1414859271125}
45 }, 43 },
46 "thirdParty": { 44 "thirdParty": {
47 "example.com": {"hits": 5, "latest": 1414916268769} 45 "example.com": {"hits": 5, "latest": 1414916268769}
48 }, 46 },
49 "subscriptions": ["EasyList", "EasyList Germany+EasyList"] 47 "subscriptions": ["EasyList", "EasyList Germany+EasyList"]
50 } 48 }
51 } 49 }
52 }""" 50 }"""
53 51
54 class APITestCase(unittest.TestCase): 52 class APITestCase(test_helpers.FilterhitsTestCase):
55 def clear_rows(self):
56 if self.db:
57 db.write(self.db, (("DELETE FROM filters",),
58 ("DELETE FROM frequencies",)))
59
60 def setUp(self):
61 self.config = test_helpers.setup_config()
62 try:
63 self.db = db.connect()
64 except MySQLdb.Error:
65 self.db = None
66 self.clear_rows()
67
68 def tearDown(self):
69 test_helpers.restore_config()
70 if self.db:
71 self.clear_rows()
72 self.db.close()
73 self.db = None
74
75 def assertResponse(self, handler, expected_response, expected_result=None, exp ected_headers=None, **environ): 53 def assertResponse(self, handler, expected_response, expected_result=None, exp ected_headers=None, **environ):
76 def check_response(response, headers): 54 def check_response(response, headers):
77 self.assertEqual(response, expected_response) 55 self.assertEqual(response, expected_response)
78 if not expected_headers is None: 56 if not expected_headers is None:
79 self.assertEqual(headers, expected_headers) 57 self.assertEqual(headers, expected_headers)
80 58
81 if "body" in environ: 59 if "body" in environ:
82 environ["CONTENT_LENGTH"] = len(environ["body"]) 60 environ["CONTENT_LENGTH"] = len(environ["body"])
83 environ["wsgi.input"] = StringIO.StringIO(environ["body"]) 61 environ["wsgi.input"] = StringIO.StringIO(environ["body"])
84 del environ["body"] 62 del environ["body"]
(...skipping 14 matching lines...) Expand all
99 self.assertResponse(submit_handler, "400 Processing Error", 77 self.assertResponse(submit_handler, "400 Processing Error",
100 REQUEST_METHOD="POST", body="") 78 REQUEST_METHOD="POST", body="")
101 self.assertResponse(submit_handler, "400 Processing Error", 79 self.assertResponse(submit_handler, "400 Processing Error",
102 REQUEST_METHOD="POST", body="Oops...") 80 REQUEST_METHOD="POST", body="Oops...")
103 self.assertResponse(submit_handler, "400 Processing Error", 81 self.assertResponse(submit_handler, "400 Processing Error",
104 REQUEST_METHOD="POST", body="{123:]") 82 REQUEST_METHOD="POST", body="{123:]")
105 self.assertResponse(submit_handler, "400 Processing Error", 83 self.assertResponse(submit_handler, "400 Processing Error",
106 REQUEST_METHOD="POST", body="1") 84 REQUEST_METHOD="POST", body="1")
107 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 0) 85 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 0)
108 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 0) 86 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 0)
109 # Ensure even an empty object, or one with the wrong fields returns OK 87 # Ensure even an empty object, or one with the wrong fields returns successf ully
110 self.assertResponse(submit_handler, "200 OK", 88 self.assertResponse(submit_handler, "204 No Content",
111 REQUEST_METHOD="POST", body="{}") 89 REQUEST_METHOD="POST", body="{}")
112 self.assertResponse(submit_handler, "200 OK", 90 self.assertResponse(submit_handler, "204 No Content",
113 REQUEST_METHOD="POST", body="{\"hello\": \"world\"}") 91 REQUEST_METHOD="POST", body="{\"hello\": \"world\"}")
114 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 0) 92 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 0)
115 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 0) 93 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 0)
116 # Now some actually valid data 94 # Now some actually valid data
117 self.assertResponse(submit_handler, "200 OK", 95 self.assertResponse(submit_handler, "204 No Content",
118 REQUEST_METHOD="POST", body=valid_data) 96 REQUEST_METHOD="POST", body=valid_data)
119 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 2) 97 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 2)
120 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 1) 98 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 1)
121 # Now make sure apparently valid data with timestamps that cause geometrical 99 # Now make sure apparently valid data with timestamps that cause geometrical
122 # mean calculations to fail with MySQL errors return OK but don't change DB 100 # mean calculations to fail with MySQL errors return OK but don't change DB
123 invalid_data = json.loads(valid_data) 101 invalid_data = json.loads(valid_data)
124 invalid_data["filters"]["||example.com^"]["firstParty"]["example.com"]["late st"] = 3 102 invalid_data["filters"]["||example.com^"]["firstParty"]["example.com"]["late st"] = 3
125 invalid_data = json.dumps(invalid_data) 103 invalid_data = json.dumps(invalid_data)
126 self.assertResponse(submit_handler, "200 OK", 104 self.assertResponse(submit_handler, "204 No Content",
127 REQUEST_METHOD="POST", body=invalid_data) 105 REQUEST_METHOD="POST", body=invalid_data)
128 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 2) 106 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 2)
129 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 1) 107 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 1)
130 108
131 def test_query(self): 109 def test_query(self):
132 # Basic query with no data, should return OK 110 # Basic query with no data, should return successfully
133 self.assertResponse(query_handler, "200 OK", {"count": 0, "total": 0, "resul ts": [], "echo": 0}) 111 self.assertResponse(query_handler, "200 OK", {"count": 0, "total": 0, "resul ts": [], "echo": 0})
134 # If echo parameter is passed and is integer it should be returned 112 # If echo parameter is passed and is integer it should be returned
135 self.assertResponse(query_handler, "200 OK", {"count": 0, "total": 0, "resul ts": [], "echo": 1337}, 113 self.assertResponse(query_handler, "200 OK", {"count": 0, "total": 0, "resul ts": [], "echo": 1337},
136 get_params={ "echo": 1337 }) 114 get_params={ "echo": 1337 })
137 self.assertResponse(query_handler, "200 OK", {"count": 0, "total": 0, "resul ts": [], "echo": 0}, 115 self.assertResponse(query_handler, "200 OK", {"count": 0, "total": 0, "resul ts": [], "echo": 0},
138 get_params={ "echo": "naughty" }) 116 get_params={ "echo": "naughty" })
139 # Now let's submit some data so we can query it back out 117 # Now let's submit some data so we can query it back out
140 test_data = [json.loads(valid_data), json.loads(valid_data), json.loads(vali d_data)] 118 test_data = [json.loads(valid_data), json.loads(valid_data), json.loads(vali d_data)]
141 test_data[1]["filters"]["##Second-Filter|"] = test_data[1]["filters"].pop("| |example.com^") 119 test_data[1]["filters"]["##Second-Filter|"] = test_data[1]["filters"].pop("| |example.com^")
142 test_data[2]["filters"]["##Third-Filter|"] = test_data[2]["filters"].pop("|| example.com^") 120 test_data[2]["filters"]["##Third-Filter|"] = test_data[2]["filters"].pop("|| example.com^")
143 for data in test_data: 121 for data in test_data:
144 self.assertResponse(submit_handler, "200 OK", 122 self.assertResponse(submit_handler, "204 No Content",
145 REQUEST_METHOD="POST", body=json.dumps(data)) 123 REQUEST_METHOD="POST", body=json.dumps(data))
146 # Ordering parameters should be respected 124 # Ordering parameters should be respected
147 self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 6, 125 self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 6,
148 "results": [{"domain": "exampl e.com", 126 "results": [{"domain": "exampl e.com",
149 "filter": "||exam ple.com^", 127 "filter": "||exam ple.com^",
150 "frequency": 0}], "echo": 0}, 128 "frequency": 0}], "echo": 0},
151 get_params={ "order_by": "filter", "order": "desc", "tak e": "1" }) 129 get_params={ "order_by": "filter", "order": "desc", "tak e": "1" })
152 self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 6, 130 self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 6,
153 "results": [{"domain": "exampl e.com", 131 "results": [{"domain": "exampl e.com",
154 "filter": "##Seco nd-Filter|", 132 "filter": "##Seco nd-Filter|",
(...skipping 29 matching lines...) Expand all
184 "results": [{"domain": "exampl e.org", 162 "results": [{"domain": "exampl e.org",
185 "filter": "##Seco nd-Filter|", 163 "filter": "##Seco nd-Filter|",
186 "frequency": 4}, 164 "frequency": 4},
187 {"domain": "exampl e.com", 165 {"domain": "exampl e.com",
188 "filter": "##Thir d-Filter|", 166 "filter": "##Thir d-Filter|",
189 "frequency": 0}], "echo": 0}, 167 "frequency": 0}], "echo": 0},
190 get_params={ "skip": "2", "take": "2" }) 168 get_params={ "skip": "2", "take": "2" })
191 169
192 if __name__ == "__main__": 170 if __name__ == "__main__":
193 unittest.main() 171 unittest.main()
LEFTRIGHT

Powered by Google App Engine
This is Rietveld