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: Create temporary log directory with tempfile module for tests. Created March 30, 2015, 7 p.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 MySQLdb
19 import StringIO
20 import json 18 import json
21 import sys 19 import sys
20 import StringIO
22 import unittest 21 import unittest
23 from urllib import urlencode 22 from urllib import urlencode
24 23
25 from sitescripts.filterhits.test import test_helpers 24 from sitescripts.filterhits.test import test_helpers
26 from sitescripts.filterhits import db 25 from sitescripts.filterhits import db
27 from sitescripts.filterhits.web.query import query_handler 26 from sitescripts.filterhits.web.query import query_handler
28 from sitescripts.filterhits.web.submit import submit as submit_handler 27 from sitescripts.filterhits.web.submit import submit as submit_handler
29 28
30 valid_data = """{ 29 valid_data = """{
31 "version": 1, 30 "version": 1,
(...skipping 11 matching lines...) Expand all
43 "example.org": {"hits": 4, "latest": 1414859271125} 42 "example.org": {"hits": 4, "latest": 1414859271125}
44 }, 43 },
45 "thirdParty": { 44 "thirdParty": {
46 "example.com": {"hits": 5, "latest": 1414916268769} 45 "example.com": {"hits": 5, "latest": 1414916268769}
47 }, 46 },
48 "subscriptions": ["EasyList", "EasyList Germany+EasyList"] 47 "subscriptions": ["EasyList", "EasyList Germany+EasyList"]
49 } 48 }
50 } 49 }
51 }""" 50 }"""
52 51
53 class APITestCase(unittest.TestCase): 52 class APITestCase(test_helpers.FilterhitsTestCase):
54 def clear_rows(self):
55 if self.db:
56 db.write(self.db, (("DELETE FROM filters",),
57 ("DELETE FROM frequencies",)))
58
59 def setUp(self):
60 self.config = test_helpers.setup_config()
61 try:
62 self.db = db.connect()
63 except MySQLdb.Error:
64 self.db = None
65 self.clear_rows()
66
67 def tearDown(self):
68 test_helpers.restore_config()
69 if self.db:
70 self.clear_rows()
71 self.db.close()
72 self.db = None
73
74 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):
75 def check_response(response, headers): 54 def check_response(response, headers):
76 self.assertEqual(response, expected_response) 55 self.assertEqual(response, expected_response)
77 if not expected_headers is None: 56 if not expected_headers is None:
78 self.assertEqual(headers, expected_headers) 57 self.assertEqual(headers, expected_headers)
79 58
80 if "body" in environ: 59 if "body" in environ:
81 environ["CONTENT_LENGTH"] = len(environ["body"]) 60 environ["CONTENT_LENGTH"] = len(environ["body"])
82 environ["wsgi.input"] = StringIO.StringIO(environ["body"]) 61 environ["wsgi.input"] = StringIO.StringIO(environ["body"])
83 del environ["body"] 62 del environ["body"]
(...skipping 14 matching lines...) Expand all
98 self.assertResponse(submit_handler, "400 Processing Error", 77 self.assertResponse(submit_handler, "400 Processing Error",
99 REQUEST_METHOD="POST", body="") 78 REQUEST_METHOD="POST", body="")
100 self.assertResponse(submit_handler, "400 Processing Error", 79 self.assertResponse(submit_handler, "400 Processing Error",
101 REQUEST_METHOD="POST", body="Oops...") 80 REQUEST_METHOD="POST", body="Oops...")
102 self.assertResponse(submit_handler, "400 Processing Error", 81 self.assertResponse(submit_handler, "400 Processing Error",
103 REQUEST_METHOD="POST", body="{123:]") 82 REQUEST_METHOD="POST", body="{123:]")
104 self.assertResponse(submit_handler, "400 Processing Error", 83 self.assertResponse(submit_handler, "400 Processing Error",
105 REQUEST_METHOD="POST", body="1") 84 REQUEST_METHOD="POST", body="1")
106 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 0) 85 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 0)
107 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 0) 86 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 0)
108 # 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
109 self.assertResponse(submit_handler, "200 OK", 88 self.assertResponse(submit_handler, "204 No Content",
110 REQUEST_METHOD="POST", body="{}") 89 REQUEST_METHOD="POST", body="{}")
111 self.assertResponse(submit_handler, "200 OK", 90 self.assertResponse(submit_handler, "204 No Content",
112 REQUEST_METHOD="POST", body="{\"hello\": \"world\"}") 91 REQUEST_METHOD="POST", body="{\"hello\": \"world\"}")
113 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 0) 92 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 0)
114 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 0) 93 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 0)
115 # Now some actually valid data 94 # Now some actually valid data
116 self.assertResponse(submit_handler, "200 OK", 95 self.assertResponse(submit_handler, "204 No Content",
117 REQUEST_METHOD="POST", body=valid_data) 96 REQUEST_METHOD="POST", body=valid_data)
118 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 2) 97 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 2)
119 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 1) 98 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 1)
120 # Now make sure apparently valid data with timestamps that cause geometrical 99 # Now make sure apparently valid data with timestamps that cause geometrical
121 # 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
122 invalid_data = json.loads(valid_data) 101 invalid_data = json.loads(valid_data)
123 invalid_data["filters"]["||example.com^"]["firstParty"]["example.com"]["late st"] = 3 102 invalid_data["filters"]["||example.com^"]["firstParty"]["example.com"]["late st"] = 3
124 invalid_data = json.dumps(invalid_data) 103 invalid_data = json.dumps(invalid_data)
125 self.assertResponse(submit_handler, "200 OK", 104 self.assertResponse(submit_handler, "204 No Content",
126 REQUEST_METHOD="POST", body=invalid_data) 105 REQUEST_METHOD="POST", body=invalid_data)
127 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 2) 106 self.assertEqual(len(db.query(self.db, "SELECT * FROM frequencies")), 2)
128 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 1) 107 self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 1)
129 108
130 def test_query(self): 109 def test_query(self):
131 # Basic query with no data, should return OK 110 # Basic query with no data, should return successfully
132 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})
133 # 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
134 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},
135 get_params={ "echo": 1337 }) 114 get_params={ "echo": 1337 })
136 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},
137 get_params={ "echo": "naughty" }) 116 get_params={ "echo": "naughty" })
138 # 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
139 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)]
140 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^")
141 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^")
142 for data in test_data: 121 for data in test_data:
143 self.assertResponse(submit_handler, "200 OK", 122 self.assertResponse(submit_handler, "204 No Content",
144 REQUEST_METHOD="POST", body=json.dumps(data)) 123 REQUEST_METHOD="POST", body=json.dumps(data))
145 # Ordering parameters should be respected 124 # Ordering parameters should be respected
146 self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 6, 125 self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 6,
147 "results": [{'domain': 'exampl e.com', 126 "results": [{"domain": "exampl e.com",
148 'filter': '||exam ple.com^', 127 "filter": "||exam ple.com^",
149 'frequency': 0}], "echo": 0}, 128 "frequency": 0}], "echo": 0},
150 get_params={ "order_by": "filter", "order": "desc", "tak e": "1" }) 129 get_params={ "order_by": "filter", "order": "desc", "tak e": "1" })
151 self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 6, 130 self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 6,
152 "results": [{'domain': 'exampl e.com', 131 "results": [{"domain": "exampl e.com",
153 'filter': '##Seco nd-Filter|', 132 "filter": "##Seco nd-Filter|",
154 'frequency': 0}], "echo": 0}, 133 "frequency": 0}], "echo": 0},
155 get_params={ "order_by": "filter", "order": "asc", "take ": "1" }) 134 get_params={ "order_by": "filter", "order": "asc", "take ": "1" })
156 # As should filtering parameters 135 # As should filtering parameters
157 self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 3, 136 self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 3,
158 "results": [{'domain': 'exampl e.com', 137 "results": [{"domain": "exampl e.com",
159 'filter': '##Thir d-Filter|', 138 "filter": "##Thir d-Filter|",
160 'frequency': 0}], "echo": 0}, 139 "frequency": 0}], "echo": 0},
161 get_params={ "domain": "example.com", "take": "1" }) 140 get_params={ "domain": "example.com", "take": "1" })
162 self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 2, 141 self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 2,
163 "results": [{'domain': 'exampl e.org', 142 "results": [{"domain": "exampl e.org",
164 'filter': '##Thir d-Filter|', 143 "filter": "##Thir d-Filter|",
165 'frequency': 4}], "echo": 0}, 144 "frequency": 4}], "echo": 0},
166 get_params={ "filter": "Third", "take": 1 }) 145 get_params={ "filter": "Third", "take": 1 })
167 self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 1, 146 self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 1,
168 "results": [{'domain': 'exampl e.com', 147 "results": [{"domain": "exampl e.com",
169 'filter': '##Thir d-Filter|', 148 "filter": "##Thir d-Filter|",
170 'frequency': 0}], "echo": 0}, 149 "frequency": 0}], "echo": 0},
171 get_params={ "domain": "example.com", "filter": "Third", "take": "1" }) 150 get_params={ "domain": "example.com", "filter": "Third", "take": "1" })
172 # ... and pagination parameters 151 # ... and pagination parameters
173 self.maxDiff = None 152 self.maxDiff = None
174 self.assertResponse(query_handler, "200 OK", {"count": 2, "total": 6, 153 self.assertResponse(query_handler, "200 OK", {"count": 2, "total": 6,
175 "results": [{'domain': 'exampl e.org', 154 "results": [{"domain": "exampl e.org",
176 'filter': '||exam ple.com^', 155 "filter": "||exam ple.com^",
177 'frequency': 4}, 156 "frequency": 4},
178 {'domain': 'exampl e.org', 157 {"domain": "exampl e.org",
179 'filter': '##Seco nd-Filter|', 158 "filter": "##Seco nd-Filter|",
180 'frequency': 4}], "echo": 0}, 159 "frequency": 4}], "echo": 0},
181 get_params={ "skip": "1", "take": "2" }) 160 get_params={ "skip": "1", "take": "2" })
182 self.assertResponse(query_handler, "200 OK", {"count": 2, "total": 6, 161 self.assertResponse(query_handler, "200 OK", {"count": 2, "total": 6,
183 "results": [{'domain': 'exampl e.org', 162 "results": [{"domain": "exampl e.org",
184 'filter': '##Seco nd-Filter|', 163 "filter": "##Seco nd-Filter|",
185 'frequency': 4}, 164 "frequency": 4},
186 {'domain': 'exampl e.com', 165 {"domain": "exampl e.com",
187 'filter': '##Thir d-Filter|', 166 "filter": "##Thir d-Filter|",
188 'frequency': 0}], "echo": 0}, 167 "frequency": 0}], "echo": 0},
189 get_params={ "skip": "2", "take": "2" }) 168 get_params={ "skip": "2", "take": "2" })
190 169
191 if __name__ == '__main__': 170 if __name__ == "__main__":
192 unittest.main() 171 unittest.main()
LEFTRIGHT

Powered by Google App Engine
This is Rietveld