def create_basic_filter(self, countries=None): if countries: country_objs = [CountryFactory(code=code) for code in countries] else: country_objs = [CountryFactory()] return filters.CountryFilter.create( countries=[c.code for c in country_objs])
def test_filter_by_country_one(self): country1 = CountryFactory() country2 = CountryFactory() recipe = RecipeFactory(countries=[country1]) client1 = ClientFactory(country=country1.code) client2 = ClientFactory(country=country2.code) assert recipe.matches(client1) assert not recipe.matches(client2)
def test_update_recipe_country(self, api_client): c1 = CountryFactory(code='US') c2 = CountryFactory(code='CA') r = RecipeFactory(countries=[c1]) res = api_client.patch(f'/api/v1/recipe/{r.pk}/', {'countries': ['CA']}) assert res.status_code == 200 r.refresh_from_db() assert list(r.countries.all()) == [c2]
def test_list_filter_countries(self, api_client): r1 = RecipeFactory(countries=[CountryFactory(code='US')]) r2 = RecipeFactory(countries=[CountryFactory(code='CA')]) res = api_client.get('/api/v1/recipe/?countries=US') assert res.status_code == 200 assert len(res.data) == 1 assert res.data[0]['id'] == r1.id res = api_client.get('/api/v1/recipe/?countries=US,CA') assert res.status_code == 200 assert len(res.data) == 2 for recipe in res.data: assert recipe['id'] in [r1.id, r2.id]
def test_it_works(self, rf): channel = ChannelFactory() country = CountryFactory() locale = LocaleFactory() recipe = RecipeFactory(arguments={'foo': 'bar'}, channels=[channel], countries=[country], locales=[locale]) action = recipe.action serializer = RecipeSerializer(recipe, context={'request': rf.get('/')}) assert serializer.data == { 'name': recipe.name, 'id': recipe.id, 'last_updated': Whatever(), 'enabled': recipe.enabled, 'extra_filter_expression': recipe.extra_filter_expression, 'filter_expression': recipe.filter_expression, 'revision_id': recipe.revision_id, 'action': action.name, 'arguments': { 'foo': 'bar', }, 'channels': [channel.slug], 'countries': [country.code], 'locales': [locale.code] }
def test_canonical_json(self): recipe = RecipeFactory( action=ActionFactory(name='action'), arguments_json='{"foo": 1, "bar": 2}', channels=[ChannelFactory(slug='beta')], countries=[CountryFactory(code='CA')], enabled=False, extra_filter_expression='2 + 2 == 4', locales=[LocaleFactory(code='en-US')], name='canonical', ) # Yes, this is really ugly, but we really do need to compare an exact # byte sequence, since this is used for hashing and signing filter_expression = ( "(normandy.locale in ['en-US']) && (normandy.country in ['CA']) && " "(normandy.channel in ['beta']) && (2 + 2 == 4)") expected = ('{' '"action":"action",' '"arguments":{"bar":2,"foo":1},' '"enabled":false,' '"filter_expression":"%(filter_expression)s",' '"id":%(id)s,' '"is_approved":false,' '"last_updated":"%(last_updated)s",' '"name":"canonical",' '"revision_id":"%(revision_id)s"' '}') % { 'id': recipe.id, 'revision_id': recipe.revision_id, 'last_updated': recipe.last_updated.strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'filter_expression': filter_expression } expected = expected.encode() assert recipe.canonical_json() == expected
def test_classify_empty_time(self, admin_client): """ If the request_time isn't provided, default to the current time. """ locale, other_locale = LocaleFactory.create_batch(2) country = CountryFactory() release_channel = ReleaseChannelFactory() matching_recipe = RecipeFactory( enabled=True, locales=[locale], countries=[country], release_channels=[release_channel], start_time=aware_datetime(2016, 1, 1), end_time=aware_datetime(2016, 1, 3), ) RecipeFactory(locales=[other_locale]) # Non-matching with patch('normandy.classifier.middleware.timezone') as timezone: timezone.now.return_value = aware_datetime(2016, 1, 2) response = admin_client.get( '/admin/classifier_preview', { 'locale': locale.code, 'release_channel': release_channel.slug, 'country': country.code, 'request_time_0': '', 'request_time_1': '', }) assert response.status_code == 200 assert list(response.context['bundle']) == [matching_recipe]
def test_classify(self, admin_client): locale, other_locale = LocaleFactory.create_batch(2) country = CountryFactory() release_channel = ReleaseChannelFactory() matching_recipe = RecipeFactory( enabled=True, locales=[locale], countries=[country], release_channels=[release_channel], start_time=aware_datetime(2016, 1, 1), end_time=aware_datetime(2016, 1, 3), ) RecipeFactory(locales=[other_locale]) # Non-matching response = admin_client.get( '/admin/classifier_preview', { 'locale': locale.code, 'release_channel': release_channel.slug, 'country': country.code, 'request_time_0': '2016-01-02', 'request_time_1': '00:00:00', }) assert response.status_code == 200 assert list(response.context['bundle']) == [matching_recipe]
def test_recipe_revise_countries(self): c1 = CountryFactory(code='CA') recipe = RecipeFactory(countries=[c1]) c2 = CountryFactory(code='US') recipe.revise(countries=[c2]) assert recipe.countries.count() == 1 assert list(recipe.countries.all()) == [c2] recipe.revise(countries=[c1, c2]) countries = list(recipe.countries.all()) assert recipe.countries.count() == 2 assert c1 in countries assert c2 in countries recipe.revise(countries=[]) assert recipe.countries.count() == 0
def test_validation_with_valid_data(self): mockAction = ActionFactory(name='show-heartbeat', arguments_schema=ARGUMENTS_SCHEMA) channel = ChannelFactory(slug='release') country = CountryFactory(code='CA') locale = LocaleFactory(code='en-US') serializer = RecipeSerializer( data={ 'name': 'bar', 'enabled': True, 'extra_filter_expression': '[]', 'action': 'show-heartbeat', 'channels': ['release'], 'countries': ['CA'], 'locales': ['en-US'], 'arguments': { 'surveyId': 'lorem-ipsum-dolor', 'surveys': [{ 'title': 'adipscing', 'weight': 1 }, { 'title': 'consequetar', 'weight': 1 }] } }) assert serializer.is_valid() assert serializer.validated_data == { 'name': 'bar', 'enabled': True, 'extra_filter_expression': '[]', 'action': mockAction, 'arguments': { 'surveyId': 'lorem-ipsum-dolor', 'surveys': [{ 'title': 'adipscing', 'weight': 1 }, { 'title': 'consequetar', 'weight': 1 }] }, 'channels': [channel], 'countries': [country], 'locales': [locale], } assert serializer.errors == {}
def test_filter_expression(self): channel1 = ChannelFactory(slug='beta', name='Beta') channel2 = ChannelFactory(slug='release', name='Release') country1 = CountryFactory(code='US', name='USA') country2 = CountryFactory(code='CA', name='Canada') locale1 = LocaleFactory(code='en-US', name='English (US)') locale2 = LocaleFactory(code='fr-CA', name='French (CA)') r = RecipeFactory() assert r.filter_expression == '' r = RecipeFactory(channels=[channel1]) assert r.filter_expression == "normandy.channel in ['beta']" r.revise(channels=[channel1, channel2]) assert r.filter_expression == "normandy.channel in ['beta', 'release']" r = RecipeFactory(countries=[country1]) assert r.filter_expression == "normandy.country in ['US']" r.revise(countries=[country1, country2]) assert r.filter_expression == "normandy.country in ['CA', 'US']" r = RecipeFactory(locales=[locale1]) assert r.filter_expression == "normandy.locale in ['en-US']" r.revise(locales=[locale1, locale2]) assert r.filter_expression == "normandy.locale in ['en-US', 'fr-CA']" r = RecipeFactory(extra_filter_expression='2 + 2 == 4') assert r.filter_expression == '2 + 2 == 4' r.revise(channels=[channel1], countries=[country1], locales=[locale1]) assert r.filter_expression == ("(normandy.locale in ['en-US']) && " "(normandy.country in ['US']) && " "(normandy.channel in ['beta']) && " "(2 + 2 == 4)")
def test_classify_no_sample(self, admin_client): """The classify view should ignore sampling.""" locale = LocaleFactory() country = CountryFactory() release_channel = ReleaseChannelFactory() recipe = RecipeFactory(sample_rate=0) response = admin_client.get( '/admin/classifier_preview', { 'locale': locale.code, 'release_channel': release_channel.slug, 'country': country.code }) assert response.status_code == 200 assert not recipe.matches(response.context['client']) assert list(response.context['bundle']) == [recipe]
def test_it_works(self, rf): channel = ChannelFactory() country = CountryFactory() locale = LocaleFactory() recipe = RecipeFactory(arguments={'foo': 'bar'}, channels=[channel], countries=[country], locales=[locale]) approval = ApprovalRequestFactory(revision=recipe.latest_revision) action = recipe.action serializer = RecipeSerializer(recipe, context={'request': rf.get('/')}) assert serializer.data == { 'name': recipe.name, 'id': recipe.id, 'last_updated': Whatever(), 'enabled': recipe.enabled, 'extra_filter_expression': recipe.extra_filter_expression, 'filter_expression': recipe.filter_expression, 'action': { 'arguments_schema': {}, 'id': action.id, 'implementation_url': Whatever(), 'name': action.name, }, 'arguments': { 'foo': 'bar', }, 'channels': [channel.slug], 'countries': [country.code], 'locales': [locale.code], 'is_approved': False, 'latest_revision': RecipeRevisionSerializer(recipe.latest_revision).data, 'approved_revision': None, 'approval_request': { 'id': approval.id, 'created': Whatever(), 'creator': Whatever(), 'approved': None, 'approver': None, 'comment': None, }, }