def test_healthcheck(self, mocked_elasticsearch, rget): searches = [] def mocked_supersearch_get(**params): searches.append(params) eq_(params['product'], [settings.DEFAULT_PRODUCT]) eq_(params['_results_number'], 1) eq_(params['_columns'], ['uuid']) return { 'hits': [ {'uuid': '12345'}, ], 'facets': [], 'total': 30002, 'errors': [], } SuperSearch.implementation().get.side_effect = ( mocked_supersearch_get ) def mocked_requests_get(url, **params): return Response(True) rget.side_effect = mocked_requests_get url = reverse('monitoring:healthcheck') response = self.client.get(url) eq_(response.status_code, 200) eq_(json.loads(response.content)['ok'], True) assert len(searches) == 1
def test_parameters(self): def mocked_supersearch_get(**params): # Verify that all expected parameters are in the URL. ok_("product" in params) ok_("WaterWolf" in params["product"]) ok_("NightTrain" in params["product"]) ok_("address" in params) ok_("0x0" in params["address"]) ok_("0xa" in params["address"]) ok_("reason" in params) ok_("^hello" in params["reason"]) ok_("$thanks" in params["reason"]) ok_("java_stack_trace" in params) ok_("Exception" in params["java_stack_trace"]) return {"hits": [], "facets": "", "total": 0} SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse("signature:signature_reports") response = self.client.get( url, { "signature": DUMB_SIGNATURE, "product": ["WaterWolf", "NightTrain"], "address": ["0x0", "0xa"], "reason": ["^hello", "$thanks"], "java_stack_trace": "Exception", }, ) eq_(response.status_code, 200)
def test_assert_supersearch_errors(self): searches = [] def mocked_supersearch_get(**params): searches.append(params) eq_(params['product'], [settings.DEFAULT_PRODUCT]) eq_(params['_results_number'], 1) eq_(params['_columns'], ['uuid']) return { 'hits': [ {'uuid': '12345'}, ], 'facets': [], 'total': 320, 'errors': ['bad'], } SuperSearch.implementation().get.side_effect = ( mocked_supersearch_get ) assert_raises( AssertionError, assert_supersearch_no_errors ) assert len(searches) == 1
def test_topcrasher_modes(self, rpost): rpost.side_effect = mocked_post_123 def mocked_supersearch_get(**params): return {"hits": [], "facets": {"signature": []}, "total": 0} SuperSearch.implementation().get.side_effect = mocked_supersearch_get now = datetime.datetime.utcnow() today = now.replace(hour=0, minute=0, second=0, microsecond=0) timestr = "%Y-%m-%d %H:%M:%S" now = now.strftime(timestr) today = today.strftime(timestr) with freezegun.freeze_time(now, tz_offset=0): # By default, it returns "real-time" data. response = self.client.get(self.base_url, {"product": "WaterWolf", "version": "19.0"}) eq_(response.status_code, 200) ok_(now in response.content, now) ok_(today not in response.content) # Now test the "day time" data. response = self.client.get( self.base_url, {"product": "WaterWolf", "version": "19.0", "_tcbs_mode": "byday"} ) eq_(response.status_code, 200) ok_(today in response.content) ok_(now not in response.content)
def test_parameters(self): def mocked_supersearch_get(**params): # Verify that all expected parameters are in the URL. ok_('product' in params) ok_('WaterWolf' in params['product']) ok_('NightTrain' in params['product']) ok_('address' in params) ok_('0x0' in params['address']) ok_('0xa' in params['address']) ok_('reason' in params) ok_('^hello' in params['reason']) ok_('$thanks' in params['reason']) ok_('java_stack_trace' in params) ok_('Exception' in params['java_stack_trace']) return {"hits": [], "facets": "", "total": 0} SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('signature:signature_reports') response = self.client.get( url, { 'signature': DUMB_SIGNATURE, 'product': ['WaterWolf', 'NightTrain'], 'address': ['0x0', '0xa'], 'reason': ['^hello', '$thanks'], 'java_stack_trace': 'Exception', }) eq_(response.status_code, 200)
def test_heartbeat(self, mocked_elasticsearch, rget): searches = [] def mocked_supersearch_get(**params): searches.append(params) assert params["product"] == [settings.DEFAULT_PRODUCT] assert params["_results_number"] == 1 assert params["_columns"] == ["uuid"] return { "hits": [{ "uuid": "12345" }], "facets": [], "total": 30002, "errors": [], } SuperSearch.implementation().get.side_effect = mocked_supersearch_get def mocked_requests_get(url, **params): return Response(True) rget.side_effect = mocked_requests_get # Verify the __heartbeat__ endpoint url = reverse("monitoring:dockerflow_heartbeat") response = self.client.get(url) assert response.status_code == 200 assert json.loads(response.content)["ok"] is True assert len(searches) == 1
def test_healthcheck(self, mocked_elasticsearch, rget): searches = [] def mocked_supersearch_get(**params): searches.append(params) assert params['product'] == [settings.DEFAULT_PRODUCT] assert params['_results_number'] == 1 assert params['_columns'] == ['uuid'] return { 'hits': [ {'uuid': '12345'}, ], 'facets': [], 'total': 30002, 'errors': [], } SuperSearch.implementation().get.side_effect = mocked_supersearch_get def mocked_requests_get(url, **params): return Response(True) rget.side_effect = mocked_requests_get url = reverse('monitoring:healthcheck') response = self.client.get(url) assert response.status_code == 200 assert json.loads(response.content)['ok'] is True assert len(searches) == 1
def test_topcrasher_modes(self, rpost): rpost.side_effect = mocked_post_123 def mocked_supersearch_get(**params): return {'hits': [], 'facets': {'signature': []}, 'total': 0} SuperSearch.implementation().get.side_effect = mocked_supersearch_get now = datetime.datetime.utcnow() today = now.replace(hour=0, minute=0, second=0, microsecond=0) timestr = '%Y-%m-%d %H:%M:%S' now = now.strftime(timestr) today = today.strftime(timestr) with freezegun.freeze_time(now, tz_offset=0): # By default, it returns "real-time" data. response = self.client.get(self.base_url, { 'product': 'WaterWolf', 'version': '19.0', }) eq_(response.status_code, 200) ok_(now in response.content, now) ok_(today not in response.content) # Now test the "day time" data. response = self.client.get(self.base_url, { 'product': 'WaterWolf', 'version': '19.0', '_tcbs_mode': 'byday', }) eq_(response.status_code, 200) ok_(today in response.content) ok_(now not in response.content)
def test_search_results_pagination(self, rpost): """Test that the pagination of results works as expected. """ def mocked_post(**options): assert 'bugs' in options['url'], options['url'] return Response(""" {"hits": [], "total": 0} """) rpost.side_effect = mocked_post def mocked_supersearch_get(**params): assert '_columns' in params # Make sure a negative page does not lead to negative offset value. # But instead it is considered as the page 1 and thus is not added. ok_('_results_offset' not in params) hits = [] for i in range(140): hits.append({ "signature": "nsASDOMWindowEnumerator::GetNext()", "date": "2017-01-31T23:12:57", "uuid": i, "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": 888981 }) return { "hits": self.only_certain_columns(hits, params['_columns']), "facets": "", "total": len(hits) } SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('supersearch.search_results') response = self.client.get(url, { '_columns': ['version'], '_facets': ['platform'] }) eq_(response.status_code, 200) ok_('140' in response.content) # Check that the pagination URL contains all three expected parameters. doc = pyquery.PyQuery(response.content) next_page_url = str(doc('.pagination a').eq(0)) ok_('_facets=platform' in next_page_url) ok_('_columns=version' in next_page_url) ok_('page=2' in next_page_url) ok_('#crash-reports' in next_page_url) # Test that a negative page value does not break it. response = self.client.get(url, {'page': '-1'}) eq_(response.status_code, 200)
def test_signature_reports_pagination(self): """Test that the pagination of results works as expected. """ def mocked_supersearch_get(**params): assert '_columns' in params # Make sure a negative page does not lead to negative offset value. # But instead it is considered as the page 1 and thus is not added. eq_(params.get('_results_offset'), 0) hits = [] for i in range(140): hits.append({ "signature": "nsASDOMWindowEnumerator::GetNext()", "date": "2017-01-31T23:12:57", "uuid": i, "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": 888981 }) return { "hits": self.only_certain_columns(hits, params['_columns']), "facets": "", "total": len(hits) } SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('signature:signature_reports') response = self.client.get( url, { 'signature': DUMB_SIGNATURE, 'product': ['WaterWolf'], '_columns': ['platform'] } ) eq_(response.status_code, 200) ok_('140' in response.content) # Check that the pagination URL contains all three expected parameters. doc = pyquery.PyQuery(response.content) next_page_url = str(doc('.pagination a').eq(0)) ok_('product=WaterWolf' in next_page_url) ok_('_columns=platform' in next_page_url) ok_('page=2' in next_page_url) # Test that a negative page value does not break it. response = self.client.get(url, { 'signature': DUMB_SIGNATURE, 'page': '-1', }) eq_(response.status_code, 200)
def test_signature_graphs(self): def mocked_supersearch_get(**params): ok_("signature" in params) eq_(params["signature"], ["=" + DUMB_SIGNATURE]) ok_("_histogram.date" in params) ok_("_facets" in params) if "product" in params["_facets"]: return { "hits": [], "total": 4, "facets": { "product": [{"count": 4, "term": "WaterWolf"}], "histogram_date": [ { "count": 2, "term": "2015-08-05T00:00:00+00:00", "facets": {"product": [{"count": 2, "term": "WaterWolf"}]}, }, { "count": 2, "term": "2015-08-06T00:00:00+00:00", "facets": {"product": [{"count": 2, "term": "WaterWolf"}]}, }, ], }, } return {"hits": [], "total": 0, "facets": {"platform": [], "signature": [], "histogram_date": []}} SuperSearch.implementation().get.side_effect = mocked_supersearch_get # Test with no results url = reverse("signature:signature_graphs", args=("platform",)) response = self.client.get(url, {"signature": DUMB_SIGNATURE}) eq_(response.status_code, 200) ok_("application/json" in response["content-type"]) struct = json.loads(response.content) ok_("aggregates" in struct) eq_(len(struct["aggregates"]), 0) ok_("term_counts" in struct) eq_(len(struct["term_counts"]), 0) # Test with results url = reverse("signature:signature_graphs", args=("product",)) response = self.client.get(url, {"signature": DUMB_SIGNATURE}) eq_(response.status_code, 200) ok_("application/json" in response["content-type"]) struct = json.loads(response.content) ok_("aggregates" in struct) eq_(len(struct["aggregates"]), 2) ok_("term_counts" in struct) eq_(len(struct["term_counts"]), 1)
def test_signature_comments_pagination(self): """Test that the pagination of comments works as expected. """ def mocked_supersearch_get(**params): assert '_columns' in params if params.get('_results_offset') != 0: hits_range = range(100, 140) else: hits_range = range(100) hits = [] for i in hits_range: hits.append({ "date": "2017-01-31T23:12:57", "uuid": i, "user_comments": "hi", }) return { "hits": self.only_certain_columns(hits, params['_columns']), "total": 140 } SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('signature:signature_comments') response = self.client.get( url, { 'signature': DUMB_SIGNATURE, 'product': ['WaterWolf'], } ) eq_(response.status_code, 200) ok_('140' in response.content) ok_('99' in response.content) ok_('139' not in response.content) # Check that the pagination URL contains all expected parameters. doc = pyquery.PyQuery(response.content) next_page_url = str(doc('.pagination a').eq(0)) ok_('product=WaterWolf' in next_page_url) ok_('page=2' in next_page_url) response = self.client.get(url, { 'signature': DUMB_SIGNATURE, 'page': '2', }) eq_(response.status_code, 200) ok_('140' in response.content) ok_('99' not in response.content) ok_('139' in response.content)
def test_search_custom(self): def mocked_supersearch_get(**params): return None SuperSearch.implementation().get.side_effect = mocked_supersearch_get self.create_custom_query_perm() url = reverse('supersearch.search_custom') response = self.client.get(url) eq_(response.status_code, 200) ok_('Run a search to get some results' in response.content)
def test_signature_aggregation(self): def mocked_supersearch_get(**params): ok_('signature' in params) eq_(params['signature'], ['=' + DUMB_SIGNATURE]) ok_('_facets' in params) if 'product' in params['_facets']: return { "hits": [], "facets": { "product": [ { "term": "windows", "count": 42, }, { "term": "linux", "count": 1337, }, { "term": "mac", "count": 3, }, ] }, "total": 1382 } # the default return {"hits": [], "facets": {"platform": []}, "total": 0} SuperSearch.implementation().get.side_effect = mocked_supersearch_get # Test with no results. url = reverse('signature:signature_aggregation', args=('platform', )) response = self.client.get(url, {'signature': DUMB_SIGNATURE}) eq_(response.status_code, 200) ok_('Product' not in response.content) ok_('No results were found' in response.content) # Test with results. url = reverse('signature:signature_aggregation', args=('product', )) response = self.client.get(url, {'signature': DUMB_SIGNATURE}) eq_(response.status_code, 200) ok_('Product' in response.content) ok_('1337' in response.content) ok_('linux' in response.content) ok_(str(1337 / 1382 * 100) in response.content) ok_('windows' in response.content) ok_('mac' in response.content)
def test_signature_summary_with_many_hexes(self, rget): def mocked_get(url, params, **options): if '/graphics_devices' in url: ok_(len(params['vendor_hex']) <= 50) ok_(len(params['adapter_hex']) <= 50) return Response({'hits': [], 'total': 0}) raise NotImplementedError(url) rget.side_effect = mocked_get def mocked_supersearch_get(**params): ok_('signature' in params) eq_(params['signature'], ['=' + DUMB_SIGNATURE]) adapters = [{ 'term': '0x{0:0>4}'.format(i), 'count': 1 } for i in range(50)] vendors = [{ 'term': '0x{0:0>4}'.format(i), 'count': 50, 'facets': { 'adapter_device_id': adapters } } for i in range(3)] res = { 'hits': [], 'total': 4, 'facets': { 'adapter_vendor_id': vendors, } } return res SuperSearch.implementation().get.side_effect = (mocked_supersearch_get) # Test with no results url = reverse('signature:signature_summary') response = self.client.get( url, { 'signature': DUMB_SIGNATURE, 'product': 'WaterWolf', 'version': '1.0', }) eq_(response.status_code, 200) # There are 150 different hexes, there should be 3 calls to the API. eq_(rget.call_count, 3)
def test_signature_comments_pagination(self): """Test that the pagination of comments works as expected. """ def mocked_supersearch_get(**params): assert '_columns' in params if '_results_offset' in params: hits_range = range(100, 140) else: hits_range = range(100) hits = [] for i in hits_range: hits.append({ "date": "2017-01-31T23:12:57", "uuid": i, "user_comments": "hi", }) return { "hits": self.only_certain_columns(hits, params['_columns']), "total": 140 } SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('signature:signature_comments') response = self.client.get(url, { 'signature': DUMB_SIGNATURE, 'product': ['WaterWolf'], }) eq_(response.status_code, 200) ok_('140' in response.content) ok_('99' in response.content) ok_('139' not in response.content) # Check that the pagination URL contains all expected parameters. doc = pyquery.PyQuery(response.content) next_page_url = str(doc('.pagination a').eq(0)) ok_('product=WaterWolf' in next_page_url) ok_('page=2' in next_page_url) response = self.client.get(url, { 'signature': DUMB_SIGNATURE, 'page': '2', }) eq_(response.status_code, 200) ok_('140' in response.content) ok_('99' not in response.content) ok_('139' in response.content)
def test_search_results_parameters(self, rpost): def mocked_post(**options): assert 'bugs' in options['url'], options['url'] return Response({ "hits": [], "total": 0 }) rpost.side_effect = mocked_post def mocked_supersearch_get(**params): # Verify that all expected parameters are in the URL. ok_('product' in params) ok_('WaterWolf' in params['product']) ok_('NightTrain' in params['product']) ok_('address' in params) ok_('0x0' in params['address']) ok_('0xa' in params['address']) ok_('reason' in params) ok_('^hello' in params['reason']) ok_('$thanks' in params['reason']) ok_('java_stack_trace' in params) ok_('Exception' in params['java_stack_trace']) return { "hits": [], "facets": "", "total": 0 } SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('supersearch.search_results') response = self.client.get( url, { 'product': ['WaterWolf', 'NightTrain'], 'address': ['0x0', '0xa'], 'reason': ['^hello', '$thanks'], 'java_stack_trace': 'Exception', } ) eq_(response.status_code, 200)
def test_topcrasher_without_any_signatures(self, rget, rpost): url = self.base_url + '?product=WaterWolf&version=19.0' response = self.client.get(self.base_url, { 'product': 'WaterWolf', }) ok_(url in response['Location']) rpost.side_effect = mocked_post_123 def mocked_get(url, params, **options): if '/products' in url: return Response(""" { "hits": [ { "is_featured": true, "throttle": 1.0, "end_date": "string", "start_date": "integer", "build_type": "string", "product": "WaterWolf", "version": "19.0", "has_builds": true }], "total": "1" } """) raise NotImplementedError(url) rget.side_effect = mocked_get def mocked_supersearch_get(**params): return { 'hits': [], 'facets': { 'signature': [] }, 'total': 0 } SuperSearch.implementation().get.side_effect = mocked_supersearch_get response = self.client.get(self.base_url, { 'product': 'WaterWolf', 'version': '19.0', }) eq_(response.status_code, 200)
def test_search_results_ratelimited(self): def mocked_supersearch_get(**params): return {"hits": [], "facets": [], "total": 0} SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('supersearch.search_results') limit = int(re.findall('(\d+)', settings.RATELIMIT_SUPERSEARCH)[0]) params = {'product': 'WaterWolf'} # double to avoid https://bugzilla.mozilla.org/show_bug.cgi?id=1148470 for i in range(limit * 2): self.client.get(url, params) response = self.client.get(url, params, HTTP_X_REQUESTED_WITH='XMLHttpRequest') eq_(response.status_code, 429) eq_(response.content, 'Too Many Requests') eq_(response['content-type'], 'text/plain')
def test_signature_aggregation(self): def mocked_supersearch_get(**params): ok_("signature" in params) eq_(params["signature"], ["=" + DUMB_SIGNATURE]) ok_("_facets" in params) if "product" in params["_facets"]: return { "hits": [], "facets": { "product": [ {"term": "windows", "count": 42}, {"term": "linux", "count": 1337}, {"term": "mac", "count": 3}, ] }, "total": 1382, } # the default return {"hits": [], "facets": {"platform": []}, "total": 0} SuperSearch.implementation().get.side_effect = mocked_supersearch_get # Test with no results. url = reverse("signature:signature_aggregation", args=("platform",)) response = self.client.get(url, {"signature": DUMB_SIGNATURE}) eq_(response.status_code, 200) ok_("Product" not in response.content) ok_("No results were found" in response.content) # Test with results. url = reverse("signature:signature_aggregation", args=("product",)) response = self.client.get(url, {"signature": DUMB_SIGNATURE}) eq_(response.status_code, 200) ok_("Product" in response.content) ok_("1337" in response.content) ok_("linux" in response.content) ok_(str(1337 / 1382 * 100) in response.content) ok_("windows" in response.content) ok_("mac" in response.content)
def test_assert_supersearch_errors(self): searches = [] def mocked_supersearch_get(**params): searches.append(params) assert params["product"] == [settings.DEFAULT_PRODUCT] assert params["_results_number"] == 1 assert params["_columns"] == ["uuid"] return { "hits": [{"uuid": "12345"}], "facets": [], "total": 320, "errors": ["bad"], } SuperSearch.implementation().get.side_effect = mocked_supersearch_get with pytest.raises(AssertionError): assert_supersearch_no_errors() assert len(searches) == 1
def test_change_certain_exceptions_to_bad_request(self): # It actually doesn't matter so much which service we use # because we're heavily mocking it. # Here we use the SuperSearch model. def mocked_supersearch_get(**params): if params.get('product'): raise MissingArgumentError(params['product']) else: raise BadArgumentError('That was a bad thing to do') SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('api:model_wrapper', args=('SuperSearch', )) response = self.client.get(url) assert response.status_code == 400 assert 'That was a bad thing to do' in response.content response = self.client.get(url, {'product': 'foobaz'}) assert response.status_code == 400 assert 'foobaz' in response.content
def test_search_results_ratelimited(self): def mocked_supersearch_get(**params): return {"hits": [], "facets": [], "total": 0} SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('supersearch.search_results') limit = int(re.findall('(\d+)', settings.RATELIMIT_SUPERSEARCH)[0]) params = {'product': 'WaterWolf'} # double to avoid https://bugzilla.mozilla.org/show_bug.cgi?id=1148470 for i in range(limit * 2): self.client.get(url, params) response = self.client.get( url, params, HTTP_X_REQUESTED_WITH='XMLHttpRequest' ) eq_(response.status_code, 429) eq_(response.content, 'Too Many Requests') eq_(response['content-type'], 'text/plain')
def test_change_certain_exceptions_to_bad_request(self): # It actually doesn't matter so much which service we use # because we're heavily mocking it. # Here we use the SuperSearch model. def mocked_supersearch_get(**params): if params.get('product'): raise MissingArgumentError(params['product']) else: raise BadArgumentError('That was a bad thing to do') SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('api:model_wrapper', args=('SuperSearch',)) response = self.client.get(url) eq_(response.status_code, 400) ok_('That was a bad thing to do' in response.content) response = self.client.get(url, {'product': 'foobaz'}) eq_(response.status_code, 400) ok_('foobaz' in response.content)
def test_assert_supersearch_errors(self): searches = [] def mocked_supersearch_get(**params): searches.append(params) assert params['product'] == [settings.DEFAULT_PRODUCT] assert params['_results_number'] == 1 assert params['_columns'] == ['uuid'] return { 'hits': [ {'uuid': '12345'}, ], 'facets': [], 'total': 320, 'errors': ['bad'], } SuperSearch.implementation().get.side_effect = mocked_supersearch_get with pytest.raises(AssertionError): assert_supersearch_no_errors() assert len(searches) == 1
def test_search_custom_parameters(self): self.create_custom_query_perm() def mocked_supersearch_get(**params): ok_('_return_query' in params) ok_('signature' in params) eq_(params['signature'], ['nsA']) return { "query": {"query": None}, "indices": ["socorro200000", "socorro200001"] } SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('supersearch.search_custom') response = self.client.get(url, {'signature': 'nsA'}) eq_(response.status_code, 200) ok_('Run a search to get some results' in response.content) ok_('{"query": null}' in response.content) ok_('socorro200000' in response.content) ok_('socorro200001' in response.content)
def test_topcrasher_modes(self, rpost): rpost.side_effect = mocked_post_123 def mocked_supersearch_get(**params): return { 'hits': [], 'facets': { 'signature': [] }, 'total': 0 } SuperSearch.implementation().get.side_effect = mocked_supersearch_get now = datetime.datetime.utcnow() today = now.replace(hour=0, minute=0, second=0, microsecond=0) timestr = '%Y-%m-%d %H:%M:%S' now = now.strftime(timestr) today = today.strftime(timestr) with freezegun.freeze_time(now, tz_offset=0): # By default, it returns "real-time" data. response = self.client.get(self.base_url, { 'product': 'WaterWolf', 'version': '19.0', }) eq_(response.status_code, 200) ok_(now in response.content, now) ok_(today not in response.content) # Now test the "day time" data. response = self.client.get(self.base_url, { 'product': 'WaterWolf', 'version': '19.0', '_tcbs_mode': 'byday', }) eq_(response.status_code, 200) ok_(today in response.content) ok_(now not in response.content)
def test_parameters(self): def mocked_supersearch_get(**params): # Verify that all expected parameters are in the URL. ok_('product' in params) ok_('WaterWolf' in params['product']) ok_('NightTrain' in params['product']) ok_('address' in params) ok_('0x0' in params['address']) ok_('0xa' in params['address']) ok_('reason' in params) ok_('^hello' in params['reason']) ok_('$thanks' in params['reason']) ok_('java_stack_trace' in params) ok_('Exception' in params['java_stack_trace']) return { "hits": [], "facets": "", "total": 0 } SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('signature:signature_reports') response = self.client.get( url, { 'signature': DUMB_SIGNATURE, 'product': ['WaterWolf', 'NightTrain'], 'address': ['0x0', '0xa'], 'reason': ['^hello', '$thanks'], 'java_stack_trace': 'Exception', } ) eq_(response.status_code, 200)
def test_signature_comments_pagination(self): """Test that the pagination of comments works as expected. """ def mocked_supersearch_get(**params): assert "_columns" in params if params.get("_results_offset") != 0: hits_range = range(100, 140) else: hits_range = range(100) hits = [] for i in hits_range: hits.append({"date": "2017-01-31T23:12:57", "uuid": i, "user_comments": "hi"}) return {"hits": self.only_certain_columns(hits, params["_columns"]), "total": 140} SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse("signature:signature_comments") response = self.client.get(url, {"signature": DUMB_SIGNATURE, "product": ["WaterWolf"]}) eq_(response.status_code, 200) ok_("140" in response.content) ok_("99" in response.content) ok_("139" not in response.content) # Check that the pagination URL contains all expected parameters. doc = pyquery.PyQuery(response.content) next_page_url = str(doc(".pagination a").eq(0)) ok_("product=WaterWolf" in next_page_url) ok_("page=2" in next_page_url) response = self.client.get(url, {"signature": DUMB_SIGNATURE, "page": "2"}) eq_(response.status_code, 200) ok_("140" in response.content) ok_("99" not in response.content) ok_("139" in response.content)
def test_healthcheck(self, mocked_elasticsearch, rget): searches = [] def mocked_supersearch_get(**params): searches.append(params) assert params['product'] == [settings.DEFAULT_PRODUCT] assert params['_results_number'] == 1 assert params['_columns'] == ['uuid'] return { 'hits': [ {'uuid': '12345'}, ], 'facets': [], 'total': 30002, 'errors': [], } SuperSearch.implementation().get.side_effect = mocked_supersearch_get def mocked_requests_get(url, **params): return Response(True) rget.side_effect = mocked_requests_get # Verify the __heartbeat__ endpoint url = reverse('monitoring:dockerflow_heartbeat') response = self.client.get(url) assert response.status_code == 200 assert json.loads(response.content)['ok'] is True assert len(searches) == 1 # Verify the deprecated healthcheck endpoint searches = [] url = reverse('monitoring:healthcheck') response = self.client.get(url) assert response.status_code == 200 assert json.loads(response.content)['ok'] is True assert len(searches) == 1
def test_signature_summary_with_many_hexes(self, rget): def mocked_get(url, params, **options): if "/graphics_devices" in url: ok_(len(params["vendor_hex"]) <= 50) ok_(len(params["adapter_hex"]) <= 50) return Response({"hits": [], "total": 0}) raise NotImplementedError(url) rget.side_effect = mocked_get def mocked_supersearch_get(**params): ok_("signature" in params) eq_(params["signature"], ["=" + DUMB_SIGNATURE]) adapters = [{"term": "0x{0:0>4}".format(i), "count": 1} for i in range(50)] vendors = [ {"term": "0x{0:0>4}".format(i), "count": 50, "facets": {"adapter_device_id": adapters}} for i in range(3) ] res = {"hits": [], "total": 4, "facets": {"adapter_vendor_id": vendors}} return res SuperSearch.implementation().get.side_effect = mocked_supersearch_get # Test with no results url = reverse("signature:signature_summary") response = self.client.get(url, {"signature": DUMB_SIGNATURE, "product": "WaterWolf", "version": "1.0"}) eq_(response.status_code, 200) # There are 150 different hexes, there should be 3 calls to the API. eq_(rget.call_count, 3)
def test_signature_reports(self): def mocked_supersearch_get(**params): assert '_columns' in params ok_('uuid' in params['_columns']) ok_('signature' in params) eq_(params['signature'], ['=' + DUMB_SIGNATURE]) if 'product' in params: results = { "hits": [{ "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa1", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": 888981 }, { "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa2", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": 888981 }, { "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa3", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": None }, { "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa4", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": None }], "total": 4 } results['hits'] = self.only_certain_columns( results['hits'], params['_columns']) return results return {"hits": [], "total": 0} SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('signature:signature_reports') # Test with no results. response = self.client.get(url, { 'signature': DUMB_SIGNATURE, 'date': '2012-01-01', }) eq_(response.status_code, 200) ok_('table id="reports-list"' not in response.content) ok_('No results were found' in response.content) # Test with results. response = self.client.get(url, { 'signature': DUMB_SIGNATURE, 'product': 'WaterWolf' }) eq_(response.status_code, 200) ok_('table id="reports-list"' in response.content) ok_('aaaaaaaaaaaaa1' in response.content) ok_('888981' in response.content) ok_('Linux' in response.content) ok_('2017-01-31 23:12:57' in response.content) # Test with a different columns list. response = self.client.get( url, { 'signature': DUMB_SIGNATURE, 'product': 'WaterWolf', '_columns': ['build_id', 'platform'], }) eq_(response.status_code, 200) ok_('table id="reports-list"' in response.content) # The build and platform appear ok_('888981' in response.content) ok_('Linux' in response.content) # The crash id is always shown ok_('aaaaaaaaaaaaa1' in response.content) # The version and date do not appear ok_('1.0' not in response.content) ok_('2017' not in response.content) # Test missing parameter. response = self.client.get(url) eq_(response.status_code, 400) response = self.client.get(url, { 'signature': '', }) eq_(response.status_code, 400)
def test_signature_summary(self, rget): def mocked_get(url, params, **options): if '/graphics_devices' in url: return Response({ 'hits': [{ 'vendor_hex': '0x0086', 'adapter_hex': '0x1234', 'vendor_name': 'Intel', 'adapter_name': 'Device', }, { 'vendor_hex': '0x0086', 'adapter_hex': '0x1239', 'vendor_name': 'Intel', 'adapter_name': 'Other', }], 'total': 2 }) raise NotImplementedError(url) rget.side_effect = mocked_get def mocked_supersearch_get(**params): ok_('signature' in params) eq_(params['signature'], ['=' + DUMB_SIGNATURE]) if '_aggs.product.version' in params: ok_('product' not in params) ok_('version' not in params) else: ok_('_histogram.uptime' in params) ok_('_facets' in params) res = { "hits": [], "total": 4, "facets": { "platform_pretty_version": [{ "count": 4, "term": "Windows 7" }], "cpu_name": [{ "count": 4, "term": "x86" }], "process_type": [{ "count": 4, "term": "browser" }], "product": [{ "count": 4, "term": "WaterWolf", "facets": { "version": [{ "term": "2.1b99", "count": 2, "facets": { "cardinality_install_time": { "value": 2 } } }, { "term": "1.0", "count": 2, "facets": { "cardinality_install_time": { "value": 2 } } }] } }], "flash_version": [{ "count": 4, "term": "1.1.1.14" }], "adapter_vendor_id": [{ "term": "0x0086", "count": 4, "facets": { "adapter_device_id": [{ "term": "0x1234", "count": 2, }, { "term": "0x1239", "count": 2, }] } }], "android_cpu_abi": [{ "term": "armeabi-v7a", "count": 4, "facets": { "android_manufacturer": [{ "term": "ZTE", "count": 4, "facets": { "android_model": [{ "term": "roamer2", "count": 4, "facets": { "android_version": [{ "term": "15", "count": 4, }] } }] } }] } }], "histogram_uptime": [{ "count": 2, "term": 0, }, { "count": 2, "term": 60, }], } } if '_histogram.date' in params: res['facets']['histogram_date'] = [{ "count": 2, "term": "2015-08-05T00:00:00+00:00", "facets": { "exploitability": [{ "count": 2, "term": "high" }] } }, { "count": 2, "term": "2015-08-06T00:00:00+00:00", "facets": { "exploitability": [{ "count": 2, "term": "low" }] } }] return res SuperSearch.implementation().get.side_effect = (mocked_supersearch_get) # Test with no results url = reverse('signature:signature_summary') response = self.client.get( url, { 'signature': DUMB_SIGNATURE, 'product': 'WaterWolf', 'version': '1.0', }) eq_(response.status_code, 200) # Make sure all boxes are there. ok_('Operating System' in response.content) ok_('Uptime Range' in response.content) ok_('Product' in response.content) ok_('Architecture' in response.content) ok_('Process Type' in response.content) ok_('Mobile Devices' in response.content) ok_('Graphics Adapter' in response.content) ok_('Flash™ Version' in response.content) # Logged out users can't see no exploitability ok_('Exploitability' not in response.content) # Check that some of the expected values are there. ok_('Windows 7' in response.content) ok_('x86' in response.content) ok_('WaterWolf' in response.content) ok_('2.1b99' in response.content) ok_('browser' in response.content) ok_('1.1.1.14' in response.content) ok_('< 1 min' in response.content) ok_('1-5 min' in response.content) ok_('ZTE' in response.content) ok_('Intel (0x0086)' in response.content) user = self._login() response = self.client.get(url, {'signature': DUMB_SIGNATURE}) eq_(response.status_code, 200) # Logged in users without the permission can't see no exploitability ok_('Exploitability' not in response.content) group = self._create_group_with_permission('view_exploitability') user.groups.add(group) assert user.has_perm('crashstats.view_exploitability') response = self.client.get(url, {'signature': DUMB_SIGNATURE}) eq_(response.status_code, 200) # Logged in users with the permission can see exploitability ok_('Exploitability' in response.content)
def test_signature_comments(self): def mocked_supersearch_get(**params): assert '_columns' in params ok_('signature' in params) eq_(params['signature'], ['=' + DUMB_SIGNATURE]) ok_('user_comments' in params) eq_(params['user_comments'], ['!__null__']) if 'product' in params: results = { "hits": [{ "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa1", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "user_comments": "hello there people!", "useragent_locale": "locale1" }, { "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa2", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "user_comments": "I love Mozilla", "useragent_locale": "locale2" }, { "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa3", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "user_comments": "this product is awesome", "useragent_locale": "locale3" }, { "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa4", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "user_comments": "WaterWolf Y U SO GOOD?", "useragent_locale": "locale4" }], "total": 4 } results['hits'] = self.only_certain_columns( results['hits'], params['_columns']) return results return {"hits": [], "total": 0} SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('signature:signature_comments') # Test with no results. response = self.client.get(url, { 'signature': DUMB_SIGNATURE, }) eq_(response.status_code, 200) ok_('Crash ID' not in response.content) ok_('No comments were found' in response.content) # Test with results. response = self.client.get(url, { 'signature': DUMB_SIGNATURE, 'product': 'WaterWolf' }) eq_(response.status_code, 200) ok_('aaaaaaaaaaaaa1' in response.content) ok_('Crash ID' in response.content) ok_('hello there' in response.content) ok_('WaterWolf Y U SO GOOD' in response.content) ok_('locale1' in response.content)
def test_signature_aggregation(self): def mocked_supersearch_get(**params): ok_('signature' in params) eq_(params['signature'], ['=' + DUMB_SIGNATURE]) ok_('_facets' in params) if 'product' in params['_facets']: return { "hits": [], "facets": { "product": [ { "term": "windows", "count": 42, }, { "term": "linux", "count": 1337, }, { "term": "mac", "count": 3, }, ] }, "total": 1382 } # the default return { "hits": [], "facets": { "platform": [] }, "total": 0 } SuperSearch.implementation().get.side_effect = mocked_supersearch_get # Test with no results. url = reverse( 'signature:signature_aggregation', args=('platform',) ) response = self.client.get(url, {'signature': DUMB_SIGNATURE}) eq_(response.status_code, 200) ok_('Product' not in response.content) ok_('No results were found' in response.content) # Test with results. url = reverse( 'signature:signature_aggregation', args=('product',) ) response = self.client.get(url, {'signature': DUMB_SIGNATURE}) eq_(response.status_code, 200) ok_('Product' in response.content) ok_('1337' in response.content) ok_('linux' in response.content) ok_(str(1337 / 1382 * 100) in response.content) ok_('windows' in response.content) ok_('mac' in response.content)
def test_NewSignatures(self): def mocked_supersearch_get(**params): assert params["product"] == [settings.DEFAULT_PRODUCT] if "version" in params: assert params["version"] == ["1.0", "2.0"] if "signature" not in params: # Return a list of signatures. signatures = [ { "term": "ba", "count": 21 }, { "term": "zin", "count": 19 }, { "term": "ga", "count": 1 }, ] else: # Return only some of the above signatures. The missing ones # are "new" signatures. signatures = [{"term": "ga", "count": 21}] return { "hits": [], "facets": { "signature": signatures }, "total": 43829 } SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse("api:model_wrapper", args=("NewSignatures", )) # Test we get expected results. response = self.client.get(url) assert response.status_code == 200 res_expected = ["ba", "zin"] res = json.loads(response.content) assert res["hits"] == res_expected # Test with versions. response = self.client.get(url, {"version": ["1.0", "2.0"]}) assert response.status_code == 200 # Test with incorrect arguments. response = self.client.get( url, { "start_date": "not a date", "end_date": "not a date", "not_after": "not a date", }, ) assert response.status_code == 400 assert response["Content-Type"] == "application/json; charset=UTF-8" res = json.loads(response.content) assert "errors" in res assert len(res["errors"]) == 3
def test_profile(self): def mocked_supersearch_get(**params): assert '_columns' in params assert '_sort' in params assert 'email' in params assert params['email'] == ['*****@*****.**'] results = { 'hits': [ { 'uuid': '1234abcd-ef56-7890-ab12-abcdef130802', 'date': '2000-01-02T00:00:00' }, { 'uuid': '1234abcd-ef56-7890-ab12-abcdef130801', 'date': '2000-01-01T00:00:00' }, ], 'total': 2 } return results def mocked_supersearch_get_no_data(**params): assert 'email' in params assert params['email'] == ['*****@*****.**'] return {'hits': [], 'total': 0} SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('profile:profile') # Test that the user must be signed in. response = self.client.get(url) eq_(response.status_code, 302) self.assertRedirects(response, reverse('crashstats:login') + '?next=%s' % url) # Now log in for the remaining tests. user = self._login() # Test with results and check email is there. response = self.client.get(url) eq_(response.status_code, 200) ok_('1234abcd-ef56-7890-ab12-abcdef130801' in response.content) ok_('1234abcd-ef56-7890-ab12-abcdef130802' in response.content) ok_('*****@*****.**' in response.content) SuperSearch.implementation().get.side_effect = ( mocked_supersearch_get_no_data) # Test with no results. response = self.client.get(url) eq_(response.status_code, 200) ok_('*****@*****.**' in response.content) ok_('no crash report' in response.content) # Make some permissions. self._create_group_with_permission('view_pii', 'Group A') group_b = self._create_group_with_permission('view_exploitability', 'Group B') user.groups.add(group_b) assert not user.has_perm('crashstats.view_pii') assert user.has_perm('crashstats.view_exploitability') # Test permissions. response = self.client.get(url) ok_(PERMISSIONS['view_pii'] in response.content) ok_(PERMISSIONS['view_exploitability'] in response.content) doc = pyquery.PyQuery(response.content) for row in doc('table.permissions tbody tr'): cells = [] for td in doc('td', row): cells.append(td.text.strip()) if cells[0] == PERMISSIONS['view_pii']: eq_(cells[1], 'No') elif cells[0] == PERMISSIONS['view_exploitability']: eq_(cells[1], 'Yes!')
def test_SuperSearch(self): def mocked_supersearch_get(**params): assert 'exploitability' not in params restricted_params = ( '_facets', '_aggs.signature', '_histogram.date', ) for key in restricted_params: if key in params: assert 'url' not in params[key] assert 'email' not in params[key] assert '_cardinality.email' not in params[key] if 'product' in params: assert params['product'] == ['WaterWolf', 'NightTrain'] return { 'hits': [{ 'signature': 'abcdef', 'product': 'WaterWolf', 'version': '1.0', 'email': '*****@*****.**', 'exploitability': 'high', 'url': 'http://embarassing.website.com', 'user_comments': 'hey I am [email protected]', }], 'facets': { 'signature': [] }, 'total': 0 } SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('api:model_wrapper', args=('SuperSearch', )) response = self.client.get(url) assert response.status_code == 200 res = json.loads(response.content) assert res['hits'] assert res['facets'] # Verify forbidden fields are not exposed. assert 'email' not in res['hits'] assert 'exploitability' not in res['hits'] assert 'url' not in res['hits'] # Verify user comments are scrubbed. assert '*****@*****.**' not in res['hits'][0]['user_comments'] # Verify it's not possible to use restricted parameters. response = self.client.get( url, { 'exploitability': 'high', '_facets': ['url', 'email', 'product', '_cardinality.email'], '_aggs.signature': ['url', 'email', 'product', '_cardinality.email'], '_histogram.date': ['url', 'email', 'product', '_cardinality.email'], }) assert response.status_code == 200 # Verify values can be lists. response = self.client.get(url, {'product': ['WaterWolf', 'NightTrain']}) assert response.status_code == 200
def test_SuperSearch(self): def mocked_supersearch_get(**params): assert 'exploitability' not in params restricted_params = ( '_facets', '_aggs.signature', '_histogram.date', ) for key in restricted_params: if key in params: assert 'url' not in params[key] assert 'email' not in params[key] assert '_cardinality.email' not in params[key] if 'product' in params: assert params['product'] == ['WaterWolf', 'NightTrain'] return { 'hits': [ { 'signature': 'abcdef', 'product': 'WaterWolf', 'version': '1.0', 'email': '*****@*****.**', 'exploitability': 'high', 'url': 'http://embarassing.website.com', 'user_comments': 'hey I am [email protected]', } ], 'facets': { 'signature': [] }, 'total': 0 } SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('api:model_wrapper', args=('SuperSearch',)) response = self.client.get(url) assert response.status_code == 200 res = json.loads(response.content) assert res['hits'] assert res['facets'] # Verify forbidden fields are not exposed. assert 'email' not in res['hits'] assert 'exploitability' not in res['hits'] assert 'url' not in res['hits'] # Verify it's not possible to use restricted parameters. response = self.client.get(url, { 'exploitability': 'high', '_facets': ['url', 'email', 'product', '_cardinality.email'], '_aggs.signature': [ 'url', 'email', 'product', '_cardinality.email' ], '_histogram.date': [ 'url', 'email', 'product', '_cardinality.email' ], }) assert response.status_code == 200 # Verify values can be lists. response = self.client.get(url, { 'product': ['WaterWolf', 'NightTrain'] }) assert response.status_code == 200
def test_NewSignatures(self): def mocked_supersearch_get(**params): assert params['product'] == [settings.DEFAULT_PRODUCT] if 'version' in params: assert params['version'] == ['1.0', '2.0'] if 'signature' not in params: # Return a list of signatures. signatures = [ {'term': 'ba', 'count': 21}, {'term': 'zin', 'count': 19}, {'term': 'ga', 'count': 1}, ] else: # Return only some of the above signatures. The missing ones # are "new" signatures. signatures = [ {'term': 'ga', 'count': 21}, ] return { 'hits': [], 'facets': { 'signature': signatures }, 'total': 43829, } SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('api:model_wrapper', args=('NewSignatures',)) # Test we get expected results. response = self.client.get(url) assert response.status_code == 200 res_expected = [ 'ba', 'zin', ] res = json.loads(response.content) assert res['hits'] == res_expected # Test with versions. response = self.client.get(url, { 'version': ['1.0', '2.0'] }) assert response.status_code == 200 # Test with incorrect arguments. response = self.client.get(url, { 'start_date': 'not a date', 'end_date': 'not a date', 'not_after': 'not a date', }) assert response.status_code == 400 assert response['Content-Type'] == 'application/json; charset=UTF-8' res = json.loads(response.content) assert 'errors' in res assert len(res['errors']) == 3
def test_signature_summary(self): def mocked_supersearch_get(**params): ok_('signature' in params) eq_(params['signature'], ['=' + DUMB_SIGNATURE]) ok_('_histogram.uptime' in params) ok_('_facets' in params) res = { "hits": [], "total": 4, "facets": { "platform_pretty_version": [ { "count": 4, "term": "WaterWolf" } ], "cpu_name": [ { "count": 4, "term": "x86" } ], "process_type": [ { "count": 4, "term": "browser" } ], "flash_version": [ { "count": 4, "term": "1.1.1.14" } ], "histogram_uptime": [ { "count": 2, "term": 0, }, { "count": 2, "term": 60, } ], } } if '_histogram.date' in params: res['facets']['histogram_date'] = [ { "count": 2, "term": "2015-08-05T00:00:00+00:00", "facets": { "exploitability": [ { "count": 2, "term": "high" } ] } }, { "count": 2, "term": "2015-08-06T00:00:00+00:00", "facets": { "exploitability": [ { "count": 2, "term": "low" } ] } } ] return res SuperSearch.implementation().get.side_effect = ( mocked_supersearch_get ) # Test with no results url = reverse('signature:signature_summary') response = self.client.get(url, {'signature': DUMB_SIGNATURE}) eq_(response.status_code, 200) # Make sure all boxes are there. ok_('Operating System' in response.content) ok_('Uptime Range' in response.content) ok_('Architecture' in response.content) ok_('Process Type' in response.content) ok_('Flash™ Version' in response.content) # Logged out users can't see no exploitability ok_('Exploitability' not in response.content) # Check that some of the expected values are there. ok_('WaterWolf' in response.content) ok_('x86' in response.content) ok_('browser' in response.content) ok_('1.1.1.14' in response.content) ok_('< 1 min' in response.content) ok_('1-5 min' in response.content) user = self._login() response = self.client.get(url, {'signature': DUMB_SIGNATURE}) eq_(response.status_code, 200) # Logged in users without the permission can't see no exploitability ok_('Exploitability' not in response.content) group = self._create_group_with_permission('view_exploitability') user.groups.add(group) assert user.has_perm('crashstats.view_exploitability') response = self.client.get(url, {'signature': DUMB_SIGNATURE}) eq_(response.status_code, 200) # Logged in users with the permission can see exploitability ok_('Exploitability' in response.content)
def test_signature_reports(self): def mocked_supersearch_get(**params): assert '_columns' in params ok_('uuid' in params['_columns']) ok_('signature' in params) eq_(params['signature'], ['=' + DUMB_SIGNATURE]) if 'product' in params: results = { "hits": [ { "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa1", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": 888981 }, { "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa2", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": 888981 }, { "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa3", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": None }, { "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa4", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": None } ], "total": 4 } results['hits'] = self.only_certain_columns( results['hits'], params['_columns'] ) return results return {"hits": [], "total": 0} SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('signature:signature_reports') # Test with no results. response = self.client.get(url, { 'signature': DUMB_SIGNATURE, 'date': '2012-01-01', }) eq_(response.status_code, 200) ok_('table id="reports-list"' not in response.content) ok_('No results were found' in response.content) # Test with results. response = self.client.get(url, { 'signature': DUMB_SIGNATURE, 'product': 'WaterWolf' }) eq_(response.status_code, 200) ok_('table id="reports-list"' in response.content) ok_('aaaaaaaaaaaaa1' in response.content) ok_('888981' in response.content) ok_('Linux' in response.content) ok_('2017-01-31 23:12:57' in response.content) # Test with a different columns list. response = self.client.get(url, { 'signature': DUMB_SIGNATURE, 'product': 'WaterWolf', '_columns': ['build_id', 'platform'], }) eq_(response.status_code, 200) ok_('table id="reports-list"' in response.content) # The build and platform appear ok_('888981' in response.content) ok_('Linux' in response.content) # The crash id is always shown ok_('aaaaaaaaaaaaa1' in response.content) # The version and date do not appear ok_('1.0' not in response.content) ok_('2017' not in response.content) # Test missing parameter. response = self.client.get(url) eq_(response.status_code, 400) response = self.client.get(url, { 'signature': '', }) eq_(response.status_code, 400)
def test_signature_summary(self, rget): def mocked_get(url, params, **options): if '/graphics_devices' in url: return Response({ 'hits': [ { 'vendor_hex': '0x0086', 'adapter_hex': '0x1234', 'vendor_name': 'Intel', 'adapter_name': 'Device', }, { 'vendor_hex': '0x0086', 'adapter_hex': '0x1239', 'vendor_name': 'Intel', 'adapter_name': 'Other', } ], 'total': 2 }) raise NotImplementedError(url) rget.side_effect = mocked_get def mocked_supersearch_get(**params): ok_('signature' in params) eq_(params['signature'], ['=' + DUMB_SIGNATURE]) if '_aggs.product.version' in params: ok_('product' not in params) ok_('version' not in params) else: ok_('_histogram.uptime' in params) ok_('_facets' in params) res = { "hits": [], "total": 4, "facets": { "platform_pretty_version": [ { "count": 4, "term": "Windows 7" } ], "cpu_name": [ { "count": 4, "term": "x86" } ], "process_type": [ { "count": 4, "term": "browser" } ], "product": [ { "count": 4, "term": "WaterWolf", "facets": { "version": [ { "term": "2.1b99", "count": 2, "facets": { "cardinality_install_time": { "value": 2 } } }, { "term": "1.0", "count": 2, "facets": { "cardinality_install_time": { "value": 2 } } } ] } } ], "flash_version": [ { "count": 4, "term": "1.1.1.14" } ], "adapter_vendor_id": [ { "term": "0x0086", "count": 4, "facets": { "adapter_device_id": [ { "term": "0x1234", "count": 2, }, { "term": "0x1239", "count": 2, } ] } } ], "android_cpu_abi": [ { "term": "armeabi-v7a", "count": 4, "facets": { "android_manufacturer": [ { "term": "ZTE", "count": 4, "facets": { "android_model": [ { "term": "roamer2", "count": 4, "facets": { "android_version": [ { "term": "15", "count": 4, } ] } } ] } } ] } } ], "histogram_uptime": [ { "count": 2, "term": 0, }, { "count": 2, "term": 60, } ], } } if '_histogram.date' in params: res['facets']['histogram_date'] = [ { "count": 2, "term": "2015-08-05T00:00:00+00:00", "facets": { "exploitability": [ { "count": 2, "term": "high" } ] } }, { "count": 2, "term": "2015-08-06T00:00:00+00:00", "facets": { "exploitability": [ { "count": 2, "term": "low" } ] } } ] return res SuperSearch.implementation().get.side_effect = ( mocked_supersearch_get ) # Test with no results url = reverse('signature:signature_summary') response = self.client.get(url, { 'signature': DUMB_SIGNATURE, 'product': 'WaterWolf', 'version': '1.0', }) eq_(response.status_code, 200) # Make sure all boxes are there. ok_('Operating System' in response.content) ok_('Uptime Range' in response.content) ok_('Product' in response.content) ok_('Architecture' in response.content) ok_('Process Type' in response.content) ok_('Mobile Devices' in response.content) ok_('Graphics Adapter' in response.content) ok_('Flash™ Version' in response.content) # Logged out users can't see no exploitability ok_('Exploitability' not in response.content) # Check that some of the expected values are there. ok_('Windows 7' in response.content) ok_('x86' in response.content) ok_('WaterWolf' in response.content) ok_('2.1b99' in response.content) ok_('browser' in response.content) ok_('1.1.1.14' in response.content) ok_('< 1 min' in response.content) ok_('1-5 min' in response.content) ok_('ZTE' in response.content) ok_('Intel (0x0086)' in response.content) user = self._login() response = self.client.get(url, {'signature': DUMB_SIGNATURE}) eq_(response.status_code, 200) # Logged in users without the permission can't see no exploitability ok_('Exploitability' not in response.content) group = self._create_group_with_permission('view_exploitability') user.groups.add(group) assert user.has_perm('crashstats.view_exploitability') response = self.client.get(url, {'signature': DUMB_SIGNATURE}) eq_(response.status_code, 200) # Logged in users with the permission can see exploitability ok_('Exploitability' in response.content)
def test_signature_comments(self): def mocked_supersearch_get(**params): assert '_columns' in params ok_('signature' in params) eq_(params['signature'], ['=' + DUMB_SIGNATURE]) ok_('user_comments' in params) eq_(params['user_comments'], ['!__null__']) if 'product' in params: results = { "hits": [ { "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa1", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "user_comments": "hello there people!", "useragent_locale": "locale1" }, { "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa2", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "user_comments": "I love Mozilla", "useragent_locale": "locale2" }, { "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa3", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "user_comments": "this product is awesome", "useragent_locale": "locale3" }, { "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa4", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "user_comments": "WaterWolf Y U SO GOOD?", "useragent_locale": "locale4" } ], "total": 4 } results['hits'] = self.only_certain_columns( results['hits'], params['_columns'] ) return results return {"hits": [], "total": 0} SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('signature:signature_comments') # Test with no results. response = self.client.get(url, { 'signature': DUMB_SIGNATURE, }) eq_(response.status_code, 200) ok_('Crash ID' not in response.content) ok_('No comments were found' in response.content) # Test with results. response = self.client.get(url, { 'signature': DUMB_SIGNATURE, 'product': 'WaterWolf' }) eq_(response.status_code, 200) ok_('aaaaaaaaaaaaa1' in response.content) ok_('Crash ID' in response.content) ok_('hello there' in response.content) ok_('WaterWolf Y U SO GOOD' in response.content) ok_('locale1' in response.content)
def test_signature_graphs(self): def mocked_supersearch_get(**params): ok_('signature' in params) eq_(params['signature'], ['=' + DUMB_SIGNATURE]) ok_('_histogram.date' in params) ok_('_facets' in params) if 'product' in params['_facets']: return { "hits": [], "total": 4, "facets": { "product": [ { "count": 4, "term": "WaterWolf" } ], "histogram_date": [ { "count": 2, "term": "2015-08-05T00:00:00+00:00", "facets": { "product": [ { "count": 2, "term": "WaterWolf" } ] } }, { "count": 2, "term": "2015-08-06T00:00:00+00:00", "facets": { "product": [ { "count": 2, "term": "WaterWolf" } ] } } ] } } return { "hits": [], "total": 0, "facets": { "platform": [], "signature": [], "histogram_date": [] } } SuperSearch.implementation().get.side_effect = mocked_supersearch_get # Test with no results url = reverse( 'signature:signature_graphs', args=('platform',) ) response = self.client.get(url, {'signature': DUMB_SIGNATURE}) eq_(response.status_code, 200) ok_('application/json' in response['content-type']) struct = json.loads(response.content) ok_('aggregates' in struct) eq_(len(struct['aggregates']), 0) ok_('term_counts' in struct) eq_(len(struct['term_counts']), 0) # Test with results url = reverse( 'signature:signature_graphs', args=('product',) ) response = self.client.get(url, {'signature': DUMB_SIGNATURE}) eq_(response.status_code, 200) ok_('application/json' in response['content-type']) struct = json.loads(response.content) ok_('aggregates' in struct) eq_(len(struct['aggregates']), 2) ok_('term_counts' in struct) eq_(len(struct['term_counts']), 1)
def test_graphics_report(self): def mocked_supersearch_get(**params): assert params['product'] == [settings.DEFAULT_PRODUCT] hits = [ { 'signature': 'my signature', 'date': '2015-10-08T23:22:21.1234 +00:00', 'cpu_name': 'arm', 'cpu_info': 'ARMv7 ARM', }, { 'signature': 'other signature', 'date': '2015-10-08T13:12:11.1123 +00:00', 'cpu_info': 'something', # note! no cpu_name }, ] # Value for each of these needs to be in there # supplement missing ones from the fixtures we intend to return. for hit in hits: for head in GRAPHICS_REPORT_HEADER: if head not in hit: hit[head] = None return {'hits': hits, 'total': 2} SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('graphics:report') # viewing this report requires that you're signed in response = self.client.get(url) assert response.status_code == 403 # But being signed in isn't good enough, you need the right # permissions too. user = self._login() response = self.client.get(url) assert response.status_code == 403 # Add the user to the Hackers group which has run_long_queries # permission group = Group.objects.get(name='Hackers') user.groups.add(group) # But even with the right permissions you still need to # provide the right minimal parameters. response = self.client.get(url) assert response.status_code == 400 # Let's finally get it right. Permission AND the date parameter. data = {'date': datetime.datetime.utcnow().date()} response = self.client.get(url, data) assert response.status_code == 200 assert response['Content-Type'] == 'text/csv' assert response['Content-Length'] == str(len(response.content)) # the response content should be parseable length = len(response.content) inp = StringIO(response.content) reader = csv.reader(inp, delimiter='\t') lines = list(reader) assert len(lines) == 3 header = lines[0] assert header == list(GRAPHICS_REPORT_HEADER) first = lines[1] assert first[GRAPHICS_REPORT_HEADER.index( 'signature')] == 'my signature' assert first[GRAPHICS_REPORT_HEADER.index( 'date_processed')] == '201510082322' # now fetch it with gzip response = self.client.get(url, data, HTTP_ACCEPT_ENCODING='gzip') assert response.status_code == 200 assert response['Content-Type'] == 'text/csv' assert response['Content-Length'] == str(len(response.content)) assert response['Content-Encoding'] == 'gzip' assert len(response.content) < length
def test_NewSignatures(self): def mocked_supersearch_get(**params): assert params['product'] == [settings.DEFAULT_PRODUCT] if 'version' in params: assert params['version'] == ['1.0', '2.0'] if 'signature' not in params: # Return a list of signatures. signatures = [ { 'term': 'ba', 'count': 21 }, { 'term': 'zin', 'count': 19 }, { 'term': 'ga', 'count': 1 }, ] else: # Return only some of the above signatures. The missing ones # are "new" signatures. signatures = [ { 'term': 'ga', 'count': 21 }, ] return { 'hits': [], 'facets': { 'signature': signatures }, 'total': 43829, } SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('api:model_wrapper', args=('NewSignatures', )) # Test we get expected results. response = self.client.get(url) assert response.status_code == 200 res_expected = [ 'ba', 'zin', ] res = json.loads(response.content) assert res['hits'] == res_expected # Test with versions. response = self.client.get(url, {'version': ['1.0', '2.0']}) assert response.status_code == 200 # Test with incorrect arguments. response = self.client.get( url, { 'start_date': 'not a date', 'end_date': 'not a date', 'not_after': 'not a date', }) assert response.status_code == 400 assert response['Content-Type'] == 'application/json; charset=UTF-8' res = json.loads(response.content) assert 'errors' in res assert len(res['errors']) == 3
def test_topcrashers(self, rpost): def mocked_post(**options): return { "hits": [{ "id": 123456789, "signature": "Something" }, { "id": 22222, "signature": u"FakeSignature1 \u7684 Japanese" }, { "id": 33333, "signature": u"FakeSignature1 \u7684 Japanese" }] } rpost.side_effect = mocked_post def mocked_supersearch_get(**params): if '_columns' not in params: params['_columns'] = [] if 'date' in params: # Return results for the previous week. results = { 'hits': [], 'facets': { 'signature': [{ 'term': u'FakeSignature1 \u7684 Japanese', 'count': 100, 'facets': { 'platform': [{ 'term': 'WaterWolf', 'count': 50, }], 'is_garbage_collecting': [{ 'term': 't', 'count': 50, }], 'hang_type': [{ 'term': 1, 'count': 50, }], 'process_type': [{ 'term': 'plugin', 'count': 50, }], } }] }, 'total': 250 } else: # Return results for the current week. results = { 'hits': [], 'facets': { 'signature': [{ 'term': u'FakeSignature1 \u7684 Japanese', 'count': 100, 'facets': { 'platform': [{ 'term': 'WaterWolf', 'count': 50, }], 'is_garbage_collecting': [{ 'term': 't', 'count': 50, }], 'hang_type': [{ 'term': 1, 'count': 50, }], 'process_type': [{ 'term': 'plugin', 'count': 50, }], } }] }, 'total': 250 } results['hits'] = self.only_certain_columns( results['hits'], params['_columns']) return results SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = self.base_url + '?product=WaterWolf&version=19.0' response = self.client.get(self.base_url, {'product': 'WaterWolf'}) ok_(url in response['Location']) response = self.client.get(self.base_url, { 'product': 'WaterWolf', 'version': '19.0', }) eq_(response.status_code, 200) response = self.client.get(self.base_url, { 'product': 'WaterWolf', 'version': '19.0', }) eq_(response.status_code, 200) doc = pyquery.PyQuery(response.content) selected_count = doc('.tc-result-count a[class="selected"]') eq_(selected_count.text(), '50') # there's actually only one such TD bug_ids = [x.text for x in doc('td.bug_ids_more > a')] # higher bug number first eq_(bug_ids, ['33333', '22222']) response = self.client.get(self.base_url, { 'product': 'WaterWolf', 'version': '19.0', '_facets_size': '100', }) eq_(response.status_code, 200) doc = pyquery.PyQuery(response.content) selected_count = doc('.tc-result-count a[class="selected"]') eq_(selected_count.text(), '100')
def test_topcrashers(self, rpost, bugs_get): def mocked_bugs(**options): return { "hits": [{ "id": 123456789, "signature": "Something" }, { "id": 22222, "signature": u"FakeSignature1 \u7684 Japanese" }, { "id": 33333, "signature": u"FakeSignature1 \u7684 Japanese" }] } bugs_get.side_effect = mocked_bugs def mocked_sigs(url, **options): if 'signature/first_date' in url: return Response({ "hits": [ { "signature": u"FakeSignature1 \u7684 Japanese", "first_date": "2000-01-01T12:23:34", "first_build": "20000101122334", }, ], "total": 1 }) raise NotImplementedError(url) rpost.side_effect = mocked_sigs def mocked_supersearch_get(**params): if '_columns' not in params: params['_columns'] = [] if 'hang_type' not in params['_aggs.signature']: # Return results for the previous week. results = { 'hits': [], 'facets': { 'signature': [{ 'term': u'FakeSignature1 \u7684 Japanese', 'count': 100, 'facets': { 'platform': [{ 'term': 'WaterWolf', 'count': 50, }], 'is_garbage_collecting': [{ 'term': 't', 'count': 50, }], 'hang_type': [{ 'term': 1, 'count': 50, }], 'process_type': [{ 'term': 'plugin', 'count': 50, }], 'histogram_uptime': [{ 'term': 0, 'count': 40, }], } }] }, 'total': 250 } else: # Return results for the current week. results = { 'hits': [], 'facets': { 'signature': [{ 'term': u'FakeSignature1 \u7684 Japanese', 'count': 100, 'facets': { 'platform': [{ 'term': 'WaterWolf', 'count': 50, }], 'is_garbage_collecting': [{ 'term': 't', 'count': 50, }], 'hang_type': [{ 'term': 1, 'count': 50, }], 'process_type': [{ 'term': 'plugin', 'count': 50, }], 'histogram_uptime': [{ 'term': 0, 'count': 60, }], } }, { 'term': u'mozCool()', 'count': 80, 'facets': { 'platform': [{ 'term': 'WaterWolf', 'count': 50, }], 'is_garbage_collecting': [{ 'term': 't', 'count': 50, }], 'hang_type': [{ 'term': 1, 'count': 50, }], 'process_type': [{ 'term': 'browser', 'count': 50, }], 'histogram_uptime': [{ 'term': 0, 'count': 40, }], } }] }, 'total': 250 } results['hits'] = self.only_certain_columns( results['hits'], params['_columns']) return results SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = self.base_url + '?product=WaterWolf&version=19.0' response = self.client.get(self.base_url, {'product': 'WaterWolf'}) ok_(url in response['Location']) # Test that several versions do not raise an error. response = self.client.get(self.base_url, { 'product': 'WaterWolf', 'version': '19.0;20.0', }) eq_(response.status_code, 200) response = self.client.get(self.base_url, { 'product': 'WaterWolf', 'version': '19.0', }) eq_(response.status_code, 200) doc = pyquery.PyQuery(response.content) selected_count = doc('.tc-result-count a[class="selected"]') eq_(selected_count.text(), '50') # there's actually only one such TD bug_ids = [x.text for x in doc('td.bug_ids_more > a')] # higher bug number first eq_(bug_ids, ['33333', '22222']) # Check the first appearance date is there. ok_('2000-01-01 12:23:34' in response.content) response = self.client.get(self.base_url, { 'product': 'WaterWolf', 'version': '19.0', '_facets_size': '100', }) eq_(response.status_code, 200) doc = pyquery.PyQuery(response.content) selected_count = doc('.tc-result-count a[class="selected"]') eq_(selected_count.text(), '100') # Check the startup crash icon is there. ok_('Startup Crash' in response.content)
def test_search_results_admin_mode(self, rpost): """Test that an admin can see more fields, and that a non-admin cannot. """ def mocked_post(**options): assert 'bugs' in options['url'], options['url'] return Response({"hits": [], "total": 0}) rpost.side_effect = mocked_post def mocked_supersearch_get(**params): assert '_columns' in params if '_facets' in params and 'url' in params['_facets']: facets = { "platform": [ { "term": "Linux", "count": 3 } ], "url": [ { "term": "http://example.org", "count": 3 } ] } else: facets = { "platform": [ { "term": "Linux", "count": 3 } ] } results = { "hits": [ { "signature": "nsASDOMWindowEnumerator::GetNext()", "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa1", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": 888981, "email": "*****@*****.**", "url": "http://example.org", "exploitability": "high" }, { "signature": "mySignatureIsCool", "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa2", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": 888981, "email": "*****@*****.**", "url": "http://example.org", "exploitability": "low" }, { "signature": "mineIsCoolerThanYours", "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa3", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": None, "email": "*****@*****.**", "url": "http://example.org", "exploitability": "error" } ], "facets": facets, "total": 3 } results['hits'] = self.only_certain_columns( results['hits'], params['_columns'] ) return results SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('supersearch.search_results') # Logged in user, can see the email field user = self._login() group = self._create_group_with_permission('view_pii') user.groups.add(group) response = self.client.get( url, { '_columns': ['version', 'email', 'url', 'exploitability'], '_facets': ['url', 'platform'] } ) eq_(response.status_code, 200) ok_('Email' in response.content) ok_('*****@*****.**' in response.content) ok_('Url facet' in response.content) ok_('http://example.org' in response.content) ok_('Version' in response.content) ok_('1.0' in response.content) # Without the correct permission the user cannot see exploitability. ok_('Exploitability' not in response.content) exp_group = self._create_group_with_permission('view_exploitability') user.groups.add(exp_group) response = self.client.get( url, { '_columns': ['version', 'email', 'url', 'exploitability'], '_facets': ['url', 'platform'] } ) eq_(response.status_code, 200) ok_('Email' in response.content) ok_('Exploitability' in response.content) ok_('high' in response.content) # Logged out user, cannot see the email field self._logout() response = self.client.get( url, { '_columns': ['version', 'email', 'url'], '_facets': ['url', 'platform'] } ) eq_(response.status_code, 200) ok_('Email' not in response.content) ok_('*****@*****.**' not in response.content) ok_('Url facet' not in response.content) ok_('http://example.org' not in response.content) ok_('Version' in response.content) ok_('1.0' in response.content)
def test_search_results(self, cpost): def mocked_post(**options): return { "hits": [ { "id": "123456", "signature": u"nsASDOMWindowEnumerator::GetNext()" } ], "total": 1 } cpost.side_effect = mocked_post def mocked_supersearch_get(**params): assert '_columns' in params if 'product' in params and 'WaterWolf' in params['product']: results = { "hits": [ { "signature": "nsASDOMWindowEnumerator::GetNext()", "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa1", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": 888981 }, { "signature": "mySignatureIsCool", "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa2", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": 888981 }, { "signature": "mineIsCoolerThanYours", "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa3", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": None }, { "signature": "EMPTY", "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa4", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": None } ], "facets": { "signature": [ { "term": "nsASDOMWindowEnumerator::GetNext()", "count": 1 }, { "term": "mySignatureIsCool", "count": 1 }, { "term": "mineIsCoolerThanYours", "count": 1 }, { "term": "EMPTY", "count": 1 } ] }, "total": 4 } results['hits'] = self.only_certain_columns( results['hits'], params['_columns'] ) return results elif 'product' in params and 'SeaMonkey' in params['product']: results = { "hits": [ { "signature": "nsASDOMWindowEnumerator::GetNext()", "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": 888981 }, { "signature": "mySignatureIsCool", "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": 888981 } ], "facets": { "build_id": [ { "term": "888981", "count": 2 } ] }, "total": 2 } results['hits'] = self.only_certain_columns( results['hits'], params['_columns'] ) return results elif ( 'signature' in params and '~nsASDOMWindowEnumerator' in params['signature'] ): results = { "hits": [ { "signature": "nsASDOMWindowEnumerator::GetNext()", "date": "2017-01-31T23:12:57", "uuid": "aaaaaaaaaaaaa", "product": "WaterWolf", "version": "1.0", "platform": "Linux", "build_id": 12345678 } ], "facets": { "signature": [ { "term": "nsASDOMWindowEnumerator::GetNext()", "count": 1 } ] }, "total": 1 } results['hits'] = self.only_certain_columns( results['hits'], params['_columns'] ) return results else: return {"hits": [], "facets": [], "total": 0} SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse('supersearch.search_results') response = self.client.get( url, {'product': 'WaterWolf'} ) eq_(response.status_code, 200) # Test results are existing ok_('table id="reports-list"' in response.content) ok_('nsASDOMWindowEnumerator::GetNext()' in response.content) ok_('mySignatureIsCool' in response.content) ok_('mineIsCoolerThanYours' in response.content) ok_('EMPTY' in response.content) ok_('aaaaaaaaaaaaa1' in response.content) ok_('888981' in response.content) ok_('Linux' in response.content) ok_('2017-01-31 23:12:57' in response.content) # Test facets are existing ok_('table id="facets-list"' in response.content) # Test bugs are existing ok_('<th scope="col">Bugs</th>' in response.content) ok_('123456' in response.content) # Test links on terms are existing ok_('product=%3DWaterWolf' in response.content) # Test with empty results response = self.client.get(url, { 'product': 'NightTrain', 'date': '2012-01-01' }) eq_(response.status_code, 200) ok_('table id="reports-list"' not in response.content) ok_('No results were found' in response.content) # Test with a signature param response = self.client.get( url, {'signature': '~nsASDOMWindowEnumerator'} ) eq_(response.status_code, 200) ok_('table id="reports-list"' in response.content) ok_('nsASDOMWindowEnumerator::GetNext()' in response.content) ok_('123456' in response.content) # Test with a different facet response = self.client.get( url, {'_facets': 'build_id', 'product': 'SeaMonkey'} ) eq_(response.status_code, 200) ok_('table id="reports-list"' in response.content) ok_('table id="facets-list"' in response.content) ok_('888981' in response.content) # Bugs should not be there, they appear only in the signature facet ok_('<th>Bugs</th>' not in response.content) ok_('123456' not in response.content) # Test with a different columns list response = self.client.get( url, {'_columns': ['build_id', 'platform'], 'product': 'WaterWolf'} ) eq_(response.status_code, 200) ok_('table id="reports-list"' in response.content) ok_('table id="facets-list"' in response.content) # The build and platform appear ok_('888981' in response.content) ok_('Linux' in response.content) # The crash id is always shown ok_('aaaaaaaaaaaaa1' in response.content) # The version and date do not appear ok_('1.0' not in response.content) ok_('2017' not in response.content) # Test missing parameters don't raise an exception. response = self.client.get( url, {'product': 'WaterWolf', 'date': '', 'build_id': ''} ) eq_(response.status_code, 200)
def test_signature_graphs(self): def mocked_supersearch_get(**params): ok_('signature' in params) eq_(params['signature'], ['=' + DUMB_SIGNATURE]) ok_('_histogram.date' in params) ok_('_facets' in params) if 'product' in params['_facets']: return { "hits": [], "total": 4, "facets": { "product": [{ "count": 4, "term": "WaterWolf" }], "histogram_date": [{ "count": 2, "term": "2015-08-05T00:00:00+00:00", "facets": { "product": [{ "count": 2, "term": "WaterWolf" }] } }, { "count": 2, "term": "2015-08-06T00:00:00+00:00", "facets": { "product": [{ "count": 2, "term": "WaterWolf" }] } }] } } return { "hits": [], "total": 0, "facets": { "platform": [], "signature": [], "histogram_date": [] } } SuperSearch.implementation().get.side_effect = mocked_supersearch_get # Test with no results url = reverse('signature:signature_graphs', args=('platform', )) response = self.client.get(url, {'signature': DUMB_SIGNATURE}) eq_(response.status_code, 200) ok_('application/json' in response['content-type']) struct = json.loads(response.content) ok_('aggregates' in struct) eq_(len(struct['aggregates']), 0) ok_('term_counts' in struct) eq_(len(struct['term_counts']), 0) # Test with results url = reverse('signature:signature_graphs', args=('product', )) response = self.client.get(url, {'signature': DUMB_SIGNATURE}) eq_(response.status_code, 200) ok_('application/json' in response['content-type']) struct = json.loads(response.content) ok_('aggregates' in struct) eq_(len(struct['aggregates']), 2) ok_('term_counts' in struct) eq_(len(struct['term_counts']), 1)
def test_SuperSearch(self): def mocked_supersearch_get(**params): assert "exploitability" not in params restricted_params = ("_facets", "_aggs.signature", "_histogram.date") for key in restricted_params: if key in params: assert "url" not in params[key] assert "email" not in params[key] assert "_cardinality.email" not in params[key] if "product" in params: assert params["product"] == ["WaterWolf", "NightTrain"] return { "hits": [{ "signature": "abcdef", "product": "WaterWolf", "version": "1.0", "email": "*****@*****.**", "exploitability": "high", "url": "http://embarassing.website.com", "user_comments": "hey I am [email protected]", }], "facets": { "signature": [] }, "total": 0, } SuperSearch.implementation().get.side_effect = mocked_supersearch_get url = reverse("api:model_wrapper", args=("SuperSearch", )) response = self.client.get(url) assert response.status_code == 200 res = json.loads(response.content) assert res["hits"] assert res["facets"] # Verify forbidden fields are not exposed. assert "email" not in res["hits"] assert "exploitability" not in res["hits"] assert "url" not in res["hits"] # Verify it's not possible to use restricted parameters. response = self.client.get( url, { "exploitability": "high", "_facets": ["url", "email", "product", "_cardinality.email"], "_aggs.signature": ["url", "email", "product", "_cardinality.email"], "_histogram.date": ["url", "email", "product", "_cardinality.email"], }, ) assert response.status_code == 200 # Verify values can be lists. response = self.client.get(url, {"product": ["WaterWolf", "NightTrain"]}) assert response.status_code == 200
def test_signature_summary_with_many_hexes(self, rget): def mocked_get(url, params, **options): if '/graphics_devices' in url: ok_(len(params['vendor_hex']) <= 50) ok_(len(params['adapter_hex']) <= 50) return Response({ 'hits': [], 'total': 0 }) raise NotImplementedError(url) rget.side_effect = mocked_get def mocked_supersearch_get(**params): ok_('signature' in params) eq_(params['signature'], ['=' + DUMB_SIGNATURE]) adapters = [ { 'term': '0x{0:0>4}'.format(i), 'count': 1 } for i in range(50) ] vendors = [ { 'term': '0x{0:0>4}'.format(i), 'count': 50, 'facets': { 'adapter_device_id': adapters } } for i in range(3) ] res = { 'hits': [], 'total': 4, 'facets': { 'adapter_vendor_id': vendors, } } return res SuperSearch.implementation().get.side_effect = ( mocked_supersearch_get ) # Test with no results url = reverse('signature:signature_summary') response = self.client.get(url, { 'signature': DUMB_SIGNATURE, 'product': 'WaterWolf', 'version': '1.0', }) eq_(response.status_code, 200) # There are 150 different hexes, there should be 3 calls to the API. eq_(rget.call_count, 3)