def test_response_view_analyzer(self): """Test secret section only shows up for analyzers""" resp = ResponseFactory(happy=True, description=u'the bestest best!') self.refresh() r = self.client.get(reverse('response_view', args=(resp.id,))) eq_(200, r.status_code) self.assertTemplateUsed(r, 'analytics/response.html') assert str(resp.description) in r.content # Verify there is no secret area visible for non-analyzers. pq = PyQuery(r.content) secretarea = pq('dl.secret') eq_(len(secretarea), 0) jane = ProfileFactory(user__email='*****@*****.**').user jane.groups.add(Group.objects.get(name='analyzers')) self.client_login_user(jane) r = self.client.get(reverse('response_view', args=(resp.id,))) eq_(200, r.status_code) self.assertTemplateUsed(r, 'analytics/response.html') assert str(resp.description) in r.content # Verify the secret area is there. pq = PyQuery(r.content) secretarea = pq('dl.secret') eq_(len(secretarea), 1) # Verify there is an mlt section in the secret area. mlt = pq('dd#mlt') eq_(len(mlt), 1)
def test_response_id_in_qs_authenticated(self): """Verify response_id in querystring overrides session id""" # Create analyzer and log in. jane = AnalyzerProfileFactory(user__email='*****@*****.**').user self.client_login_user(jane) # Create some feedback which sets the response_id in the # session. url = reverse('feedback', args=(u'firefox',), locale='en-US') r = self.client.post(url, { 'happy': 0, 'description': u'Why Firefox not make me sandwiches!', }, follow=True) # Create another piece of feedback which is not the one we # just did. feedback = ResponseFactory(description=u'purple horseshoes') # Fetch the thank you page with the response_id in the # querystring. url = reverse('thanks') + '?response_id={0}'.format(feedback.id) r = self.client.get(url) eq_(r.status_code, 200) eq_(r.context['feedback'].id, feedback.id) eq_(r.context['suggestions'], [])
def test_urls_product_inferred_platform_fxios(self): """Test firefoxdev platform gets inferred""" ProductFactory( enabled=True, display_name=u"Firefox for iOS", db_name=u"Firefox for iOS", slug=u"fxios", on_dashboard=False, on_picker=False, browser=u"Firefox for iOS", ) # Test that we infer the platform if the products are the # same. ua = ( "Mozilla/5.0 (iPod touch; CPU iPhone OS 8_4 like Mac OS X) " "AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/1.0 " "Mobile/12H143 Safari/600.1.4" ) url = reverse("feedback", args=("fxios",)) resp = self.client.post( url, {"happy": 1, "description": u"Firefox for iOS rocks!", "url": u"http://mozilla.org/"}, HTTP_USER_AGENT=ua, ) self.assertRedirects(resp, reverse("thanks")) assert models.Response.objects.count() == 1 feedback = models.Response.objects.latest(field_name="id") assert feedback.locale == "en-US" assert feedback.product == "Firefox for iOS" assert feedback.platform == "iPhone OS 8.4" assert feedback.browser == "Firefox for iOS" assert feedback.browser_version == "1.0" assert feedback.browser_platform == "iPhone OS"
def test_throttle(self): # We allow 50 posts per hour. throttle_trigger = 50 # Descriptions have to be unique otherwise we hit the # double-submit throttling. So we do this fancy thing here. def data_generator(): while True: yield { 'happy': True, 'description': u'Great! ' + str(time.time()), 'product': u'Firefox OS', 'channel': u'stable', 'version': u'1.1', 'platform': u'Firefox OS', 'locale': 'en-US', } data = data_generator() # Now hit the api a fajillion times making sure things got # created for i in range(throttle_trigger): r = self.client.post(reverse('feedback-api'), data.next()) eq_(r.status_code, 201) # This one should trip the throttle trigger r = self.client.post(reverse('feedback-api'), data.next()) eq_(r.status_code, 429)
def test_double_submit_throttling(self): """Verify double-submit throttling.""" # Make sure there are no responses in the db because we're # basing our test on response counts. initial_amount = models.Response.objects.count() eq_(initial_amount, 0) url = reverse('feedback') data = { 'happy': 1, 'description': u'Double-submit is the best!', 'url': u'http://mozilla.org/' } # Post it! r = self.client.post(url, data) self.assertRedirects(r, reverse('thanks')) eq_(models.Response.objects.count(), 1) # Post it again! This time it doesn't get to the db. r = self.client.post(url, data) self.assertRedirects(r, reverse('thanks')) eq_(models.Response.objects.count(), 1) # Post something different from the same ip address. data['description'] = u'Not a double-submit!' r = self.client.post(url, data) self.assertRedirects(r, reverse('thanks')) eq_(models.Response.objects.count(), 2)
def test_update_survey(self): survey = SurveyFactory() data = { 'id': survey.id, 'name': 'rehanrocks', 'description': survey.description, 'enabled': survey.enabled } resp = self.client.post( reverse('hb_surveys_update', args=(survey.id,)), data ) assert resp.status_code == 403 jane = AnalyzerProfileFactory().user self.client_login_user(jane) resp = self.client.post( reverse('hb_surveys_update', args=(survey.id,)), data ) assert resp.status_code == 302 # Make sure it's in the survey list resp = self.client.get(reverse('hb_surveys')) assert resp.status_code == 200 assert data['name'] in resp.content
def test_url_max_length(self): url_base = 'http://example.com/' # Up to 199 characters is fine. data = { 'happy': True, 'channel': u'stable', 'version': u'1.1', 'description': u'Great! 199', 'product': u'Firefox OS', 'platform': u'Firefox OS', 'url': url_base + ('a' * (199 - len(url_base))) + 'b', 'locale': 'en-US', } r = self.client.post(reverse('feedback-api'), data) eq_(r.status_code, 201) # 200th character is not fine. data = { 'happy': True, 'channel': u'stable', 'version': u'1.1', 'description': u'Great! 200', 'product': u'Firefox OS', 'platform': u'Firefox OS', 'url': url_base + ('a' * (200 - len(url_base))) + 'b', 'locale': 'en-US', } r = self.client.post(reverse('feedback-api'), data) eq_(r.status_code, 400)
def test_unicode_in_description(self): """Description should accept unicode data""" url = reverse("feedback", args=(u"firefox",)) r = self.client.post(url, {"url": "http://mozilla.org/", "happy": 0, "description": u"\u2713 this works"}) self.assertRedirects(r, reverse("thanks")) assert models.Response.objects.count() == 1
def test_double_submit_throttle(self): # We disallow two submits in a row of the same description # from the same ip address. data = { 'happy': True, 'description': u'Great!', 'product': u'Firefox OS', 'channel': u'stable', 'version': u'1.1', 'platform': u'Firefox OS', 'locale': 'en-US', } # First time is fine r = self.client.post( reverse('feedback-api'), content_type='application/json', data=json.dumps(data)) assert r.status_code == 201 # Second time and back off! r = self.client.post( reverse('feedback-api'), content_type='application/json', data=json.dumps(data)) assert r.status_code == 429
def test_dashboard_atom_links(self): """Test dashboard atom links are correct""" r = self.client.get(reverse('dashboard')) eq_(200, r.status_code) assert '/en-US/?format=atom' in r.content r = self.client.get( reverse('dashboard'), {'happy': 1}) eq_(200, r.status_code) pq = PyQuery(r.content) pq = pq('link[type="application/atom+xml"]') qs = QueryDict(pq[0].attrib['href'].split('?')[1]) eq_(qs['happy'], u'1') eq_(qs['format'], u'atom') r = self.client.get( reverse('dashboard'), {'product': 'Firefox', 'version': '20.0.0'}) eq_(200, r.status_code) pq = PyQuery(r.content) pq = pq('link[type="application/atom+xml"]') qs = QueryDict(pq[0].attrib['href'].split('?')[1]) eq_(qs['product'], u'Firefox') eq_(qs['version'], u'20.0.0')
def test_valid_happy(self): """Submitting a valid happy form creates an item in the DB. Additionally, it should redirect to the Thanks page. """ amount = models.Response.objects.count() url = reverse('feedback') r = self.client.post(url, { 'happy': 1, 'description': u'Firefox rocks!', 'url': u'http://mozilla.org/' }) self.assertRedirects(r, reverse('thanks')) eq_(amount + 1, models.Response.objects.count()) feedback = models.Response.objects.latest(field_name='id') eq_(u'Firefox rocks!', feedback.description) eq_(u'http://mozilla.org/', feedback.url) eq_(True, feedback.happy) # This comes from the client.post url. eq_(u'en-US', feedback.locale) # Note: This comes from the user agent from the LocalizingClient eq_(u'Firefox', feedback.product) eq_(u'stable', feedback.channel) eq_(u'14.0.1', feedback.version)
def test_reject_non_firefox(self): """Using non-Firefox browser lands you on download-firefox page.""" # TODO: This test might need to change when the router starts routing. url = reverse("feedback") for ua in ( ("Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; " "Trident/5.0)"), ( "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 " "(KHTML, like Gecko) Chrome/24.0.1312.68 Safari/537.17" ), ( "Mozilla/5.0 (Linux; U; Android 4.0.2; en-us; Galaxy Nexus " "Build/ICL53F) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 " "Mobile Safari/534.30" ), ( "Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; Xoom Build/IMM76) " "AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 " "Safari/534.30" ), ( "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.22 (KHTML, like " "Gecko) Chrome/25.0.1364.97 Safari/537.22" ), ): r = self.client.get(url, HTTP_USER_AGENT=ua) self.assertRedirects(r, reverse("download-firefox"))
def test_unicode_in_url(self): """URL should accept unicode data""" url = reverse("feedback", args=("firefox.desktop.stable",)) r = self.client.post(url, {"url": u"http://mozilla.org/\u2713", "happy": 0, "description": u"foo"}) self.assertRedirects(r, reverse("thanks")) eq_(models.Response.objects.count(), 1)
def test_response_view_analyzer(self): """Test secret section only shows up for analyzers""" resp = ResponseFactory(happy=True, description=u'the bestest best!') self.refresh() r = self.client.get(reverse('response_view', args=(resp.id,))) assert r.status_code == 200 self.assertTemplateUsed(r, 'analytics/response.html') assert str(resp.description) in r.content # Verify there is no secret area visible for non-analyzers. pq = PyQuery(r.content) secretarea = pq('dl.secret') assert len(secretarea) == 0 jane = AnalyzerProfileFactory().user self.client_login_user(jane) r = self.client.get(reverse('response_view', args=(resp.id,))) assert r.status_code == 200 self.assertTemplateUsed(r, 'analytics/response.html') assert str(resp.description) in r.content # Verify the secret area is there. pq = PyQuery(r.content) secretarea = pq('dl.secret') assert len(secretarea) == 1 # Verify there is an mlt section in the secret area. mlt = pq('dd#mlt') assert len(mlt) == 1
def test_valid_urls(self): """Test valid url field values""" test_data = [ # input, expected ('example.com', 'http://example.com/'), ('http://example.com', 'http://example.com/'), ('https://example.com', 'https://example.com/'), ('ftp://example.com', ''), # We currently redact ftp urls ('about:config', 'about:config'), ('chrome://foo', 'chrome://foo') ] url = reverse('feedback', args=(u'firefox',)) for item, expected in test_data: cache.clear() r = self.client.post(url, { 'url': item, 'happy': 0, 'description': u'foo' + item }) self.assertRedirects(r, reverse('thanks')) latest = models.Response.objects.latest('pk') eq_(latest.url, expected)
def test_urls_product_no_inferred_platform(self): """Test setting product from the url and platform non-inference""" prod = ProductFactory( display_name=u'Someprod', db_name=u'Someprod', slug=u'someprod', enabled=True, ) amount = models.Response.objects.count() # The UA is for a different browser than what the user is # leaving feedback for, so we should not infer the platform. ua = 'Mozilla/5.0 (Windows NT 6.0; rv:14.0) Gecko/20100101 Firefox/14.0.1' # noqa url = reverse('feedback', args=(prod.slug,)) resp = self.client.post( url, { 'happy': 1, 'description': u'Firefox rocks FFA!', 'url': u'http://mozilla.org/' }, HTTP_USER_AGENT=ua) self.assertRedirects(resp, reverse('thanks')) eq_(amount + 1, models.Response.objects.count()) feedback = models.Response.objects.latest(field_name='id') eq_(u'en-US', feedback.locale) eq_(u'Someprod', feedback.product) eq_(u'', feedback.platform)
def test_valid_happy(self): """Submitting a valid happy form creates an item in the DB. Additionally, it should redirect to the Thanks page. """ amount = models.Response.objects.count() url = reverse("feedback", args=(u"firefox",)) r = self.client.post(url, {"happy": 1, "description": u"Firefox rocks!", "url": u"http://mozilla.org/"}) self.assertRedirects(r, reverse("thanks")) assert amount + 1 == models.Response.objects.count() feedback = models.Response.objects.latest(field_name="id") assert u"Firefox rocks!" == feedback.description assert u"http://mozilla.org/" == feedback.url assert True == feedback.happy # This comes from the client.post url. assert u"en-US" == feedback.locale # Note: This comes from the user agent from the LocalizingClient assert u"Firefox" == feedback.product assert u"14.0.1" == feedback.version # Make sure it doesn't create an email record assert models.ResponseEmail.objects.count() == 0 # Make sure it doesn't create a context record assert models.ResponseContext.objects.count() == 0
def test_valid_sad(self): """Submitting a valid sad form creates an item in the DB. Additionally, it should redirect to the Thanks page. """ amount = models.Response.objects.count() url = reverse('feedback') r = self.client.post(url, { 'happy': 0, 'description': u"Firefox doesn't make me sandwiches. :(" }) self.assertRedirects(r, reverse('thanks')) eq_(amount + 1, models.Response.objects.count()) feedback = models.Response.objects.latest(field_name='id') eq_(u"Firefox doesn't make me sandwiches. :(", feedback.description) eq_(u'', feedback.url) eq_(False, feedback.happy) # This comes from the client.post url. eq_(u'en-US', feedback.locale) # Note: This comes from the user agent from the LocalizingClient eq_(u'Firefox', feedback.product) eq_(u'stable', feedback.channel) eq_(u'14.0.1', feedback.version)
def test_whitespace_description(self): """Descriptions with just whitespace get thrown out""" url = reverse("feedback", args=(u"firefox",)) r = self.client.post(url, {"url": "http://mozilla.org/", "happy": 0, "description": u" "}) self.assertRedirects(r, reverse("thanks")) assert models.Response.objects.count() == 0
def test_composed_prodchan(self): # Test with product and channel data = { "happy": True, "description": u"Great!", "product": u"Firefox OS", "channel": u"stable", "version": u"1.1", "platform": u"Firefox OS", "locale": "en-US", } r = self.client.post(reverse("api-post-feedback"), data) eq_(r.status_code, 201) feedback = models.Response.uncached.latest(field_name="id") eq_(feedback.prodchan, u"firefoxos.stable") # Test with a product, but no channel data = { "happy": True, "description": u"Great!", "product": u"Firefox OS", "version": u"1.1", "platform": u"Firefox OS", "locale": "en-US", } r = self.client.post(reverse("api-post-feedback"), data) eq_(r.status_code, 201) feedback = models.Response.uncached.latest(field_name="id") eq_(feedback.prodchan, u"firefoxos.unknown")
def test_products_and_versions(self): self.create_basic_data() resp = self.client.get(reverse('feedback-api'), {'products': 'Firefox'}) json_data = json.loads(resp.content) assert json_data['count'] == 2 assert len(json_data['results']) == 2 resp = self.client.get(reverse('feedback-api'), {'products': 'Firefox,Firefox for Android'}) json_data = json.loads(resp.content) assert json_data['count'] == 3 assert len(json_data['results']) == 3 # version without product gets ignored resp = self.client.get(reverse('feedback-api'), {'versions': '30.0'}) json_data = json.loads(resp.content) assert json_data['count'] == 3 assert len(json_data['results']) == 3 resp = self.client.get(reverse('feedback-api'), {'products': 'Firefox', 'versions': '30.0'}) json_data = json.loads(resp.content) assert json_data['count'] == 1 assert len(json_data['results']) == 1
def test_throttle(self): # This test is a little goofy. Essentially we figure out what # the throttle trigger is, post that many times, then post # once more to see if it gets throttled. So if the trigger is # 100, then we post 101 times which seems kind of excessive # in a test. # Get the trigger so that we can post that many times + 1 # to test throttling trigger = settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["anon"] trigger = int(trigger.split("/")[0]) data = { "happy": True, "description": u"Great!", "product": u"Firefox OS", "channel": u"stable", "version": u"1.1", "platform": u"Firefox OS", "locale": "en-US", } # Now hit the api a fajillion times making sure things got # created for i in range(trigger): r = self.client.post(reverse("api-post-feedback"), data) eq_(r.status_code, 201) # This one should trip the throttle trigger r = self.client.post(reverse("api-post-feedback"), data) eq_(r.status_code, 429)
def test_urls_locale(self): """Test setting locale from the locale part of the url""" try: count = models.Response.objects.count() # Hard-coded url so we're guaranteed to get /es/. url = reverse('feedback', args=(u'firefox',), locale='es') resp = self.client.post(url, { 'happy': 1, 'description': u'Firefox rocks for es!', 'url': u'http://mozilla.org/' }) self.assertRedirects(resp, reverse('thanks')) eq_(count + 1, models.Response.objects.count()) feedback = models.Response.objects.latest(field_name='id') eq_(u'es', feedback.locale) eq_(u'Firefox', feedback.product) eq_(u'14.0.1', feedback.version) finally: # FIXME - We have to do another request to set the # LocalizingClient back to en-US otherwise it breaks all # tests ever. This is goofy-pants since it should get # reset in test teardown. resp = self.client.get('/en-US/feedback/')
def test_throttle(self): # This test is a little goofy. Essentially we figure out what # the throttle trigger is, post that many times, then post # once more to see if it gets throttled. So if the trigger is # 100, then we post 101 times which seems kind of excessive # in a test. # Get the trigger so that we can post that many times + 1 # to test throttling trigger = settings.REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']['anon'] trigger = int(trigger.split('/')[0]) data = { 'happy': True, 'description': u'Great!', 'product': u'Firefox OS', 'channel': u'stable', 'version': u'1.1', 'platform': u'Firefox OS', 'locale': 'en-US', } # Now hit the api a fajillion times making sure things got # created for i in range(trigger): r = self.client.post(reverse('api-post-feedback'), data) eq_(r.status_code, 201) # This one should trip the throttle trigger r = self.client.post(reverse('api-post-feedback'), data) eq_(r.status_code, 429)
def test_composed_prodchan(self): # Test with product and channel data = { 'happy': True, 'description': u'Great!', 'product': u'Firefox OS', 'channel': u'stable', 'version': u'1.1', 'platform': u'Firefox OS', 'locale': 'en-US', } r = self.client.post(reverse('feedback-api'), data) eq_(r.status_code, 201) feedback = models.Response.uncached.latest(field_name='id') eq_(feedback.prodchan, u'firefoxos.stable') # Test with a product, but no channel data = { 'happy': True, 'description': u'Great! Hazzah!', 'product': u'Firefox OS', 'version': u'1.1', 'platform': u'Firefox OS', 'locale': 'en-US', } r = self.client.post(reverse('feedback-api'), data) eq_(r.status_code, 201) feedback = models.Response.uncached.latest(field_name='id') eq_(feedback.prodchan, u'firefoxos.unknown')
def test_throttled(self): """Verify that posts are throttled.""" # Make sure there are no responses in the db because we're # basing our test on response counts. initial_amount = models.Response.objects.count() eq_(initial_amount, 0) url = reverse('feedback') # Toss 100 responses in. for i in range(100): r = self.client.post(url, { 'happy': 1, 'description': u'{0} Firefox rocks! {0}'.format(i), 'url': u'http://mozilla.org/' }) eq_(models.Response.objects.count(), 100) # The 101st should be throttled, so there should only be 100 # responses in the db. r = self.client.post(url, { 'happy': 1, 'description': u'Firefox rocks!', 'url': u'http://mozilla.org/' }) eq_(models.Response.objects.count(), 100) # Make sure we still went to the Thanks page. self.assertRedirects(r, reverse('thanks'))
def test_products_and_versions(self): self.create_basic_data() resp = self.client.get(reverse('feedback-api'), {'products': 'Firefox'}) json_data = json.loads(resp.content) eq_(json_data['count'], 2) eq_(len(json_data['results']), 2) resp = self.client.get(reverse('feedback-api'), {'products': 'Firefox,Firefox for Android'}) json_data = json.loads(resp.content) eq_(json_data['count'], 3) eq_(len(json_data['results']), 3) # version without product gets ignored resp = self.client.get(reverse('feedback-api'), {'versions': '30.0'}) json_data = json.loads(resp.content) eq_(json_data['count'], 3) eq_(len(json_data['results']), 3) resp = self.client.get(reverse('feedback-api'), {'products': 'Firefox', 'versions': '30.0'}) json_data = json.loads(resp.content) eq_(json_data['count'], 1) eq_(len(json_data['results']), 1)
def test_double_submit_throttling(self): """Verify double-submit throttling.""" # Make sure there are no responses in the db because we're # basing our test on response counts. initial_amount = models.Response.objects.count() assert initial_amount == 0 url = reverse("feedback", args=(u"firefox",)) data = {"happy": 1, "description": u"Double-submit is the best!", "url": u"http://mozilla.org/"} # Post it! r = self.client.post(url, data) self.assertRedirects(r, reverse("thanks")) assert models.Response.objects.count() == 1 # Post it again! This time it doesn't get to the db. r = self.client.post(url, data) self.assertRedirects(r, reverse("thanks")) assert models.Response.objects.count() == 1 # Post something different from the same ip address. data["description"] = u"Not a double-submit!" r = self.client.post(url, data) self.assertRedirects(r, reverse("thanks")) assert models.Response.objects.count() == 2
def test_missing_data(self): data = {} resp = self.client.post( reverse('heartbeat-api'), content_type='application/json', data=json.dumps(data)) eq_(resp.status_code, 400) json_data = json.loads(resp.content) eq_(json_data['msg'], 'missing fields: answer, channel, locale, platform, poll, ' 'product, version') data = { 'locale': 'es' } resp = self.client.post( reverse('heartbeat-api'), content_type='application/json', data=json.dumps(data)) eq_(resp.status_code, 400) json_data = json.loads(resp.content) eq_(json_data['msg'], 'missing fields: answer, channel, platform, poll, ' 'product, version')
def test_new_user(self): """Tests that new users get redirected to new_user page""" # Create a user that has no profile--this is the sign that the # user is new! new_user = UserFactory(profile=None) self.client_login_user(new_user) # Now do some ridiculous setup so we can call login_success() # on the Verify and see if it did what it should be doing. # FIXME - this can go away post django-browserid 0.9 new_user.backend = 'django_browserid.auth.BrowserIDBackend' post_request = RequestFactory().post(reverse('browserid.login')) post_request.user = new_user post_request.session = self.client.session fv = FjordVerify() fv.user = new_user fv.request = post_request resp = fv.login_success() eq_(200, resp.status_code) body = json.loads(resp.content) eq_(body['redirect'], reverse('new-user-view'))
def test_minimal_data(self): """Minimum amount of data required""" survey = SurveyFactory.create() data = { 'experiment_version': '1', 'response_version': 1, 'person_id': 'joemamma', 'survey_id': survey.name, 'flow_id': '20141113', 'question_id': '1', 'updated_ts': self.timestamp(), 'question_text': 'how was lunch?', 'variation_id': '1' } resp = self.client.post( reverse('heartbeat-api'), content_type='application/json', data=json.dumps(data)) assert resp.status_code == 201
def test_picker_with_disabled_products(self): ProductFactory(display_name=u'ProductFoo', slug=u'productfoo', enabled=True) ProductFactory(display_name=u'ProductBar', slug=u'productbar', enabled=False) cache.clear() resp = self.client.get(reverse('feedback')) eq_(resp.status_code, 200) # This is on the picker self.assertContains(resp, 'ProductFoo') self.assertContains(resp, 'productfoo') # This is not on the picker self.assertNotContains(resp, 'ProductBar') self.assertNotContains(resp, 'productbar')
def test_old_responses(self): # Make sure we can't see responses from > 180 days ago cutoff = datetime.today() - timedelta(days=180) ResponseFactory(description='Young enough--Party!', created=cutoff + timedelta(days=1)) ResponseFactory(description='Too old--Get off my lawn!', created=cutoff - timedelta(days=1)) self.refresh() resp = self.client.get( reverse('feedback-api'), { 'date_start': (cutoff - timedelta(days=1)).strftime('%Y-%m-%d'), 'date_end': (cutoff + timedelta(days=1)).strftime('%Y-%m-%d') }) json_data = json.loads(resp.content) results = json_data['results'] assert len(results) == 1 assert 'Young enough--Party!' in resp.content assert 'Too old--Get off my lawn!' not in resp.content
def test_minimal(self): data = { 'happy': True, 'description': u'Great!', 'product': u'Firefox OS' } r = self.client.post(reverse('feedback-api'), content_type='application/json', data=json.dumps(data)) assert r.status_code == 201 feedback = models.Response.objects.latest(field_name='id') assert feedback.happy is True assert feedback.description == data['description'] assert feedback.product == data['product'] # Fills in defaults assert feedback.url == u'' assert feedback.api == 1 assert feedback.user_agent == u''
def test_invalid_search(self): url = reverse('dashboard') # Invalid values for happy shouldn't filter r = self.client.get(url, {'happy': 'fish'}) eq_(r.status_code, 200) pq = PyQuery(r.content) eq_(len(pq('li.opinion')), 7) # Unknown parameters should be ignored. r = self.client.get(url, {'apples': 'oranges'}) eq_(r.status_code, 200) pq = PyQuery(r.content) eq_(len(pq('li.opinion')), 7) # A broken date range search shouldn't affect anything # Why this? Because this is the thing the fuzzer found. r = self.client.get(url, { 'date_end': '/etc/shadow\x00', 'date_start': '/etc/passwd\x00' }) eq_(r.status_code, 200) pq = PyQuery(r.content) eq_(len(pq('li.opinion')), 7)
def test_picker_with_not_on_picker_products(self): ProductFactory(display_name=u'ProductFoo', slug=u'productfoo', on_picker=True) ProductFactory(display_name=u'ProductBar', slug=u'productbar', on_picker=False) cache.clear() resp = self.client.get(reverse('picker')) assert resp.status_code == 200 # This is on the picker assert 'ProductFoo' in resp.content assert 'productfoo' in resp.content # This is not on the picker assert 'ProductBar' not in resp.content assert 'productbar' not in resp.content
def test_fjord_authorization_token(self): """Verify auth will use Fjord-Authorization header if Authorization isn't there """ token = TokenFactory() flavor = AlertFlavorFactory(name='Foo', slug='fooflavor') flavor.allowed_tokens.add(token) qs = { 'flavors': flavor.slug } resp = self.client.get( reverse('alerts-api') + '?' + urllib.urlencode(qs), HTTP_FJORD_AUTHORIZATION='token ' + token.token ) assert resp.status_code == 200 assert ( json.loads(resp.content) == {u'count': 0, u'total': 0, u'alerts': []} )
def test_zero_fill(self): """If a day in a date range has no data, it should be zero filled.""" # Note that we request a date range that includes 3 days without data. url = reverse('dashboard') start = (datetime.now() - timedelta(days=9)) end = (datetime.now() - timedelta(days=3)) r = self.client.get( url, { 'date_start': start.strftime('%Y-%m-%d'), 'date_end': end.strftime('%Y-%m-%d'), }) # The histogram data is of the form [d, v], where d is a number of # milliseconds since the epoch, and v is the value at that time stamp. dates = [d[0] for d in r.context['histogram'][0]['data']] dates = [datetime.fromtimestamp(d / 1000) for d in dates] days = [d.day for d in dates] d = start while d <= end: assert d.day in days, "Day %s has no data." % d.day d += timedelta(days=1)
def test_max(self): token = TokenFactory() flavor = AlertFlavorFactory(name='Foo', slug='fooflavor') flavor.allowed_tokens.add(token) alert1 = AlertFactory(summary=u'alert 1', flavor=flavor) # We backdate the created so we can verify we're getting the # right order of alerts. alert1.created = datetime.datetime.now() - datetime.timedelta(days=5) alert1.save() AlertFactory(summary=u'alert 2', flavor=flavor) qs = {'flavors': flavor.slug, 'max': 1} resp = self.client.get(reverse('alerts-api') + '?' + urllib.urlencode(qs), HTTP_AUTHORIZATION='token ' + token.token) eq_(resp.status_code, 200) eq_( json.loads(resp.content), { u'count': 1, u'total': 2, u'alerts': [{ u'id': WHATEVER, u'summary': u'alert 2', u'description': u'the account balance is at $5.', u'flavor': flavor.slug, u'emitter_version': 0, u'emitter_name': u'balance-checker', u'start_time': None, u'end_time': None, u'created': WHATEVER, u'severity': 0, u'links': [] }] })
def test_survey_doesnt_exist(self): """If the survey doesn't exist, kick up an error""" data = { 'experiment_version': '1', 'response_version': 1, 'person_id': 'joemamma', 'survey_id': 'foosurvey', 'flow_id': '20141113', 'question_id': '1', 'updated_ts': self.timestamp(), 'question_text': 'how was lunch?', 'variation_id': '1' } resp = self.client.post(reverse('heartbeat-api'), content_type='application/json', data=json.dumps(data)) eq_(resp.status_code, 400) errors = json.loads(resp.content)['errors'] eq_(errors['survey_id'], [u'Object with name=foosurvey does not exist.'])
def test_add_product(self): jane = AnalyzerProfileFactory().user self.client_login_user(jane) data = { 'enabled': True, 'display_name': 'Rehan', 'display_description': '*the* Rehan', 'db_name': 'rehan', 'slug': 'rehan', 'on_dashboard': True, 'on_picker': True, 'browser': '', 'browser_data_browser': '', 'notes': '' } resp = self.client.post(reverse('analytics_products'), data, follow=True) assert resp.status_code == 200 assert data['display_name'] in resp.content
def test_monitor_view(self): """Tests for the monitor view.""" # TODO: When we add a mocking framework, we can mock this # properly. test_memcached = views.test_memcached try: with self.settings( SHOW_STAGE_NOTICE=True, CACHES={ 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': ['localhost:11211', 'localhost2:11211'] } }): # Mock the test_memcached function so it always returns # True. views.test_memcached = lambda host, port: True # TODO: Replace when we get a mock library. def mock_rabbitmq(): class MockRabbitMQ(object): def connect(self): return True return lambda *a, **kw: MockRabbitMQ() views.establish_connection = mock_rabbitmq() # Request /services/monitor and make sure it returns # HTTP 200 and that there aren't errors on the page. resp = self.client.get(reverse('services-monitor')) errors = [line for line in resp.content.splitlines() if 'ERROR' in line] eq_(resp.status_code, 200, '%s != %s (%s)' % ( resp.status_code, 200, repr(errors))) finally: views.test_memcached = test_memcached
def test_with_context_20_pairs(self): data = { 'happy': True, 'description': u'Great!', 'product': u'Firefox OS', 'channel': u'stable', 'version': u'1.1', 'platform': u'Firefox OS', 'locale': 'en-US', 'email': '*****@*****.**', } for i in range(25): data['foo%02d' % i] = str(i) r = self.client.post(reverse('feedback-api'), data) eq_(r.status_code, 201) context = models.ResponseContext.objects.latest(field_name='id') data = sorted(context.data.items()) eq_(len(data), 20) eq_(data[0], ('foo00', '0')) eq_(data[-1], ('foo19', '19'))
def test_deprecated_firefox_for_android_minimal(self): """Test the minimal post data from FfA works.""" data = { '_type': 1, 'description': u'This is how to make it better...', 'device': 'Stone tablet', 'manufacturer': 'Rosetta' } ua = 'Mozilla/5.0 (Android; Tablet; rv:24.0) Gecko/24.0 Firefox/24.0' r = self.client.post(reverse('feedback'), data, HTTP_USER_AGENT=ua) assert r.status_code == 302 feedback = models.Response.objects.latest(field_name='id') assert feedback.happy is True assert feedback.url == u'' assert feedback.description == data['description'] # This comes from the client.post url. assert u'en-US' == feedback.locale # Note: This comes from the user agent from the LocalizingClient assert u'Firefox for Android' == feedback.product assert u'24.0' == feedback.version
def test_survey_disabled(self): """If the survey is disabled, kick up an error""" survey = SurveyFactory.create(enabled=False) data = { 'experiment_version': '1', 'response_version': 1, 'person_id': 'joemamma', 'survey_id': survey.name, 'flow_id': '20141113', 'question_id': '1', 'updated_ts': self.timestamp(), 'question_text': 'how was lunch?', 'variation_id': '1' } resp = self.client.post(reverse('heartbeat-api'), content_type='application/json', data=json.dumps(data)) eq_(resp.status_code, 400) errors = json.loads(resp.content)['errors'] eq_(errors['survey_id'], ['survey "%s" is not enabled' % survey.name])
def test_country_unknown(self): """This is a stopgap fix for handling 'unknown' value for country""" survey = SurveyFactory.create() data = { 'experiment_version': '1', 'response_version': 1, 'person_id': 'joemamma', 'survey_id': survey.name, 'flow_id': '20141113', 'question_id': '1', 'updated_ts': self.timestamp(), 'question_text': 'ou812?', 'variation_id': '1', 'country': 'unknown' } resp = self.client.post(reverse('heartbeat-api'), content_type='application/json', data=json.dumps(data)) assert resp.status_code == 201 ans = Answer.objects.latest('id') assert ans.country == 'UNK'
def test_links(self): token = TokenFactory() flavor = AlertFlavorFactory(name='Foo', slug='fooflavor') flavor.allowed_tokens.add(token) alert = AlertFactory(summary=u'alert 1', flavor=flavor) link = LinkFactory(alert=alert) qs = {'flavors': flavor.slug} resp = self.client.get(reverse('alerts-api') + '?' + urllib.urlencode(qs), HTTP_AUTHORIZATION='token ' + token.token) eq_(resp.status_code, 200) eq_( json.loads(resp.content), { u'count': 1, u'total': 1, u'alerts': [{ u'id': WHATEVER, u'summary': u'alert 1', u'description': u'the account balance is at $5.', u'flavor': flavor.slug, u'emitter_version': 0, u'emitter_name': u'balance-checker', u'start_time': None, u'end_time': None, u'created': WHATEVER, u'severity': 0, u'links': [{ u'name': link.name, u'url': link.url }] }] })
def test_get_suggestions(self): url = reverse('feedback', args=(u'firefox', )) desc = u'slow browser please speed improve i am wait speed improv 2' # Post some basic feedback that meets the SUMO Suggest # Provider standards and follow through to the Thank You # page. This triggers the suggestions and docs should be # in the session. resp = self.client.post(url, { 'happy': 0, 'description': desc, }, follow=True) feedback_id = self.client.session['response_id'] session_key = SUMO_SUGGEST_SESSION_KEY.format(feedback_id) # Verify we get the right number of docs from the SUMO Suggest # API and that the urls start with SUMO_HOST. docs = self.client.session[session_key] assert 0 < len(docs) <= 3 for doc in docs: assert doc['url'].startswith(SUMO_HOST) # Note: Since SUMO content changes, we can't check specific # strings since we don't really know what it's going to # return. links = resp.jinja_context['suggestions'] assert links[0].provider == 'sumosuggest' assert links[0].provider_version == 1 # Verify that the first link has non-empty summary, url and # description. assert links[0].summary assert links[0].url assert links[0].description
def test_empty_tr(self): feedback_responses = ResponseFactory.create_batch(5) jane = AnalyzerProfileFactory().user self.client_login_user(jane) data = { 'locales': [], 'products': [], 'versions': [], 'keywords': [], 'url_exists': None } resp = self.client.post( reverse('triggerrule-match'), content_type='application/json', data=json.dumps(data) ) assert resp.status_code == 200 # Note: This matches everything because it's an empty rule. assert ( [item['id'] for item in json.loads(resp.content)['results']] == [fr.id for fr in reversed(feedback_responses)] )
def test_contents(self): fr = ResponseFactory() jane = AnalyzerProfileFactory().user self.client_login_user(jane) data = { 'locales': [], 'products': [], 'versions': [], 'keywords': [], 'url_exists': None } resp = self.client.post( reverse('triggerrule-match'), content_type='application/json', data=json.dumps(data) ) assert resp.status_code == 200 content = json.loads(resp.content) assert ( content['results'] == [ { u'id': int(fr.id), u'created': fr.created.strftime(u'%Y-%m-%dT%H:%M:%S'), u'description': fr.description, u'happy': fr.happy, u'locale': fr.locale, u'product': fr.product, u'platform': fr.platform, u'url': fr.url, u'version': fr.version } ] )
def test_deprecated_firefox_for_android_minimal(self): """Test the minimal post data from FfA works.""" data = { '_type': 1, 'description': u'This is how to make it better...', 'device': 'Stone tablet', 'manufacturer': 'Rosetta' } ua = 'Mozilla/5.0 (Android; Tablet; rv:24.0) Gecko/24.0 Firefox/24.0' r = self.client.post(reverse('feedback'), data, HTTP_USER_AGENT=ua) eq_(r.status_code, 302) feedback = models.Response.objects.latest(field_name='id') eq_(feedback.happy, True) eq_(feedback.url, u'') eq_(feedback.description, data['description']) # This comes from the client.post url. eq_(u'en-US', feedback.locale) # Note: This comes from the user agent from the LocalizingClient eq_(u'Firefox for Android', feedback.product) eq_(u'stable', feedback.channel) eq_(u'24.0.0', feedback.version)
def test_deprecated_firefox_for_android_sad_is_sad(self): data = { '_type': 2, 'description': u'This is how to make it better...', 'add_url': 1, 'url': u'http://mozilla.org/', 'device': 'Stone tablet', 'manufacturer': 'Rosetta' } ua = 'Mozilla/5.0 (Android; Tablet; rv:24.0) Gecko/24.0 Firefox/24.0' r = self.client.post(reverse('feedback'), data, HTTP_USER_AGENT=ua) eq_(r.status_code, 302) feedback = models.Response.objects.latest(field_name='id') eq_(feedback.happy, False) eq_(feedback.url, data['url']) eq_(feedback.description, data['description']) # This comes from the client.post url. eq_(u'en-US', feedback.locale) # Note: This comes from the user agent from the LocalizingClient eq_(u'Firefox for Android', feedback.product) eq_(u'24.0', feedback.version)
def test_firefox_os_view(self): """Firefox OS returns correct view""" # Specifying fxos as the product in the url url = reverse('feedback', args=(u'fxos', )) r = self.client.get(url) assert template_used(r, 'feedback/fxos_feedback.html')
def test_android_view(self): """Android returns correct view""" url = reverse('feedback', args=(u'android', )) r = self.client.get(url) assert template_used(r, 'feedback/android_feedback.html')
def test_text_search_unicode(self): """Unicode in the search field shouldn't kick up errors""" url = reverse('dashboard') # Text search r = self.client.get(url, {'q': u'\u2713'}) eq_(r.status_code, 200)
def test_frontpage_index_missing(self): """If index is missing, show es_down template.""" self.teardown_indexes() resp = self.client.get(reverse('dashboard')) self.assertTemplateUsed(resp, 'analytics/es_down.html')
def test_sad_redirect(self): r = self.client.get(reverse('sad-redirect')) self.assertRedirects(r, reverse('feedback') + '?happy=0')
def test_happy_redirect(self): r = self.client.get(reverse('happy-redirect')) self.assertRedirects(r, reverse('feedback') + '?happy=1')
def test_picker_no_products(self): resp = self.client.get(reverse('feedback')) assert resp.status_code == 200 assert template_used(resp, 'feedback/picker.html') assert 'No products available.' in resp.content
def test_picker_no_products(self): resp = self.client.get(reverse('feedback')) eq_(resp.status_code, 200) self.assertTemplateUsed(resp, 'feedback/picker.html') assert 'No products available.' in resp.content