| OLD | NEW | 
| (Empty) |  | 
 |    1 # coding: utf-8 | 
 |    2  | 
 |    3 # This file is part of the Adblock Plus web scripts, | 
 |    4 # Copyright (C) 2006-2015 Eyeo GmbH | 
 |    5 # | 
 |    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 | 
 |    8 # published by the Free Software Foundation. | 
 |    9 # | 
 |   10 # Adblock Plus is distributed in the hope that it will be useful, | 
 |   11 # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |   12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |   13 # GNU General Public License for more details. | 
 |   14 # | 
 |   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/>. | 
 |   17  | 
 |   18 import MySQLdb, StringIO, json, sys, unittest | 
 |   19 from urllib import urlencode | 
 |   20  | 
 |   21 import sitescripts.filterhits.db as db | 
 |   22 from sitescripts.filterhits.web.query import query_handler | 
 |   23 from sitescripts.filterhits.web.submit import submit as submit_handler | 
 |   24  | 
 |   25 valid_data = """{ | 
 |   26   "version": 1, | 
 |   27   "timeSincePush": 12345, | 
 |   28   "addonName": "adblockplus", | 
 |   29   "addonVersion": "2.3.4", | 
 |   30   "application": "firefox", | 
 |   31   "applicationVersion": "31", | 
 |   32   "platform": "gecko", | 
 |   33   "platformVersion": "31", | 
 |   34   "filters": { | 
 |   35     "||example.com^": { | 
 |   36       "firstParty": { | 
 |   37         "example.com": {"hits": 12, "latest": 1414817340948}, | 
 |   38         "example.org": {"hits": 4, "latest": 1414859271125} | 
 |   39       }, | 
 |   40       "thirdParty": { | 
 |   41         "example.com": {"hits": 5, "latest": 1414916268769} | 
 |   42       }, | 
 |   43       "subscriptions": ["EasyList", "EasyList Germany+EasyList"] | 
 |   44     } | 
 |   45   } | 
 |   46 }""" | 
 |   47  | 
 |   48 class APITestCase(unittest.TestCase): | 
 |   49   def clear_rows(self): | 
 |   50     if self.db: | 
 |   51       db.write(self.db, (("DELETE FROM filters",), | 
 |   52                          ("DELETE FROM geometrical_mean",))) | 
 |   53  | 
 |   54   def setUp(self): | 
 |   55     try: | 
 |   56       db.testing = True | 
 |   57       self.db = db.connect() | 
 |   58     except MySQLdb.Error: | 
 |   59       self.db = None | 
 |   60     self.clear_rows() | 
 |   61  | 
 |   62   def tearDown(self): | 
 |   63     if self.db: | 
 |   64       self.clear_rows() | 
 |   65       self.db.close() | 
 |   66       self.db = None | 
 |   67  | 
 |   68   def assertResponse(self, handler, expected_response, expected_result=None, exp
     ected_headers=None, **environ): | 
 |   69     def check_response(response, headers): | 
 |   70       self.assertEqual(response, expected_response) | 
 |   71       if not expected_headers is None: | 
 |   72         self.assertEqual(headers, expected_headers) | 
 |   73  | 
 |   74     if "body" in environ: | 
 |   75       environ["CONTENT_LENGTH"] = len(environ["body"]) | 
 |   76       environ["wsgi.input"] = StringIO.StringIO(environ["body"]) | 
 |   77       del environ["body"] | 
 |   78  | 
 |   79     if "get_params" in environ: | 
 |   80       environ["QUERY_STRING"] = urlencode(environ["get_params"]) | 
 |   81       del environ["get_params"] | 
 |   82  | 
 |   83     environ["wsgi.errors"] = sys.stderr | 
 |   84     result = handler(environ, check_response) | 
 |   85     if not expected_result is None: | 
 |   86       self.assertEqual(json.loads("".join(result)), expected_result) | 
 |   87  | 
 |   88   def test_submit(self): | 
 |   89     self.assertEqual(len(db.query(self.db, "SELECT * FROM geometrical_mean")), 0
     ) | 
 |   90     self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 0) | 
 |   91     # Ensure missing or invalid JSON results in an error | 
 |   92     self.assertResponse(submit_handler, "400 Processing Error", | 
 |   93                         REQUEST_METHOD="POST", body="") | 
 |   94     self.assertResponse(submit_handler, "400 Processing Error", | 
 |   95                         REQUEST_METHOD="POST", body="Oops...") | 
 |   96     self.assertResponse(submit_handler, "400 Processing Error", | 
 |   97                         REQUEST_METHOD="POST", body="{123:]") | 
 |   98     self.assertResponse(submit_handler, "400 Processing Error", | 
 |   99                         REQUEST_METHOD="POST", body="1") | 
 |  100     self.assertEqual(len(db.query(self.db, "SELECT * FROM geometrical_mean")), 0
     ) | 
 |  101     self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 0) | 
 |  102     # Ensure even an empty object, or one with the wrong fields returns OK | 
 |  103     self.assertResponse(submit_handler, "200 OK", | 
 |  104                         REQUEST_METHOD="POST", body="{}") | 
 |  105     self.assertResponse(submit_handler, "200 OK", | 
 |  106                         REQUEST_METHOD="POST", body="{\"hello\": \"world\"}") | 
 |  107     self.assertEqual(len(db.query(self.db, "SELECT * FROM geometrical_mean")), 0
     ) | 
 |  108     self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 0) | 
 |  109     # Now some actually valid data | 
 |  110     self.assertResponse(submit_handler, "200 OK", | 
 |  111                         REQUEST_METHOD="POST", body=valid_data) | 
 |  112     self.assertEqual(len(db.query(self.db, "SELECT * FROM geometrical_mean")), 2
     ) | 
 |  113     self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 1) | 
 |  114     # Now make sure apparently valid data with timestamps that cause geometrical | 
 |  115     # mean calculations to fail with MySQL errors return OK but don't change DB | 
 |  116     invalid_data = json.loads(valid_data) | 
 |  117     invalid_data["filters"]["||example.com^"]["firstParty"]["example.com"]["late
     st"] = 3 | 
 |  118     invalid_data = json.dumps(invalid_data) | 
 |  119     self.assertResponse(submit_handler, "200 OK", | 
 |  120                         REQUEST_METHOD="POST", body=invalid_data) | 
 |  121     self.assertEqual(len(db.query(self.db, "SELECT * FROM geometrical_mean")), 2
     ) | 
 |  122     self.assertEqual(len(db.query(self.db, "SELECT * FROM filters")), 1) | 
 |  123  | 
 |  124   def test_query(self): | 
 |  125     # Basic query with no data, should return OK | 
 |  126     self.assertResponse(query_handler, "200 OK", {"count": 0, "total": 0, "resul
     ts": [], "echo": 0}) | 
 |  127     # If echo parameter is passed and is integer it should be returned | 
 |  128     self.assertResponse(query_handler, "200 OK", {"count": 0, "total": 0, "resul
     ts": [], "echo": 1337}, | 
 |  129                         get_params={ "echo": 1337 }) | 
 |  130     self.assertResponse(query_handler, "200 OK", {"count": 0, "total": 0, "resul
     ts": [], "echo": 0}, | 
 |  131                         get_params={ "echo": "naughty" }) | 
 |  132     # Now let's submit some data so we can query it back out | 
 |  133     test_data = [json.loads(valid_data), json.loads(valid_data), json.loads(vali
     d_data)] | 
 |  134     test_data[1]["filters"]["##Second-Filter|"] = test_data[1]["filters"].pop("|
     |example.com^") | 
 |  135     test_data[2]["filters"]["##Third-Filter|"] = test_data[2]["filters"].pop("||
     example.com^") | 
 |  136     for data in test_data: | 
 |  137       self.assertResponse(submit_handler, "200 OK", | 
 |  138                           REQUEST_METHOD="POST", body=json.dumps(data)) | 
 |  139     # Ordering parameters should be respected | 
 |  140     self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 6, | 
 |  141                                                   "results": [{'domain': 'exampl
     e.com', | 
 |  142                                                                'filter': '||exam
     ple.com^', | 
 |  143                                                                'hits': 0}], "ech
     o": 0}, | 
 |  144                         get_params={ "order_by": "filter", "order": "desc", "tak
     e": "1" }) | 
 |  145     self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 6, | 
 |  146                                                   "results": [{'domain': 'exampl
     e.com', | 
 |  147                                                                'filter': '##Seco
     nd-Filter|', | 
 |  148                                                                'hits': 0}], "ech
     o": 0}, | 
 |  149                         get_params={ "order_by": "filter", "order": "asc", "take
     ": "1" }) | 
 |  150     # As should filtering parameters | 
 |  151     self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 3, | 
 |  152                                                   "results": [{'domain': 'exampl
     e.com', | 
 |  153                                                                'filter': '##Thir
     d-Filter|', | 
 |  154                                                                'hits': 0}], "ech
     o": 0}, | 
 |  155                         get_params={ "domain": "example.com", "take": "1" }) | 
 |  156     self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 2, | 
 |  157                                                   "results": [{'domain': 'exampl
     e.org', | 
 |  158                                                                'filter': '##Thir
     d-Filter|', | 
 |  159                                                                'hits': 4}], "ech
     o": 0}, | 
 |  160                         get_params={ "filter": "Third", "take": 1 }) | 
 |  161     self.assertResponse(query_handler, "200 OK", {"count": 1, "total": 1, | 
 |  162                                                   "results": [{'domain': 'exampl
     e.com', | 
 |  163                                                                'filter': '##Thir
     d-Filter|', | 
 |  164                                                                'hits': 0}], "ech
     o": 0}, | 
 |  165                         get_params={ "domain": "example.com", "filter": "Third",
      "take": "1" }) | 
 |  166     # ... and pagination parameters | 
 |  167     self.maxDiff = None | 
 |  168     self.assertResponse(query_handler, "200 OK", {"count": 2, "total": 6, | 
 |  169                                                   "results": [{'domain': 'exampl
     e.org', | 
 |  170                                                                'filter': '||exam
     ple.com^', | 
 |  171                                                                'hits': 4}, | 
 |  172                                                               {'domain': 'exampl
     e.org', | 
 |  173                                                                'filter': '##Seco
     nd-Filter|', | 
 |  174                                                                'hits': 4}], "ech
     o": 0}, | 
 |  175                         get_params={ "skip": "1", "take": "2" }) | 
 |  176     self.assertResponse(query_handler, "200 OK", {"count": 2, "total": 6, | 
 |  177                                                   "results": [{'domain': 'exampl
     e.org', | 
 |  178                                                                'filter': '##Seco
     nd-Filter|', | 
 |  179                                                                'hits': 4}, | 
 |  180                                                               {'domain': 'exampl
     e.com', | 
 |  181                                                                'filter': '##Thir
     d-Filter|', | 
 |  182                                                                'hits': 0}], "ech
     o": 0}, | 
 |  183                         get_params={ "skip": "2", "take": "2" }) | 
 |  184  | 
 |  185 if __name__ == '__main__': | 
 |  186   unittest.main() | 
| OLD | NEW |