class TestSuggestionsApi(ESTestCase): fixtures = fixture("webapp_337141") def setUp(self): self.url = reverse("suggestions-search-api") self.refresh("webapp") self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.save() self.app2 = app_factory( name=u"Second âpp", description=u"Second dèsc" * 25, icon_type="image/png", created=self.days_ago(3) ) self.refresh("webapp") def tearDown(self): # Cleanup to remove these from the index. unindex_webapps([self.app1.id, self.app2.id]) self.app1.delete() self.app2.delete() def test_suggestions(self): response = self.client.get(self.url, data={"lang": "en-US"}) parsed = json.loads(response.content) eq_(parsed[0], "") self.assertSetEqual(parsed[1], [unicode(self.app1.name), unicode(self.app2.name)]) self.assertSetEqual(parsed[2], [unicode(self.app1.description), unicode(truncate(self.app2.description))]) self.assertSetEqual(parsed[3], [absolutify(self.app1.get_detail_url()), absolutify(self.app2.get_detail_url())]) self.assertSetEqual(parsed[4], [self.app1.get_icon_url(64), self.app2.get_icon_url(64)]) def test_suggestions_filtered(self): response = self.client.get(self.url, data={"q": "Second", "lang": "en-US"}) parsed = json.loads(response.content) eq_(parsed[1], [unicode(self.app2.name)])
def test_owner_still_non_reviewer_access(self): user = Webapp.objects.get(pk=337141).authors.all()[0] access = Access.objects.create( key='test_oauth_key_owner', secret='super secret', user=user) client = RestOAuthClient(access) res = client.get(self.url) eq_(res.status_code, 403)
def setUp(self): self.client = RestOAuthClient(None) self.url = reverse('search-api') self.webapp = Webapp.objects.get(pk=337141) self.category = Category.objects.create(name='test', slug='test', type=amo.ADDON_WEBAPP) self.webapp.icon_hash = 'fakehash' self.webapp.save() self.refresh('webapp')
def test_admin_get(self): self.create_app() admin = UserProfile.objects.get(email="*****@*****.**") g = Group.objects.create(rules="*:*") GroupUser.objects.create(group=g, user=admin) ac = Access.objects.create(key="adminOauthKey", secret=generate(), user=admin.user) client = RestOAuthClient(ac) r = client.get(self.get_url) eq_(r.status_code, 200)
def test_reviewer_get(self): self.create_app() editor = UserProfile.objects.get(email="*****@*****.**") g = Group.objects.create(rules="Apps:Review,Reviews:Edit") GroupUser.objects.create(group=g, user=editor) ac = Access.objects.create(key="adminOauthKey", secret=generate(), user=editor.user) client = RestOAuthClient(ac) r = client.get(self.get_url) eq_(r.status_code, 200)
def setUp(self): self.client = RestOAuthClient(None) self.url = reverse('search-api') self.webapp = Webapp.objects.get(pk=337141) self.category = Category.objects.create(name='test', type=amo.ADDON_WEBAPP) # Pick a few common device features. self.profile = FeatureProfile(apps=True, audio=True, fullscreen=True, geolocation=True, indexeddb=True, sms=True).to_signature() self.qs = {'q': 'something', 'pro': self.profile, 'dev': 'firefoxos'}
def test_admin_get(self): self.create_app() admin = UserProfile.objects.get(email='*****@*****.**') g = Group.objects.create(rules='*:*') GroupUser.objects.create(group=g, user=admin) ac = Access.objects.create(key='adminOauthKey', secret=generate(), user=admin.user) client = RestOAuthClient(ac) r = client.get(self.get_url) eq_(r.status_code, 200)
def test_reviewer_get(self): self.create_app() editor = UserProfile.objects.get(email='*****@*****.**') g = Group.objects.create(rules='Apps:Review,Reviews:Edit') GroupUser.objects.create(group=g, user=editor) ac = Access.objects.create(key='adminOauthKey', secret=generate(), user=editor.user) client = RestOAuthClient(ac) r = client.get(self.get_url) eq_(r.status_code, 200)
def setUp(self): self.url = reverse('suggestions-search-api') self.refresh('webapp') self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.save() self.app2 = app_factory(name=u'Second âpp', description=u'Second dèsc' * 25, icon_type='image/png', created=self.days_ago(3)) self.refresh('webapp')
def setUp(self): self.client = RestOAuthClient(None) self.url = reverse('search-api') self.webapp = Webapp.objects.get(pk=337141) self.webapp.addondevicetype_set.create(device_type=amo.DEVICE_GAIA.id) # Pick a few common device features. self.profile = FeatureProfile(apps=True, audio=True, fullscreen=True, geolocation=True, indexeddb=True, sms=True).to_signature() self.qs = {'q': 'something', 'pro': self.profile, 'dev': 'firefoxos'}
def setUp(self): self.url = reverse('rocketbar-search-api') self.refresh('webapp') self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.save() self.app2 = app_factory( name=u'Second âpp', description=u'Second dèsc' * 25, icon_type='image/png', created=self.days_ago(3), manifest_url='http://testrocketbar.example.com') self.refresh('webapp')
class TestSuggestionsApi(ESTestCase): fixtures = fixture('webapp_337141') def setUp(self): self.url = reverse('suggestions-search-api') self.refresh('webapp') self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.save() self.app2 = app_factory(name=u'Second âpp', description=u'Second dèsc' * 25, icon_type='image/png', created=self.days_ago(3)) self.refresh('webapp') def tearDown(self): # Cleanup to remove these from the index. unindex_webapps([self.app1.id, self.app2.id]) self.app1.delete() self.app2.delete() def test_suggestions(self): response = self.client.get(self.url, data={'lang': 'en-US'}) parsed = json.loads(response.content) eq_(parsed[0], '') self.assertSetEqual(parsed[1], [unicode(self.app1.name), unicode(self.app2.name)]) self.assertSetEqual(parsed[2], [ unicode(self.app1.description), unicode(truncate(self.app2.description)) ]) self.assertSetEqual(parsed[3], [ absolutify(self.app1.get_detail_url()), absolutify(self.app2.get_detail_url()) ]) self.assertSetEqual( parsed[4], [self.app1.get_icon_url(64), self.app2.get_icon_url(64)]) def test_suggestions_filtered(self): response = self.client.get(self.url, data={ 'q': 'Second', 'lang': 'en-US' }) parsed = json.loads(response.content) eq_(parsed[1], [unicode(self.app2.name)])
class TestRocketbarApi(ESTestCase): fixtures = fixture('webapp_337141') def setUp(self): self.url = reverse('rocketbar-search-api') self.refresh('webapp') self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.save() self.app2 = app_factory(name=u'Second âpp', description=u'Second dèsc' * 25, icon_type='image/png', created=self.days_ago(3), manifest_url='http://testrocketbar.example.com') self.refresh('webapp') def tearDown(self): # Cleanup to remove these from the index. unindex_webapps([self.app1.id, self.app2.id]) self.app1.delete() self.app2.delete() def test_suggestions_filtered(self): response = self.client.get(self.url, data={'q': 'Second', 'lang': 'en-US'}) parsed = json.loads(response.content) eq_(parsed, [{'manifest_url': self.app2.get_manifest_url(), 'icon': self.app2.get_icon_url(64), 'name': unicode(self.app2.name), 'slug': self.app2.app_slug}])
def test_admin_get(self): app = self.create_app(privacy_policy=u'élolà') admin = UserProfile.objects.get(email='*****@*****.**') g = Group.objects.create(rules='*:*') GroupUser.objects.create(group=g, user=admin) ac = Access.objects.create(key='adminOauthKey', secret='admin secret', user=admin) client = RestOAuthClient(ac) r = client.get(self.get_url) eq_(r.status_code, 200) res = client.get(reverse('app-privacy-policy-detail', args=[app.pk])) eq_(r.status_code, 200) eq_(res.json['privacy_policy'], u'élolà')
def setUp(self): self.client = RestOAuthClient(None) self.url = reverse("search-api") self.webapp = Webapp.objects.get(pk=337141) self.category = Category.objects.create(name="test", slug="test", type=amo.ADDON_WEBAPP) self.webapp.save() self.refresh("webapp")
def test_admin_get(self): app = self.create_app() data = self.base_data() self.client.put(self.get_url, data=json.dumps(data)) admin = UserProfile.objects.get(email="*****@*****.**") g = Group.objects.create(rules="*:*") GroupUser.objects.create(group=g, user=admin) ac = Access.objects.create(key="adminOauthKey", secret=generate(), user=admin) client = RestOAuthClient(ac) r = client.get(self.get_url) eq_(r.status_code, 200) res = client.get(reverse("app-privacy-policy-detail", args=[app.pk])) eq_(r.status_code, 200) eq_(res.json["privacy_policy"], data["privacy_policy"])
def setUp(self): self.client = RestOAuthClient(None) self.url = reverse('search-api') self.webapp = Webapp.objects.get(pk=337141) self.category = 'books' self.webapp.icon_hash = 'fakehash' self.webapp.save() self.refresh('webapp')
def setUp(self): self.client = RestOAuthClient(None) self.url = reverse("search-api") self.webapp = Webapp.objects.get(pk=337141) self.category = "books" self.webapp.icon_hash = "fakehash" self.webapp.save() self.refresh("webapp")
def setUp(self): self.client = RestOAuthClient(None) self.url = reverse("search-api") self.webapp = Webapp.objects.get(pk=337141) # Pick a few common device features. self.profile = FeatureProfile( apps=True, audio=True, fullscreen=True, geolocation=True, indexeddb=True, sms=True ).to_signature() self.qs = {"q": "something", "pro": self.profile, "dev": "firefoxos"}
def test_reviewer_get(self): app = self.create_app() data = self.base_data() self.client.put(self.get_url, data=json.dumps(data)) editor = UserProfile.objects.get(email='*****@*****.**') g = Group.objects.create(rules='Apps:Review,Reviews:Edit') GroupUser.objects.create(group=g, user=editor) ac = Access.objects.create(key='adminOauthKey', secret=generate(), user=editor.user) client = RestOAuthClient(ac) r = client.get(self.get_url) eq_(r.status_code, 200) res = client.get(reverse('app-privacy-policy-detail', args=[app.pk])) eq_(r.status_code, 200) eq_(res.json['privacy_policy'], data['privacy_policy'])
def test_admin_get(self): app = self.create_app() data = self.base_data() self.client.put(self.get_url, data=json.dumps(data)) admin = UserProfile.objects.get(email='*****@*****.**') g = Group.objects.create(rules='*:*') GroupUser.objects.create(group=g, user=admin) ac = Access.objects.create(key='adminOauthKey', secret=generate(), user=admin.user) client = RestOAuthClient(ac) r = client.get(self.get_url) eq_(r.status_code, 200) res = client.get(reverse('app-privacy-policy-detail', args=[app.pk])) eq_(r.status_code, 200) eq_(res.json['privacy_policy'], data['privacy_policy'])
def setUp(self): self.client = RestOAuthClient(None) self.url = reverse('search-api') self.webapp = Webapp.objects.get(pk=337141) # Pick a few common device features. self.profile = FeatureProfile(apps=True, audio=True, fullscreen=True, geolocation=True, indexeddb=True, sms=True).to_signature() self.qs = {'q': 'something', 'pro': self.profile, 'dev': 'firefoxos'}
def setUp(self): self.client = RestOAuthClient(None) self.url = reverse('search-api') self.webapp = Webapp.objects.get(pk=337141) self.category = Category.objects.create(name='Books', slug='books', type=amo.ADDON_WEBAPP) self.webapp.icon_hash = 'fakehash' self.webapp.save() self.refresh('webapp')
class TestSuggestionsApi(ESTestCase): fixtures = fixture('webapp_337141') def setUp(self): self.url = reverse('suggestions-api') self.refresh('webapp') self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.save() self.app2 = app_factory(name=u'Second âpp', description=u'Second dèsc' * 25, created=self.days_ago(3)) self.refresh('webapp') def tearDown(self): # Cleanup to remove these from the index. unindex_webapps([self.app1.id, self.app2.id]) self.app1.delete() self.app2.delete() def test_suggestions(self): response = self.client.get(self.url, data={'lang': 'en-US'}) parsed = json.loads(response.content) eq_(parsed[0], '') self.assertSetEqual( parsed[1], [unicode(self.app1.name), unicode(self.app2.name)]) self.assertSetEqual( parsed[2], [unicode(self.app1.description), unicode(truncate(self.app2.description))]) self.assertSetEqual( parsed[3], [absolutify(self.app1.get_detail_url()), absolutify(self.app2.get_detail_url())]) self.assertSetEqual( parsed[4], [self.app1.get_icon_url(64), self.app2.get_icon_url(64)]) def test_suggestions_filtered(self): response = self.client.get(self.url, data={'q': 'Second', 'lang': 'en-US'}) parsed = json.loads(response.content) eq_(parsed[1], [unicode(self.app2.name)])
def setUp(self): self.url = reverse("suggestions-search-api") self.refresh("webapp") self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.save() self.app2 = app_factory( name=u"Second âpp", description=u"Second dèsc" * 25, icon_type="image/png", created=self.days_ago(3) ) self.refresh("webapp")
def setUp(self): self.url = reverse('suggestions-api') self.refresh('webapp') self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.save() self.app2 = app_factory(name=u'Second âpp', description=u'Second dèsc' * 25, created=self.days_ago(3)) self.refresh('webapp')
def setUp(self): self.url = reverse('rocketbar-search-api') self.refresh('webapp') self.client = RestOAuthClient(None) self.profile = UserProfile.objects.get(pk=2519) self.app1 = Webapp.objects.get(pk=337141) self.app1.addondevicetype_set.create(device_type=amo.DEVICE_GAIA.id) self.app1.save() self.app2 = app_factory(name=u'Something Second Something Something', description=u'Second dèsc' * 25, icon_type='image/png', icon_hash='fakehash', created=self.days_ago(3), manifest_url='http://rocket.example.com') self.app2.addondevicetype_set.create(device_type=amo.DEVICE_GAIA.id) # Add 2 installed records so this app is boosted higher than app1. Installed.objects.create(user=self.profile, addon=self.app2) Installed.objects.create(user=self.profile, addon=self.app2) self.app2.save() self.refresh('webapp')
def setUp(self): self.url = reverse('rocketbar-search-api') self.refresh('webapp') self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.save() self.app2 = app_factory(name=u'Second âpp', description=u'Second dèsc' * 25, icon_type='image/png', created=self.days_ago(3), manifest_url='http://testrocketbar.example.com') self.refresh('webapp')
def setUp(self): self.client = RestOAuthClient(None) self.url = reverse('search-api') self.webapp = Webapp.objects.get(pk=337141) self.webapp.platform_set.create(platform_id=mkt.PLATFORM_FXOS.id) self.webapp.form_factor_set.create(form_factor_id=mkt.FORM_MOBILE.id) self.category = Category.objects.create(name='test', type=amo.ADDON_WEBAPP) # Pick a few common device features. self.profile = FeatureProfile(apps=True, audio=True, fullscreen=True, geolocation=True, indexeddb=True, sms=True).to_signature() self.qs = {'q': 'something', 'pro': self.profile, 'platform': 'firefoxos', 'form_factor': 'mobile'}
def setUp(self): self.url = reverse("rocketbar-search-api") self.refresh("webapp") self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.save() self.app2 = app_factory( name=u"Second âpp", description=u"Second dèsc" * 25, icon_type="image/png", created=self.days_ago(3), manifest_url="http://testrocketbar.example.com", ) self.refresh("webapp")
def setUp(self): self.url = reverse('rocketbar-search-api') self.refresh('webapp') self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.platform_set.create(platform_id=mkt.PLATFORM_FXOS.id) self.app1.save() self.app2 = app_factory(name=u'Something Second Something Something', description=u'Second dèsc' * 25, icon_type='image/png', created=self.days_ago(3), manifest_url='http://rocket.example.com') self.app2.platform_set.create(platform_id=mkt.PLATFORM_FXOS.id) self.app2.save() self.refresh('webapp')
def setUp(self): self.url = reverse('rocketbar-search-api') self.refresh('webapp') self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.addondevicetype_set.create(device_type=amo.DEVICE_GAIA.id) self.app1.save() self.app2 = app_factory(name=u'Something Second Something Something', description=u'Second dèsc' * 25, icon_type='image/png', created=self.days_ago(3), manifest_url='http://rocket.example.com') self.app2.addondevicetype_set.create(device_type=amo.DEVICE_GAIA.id) self.app2.save() self.refresh('webapp')
def setUp(self): self.url = reverse("rocketbar-search-api") self.refresh("webapp") self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.addondevicetype_set.create(device_type=amo.DEVICE_GAIA.id) self.app1.save() self.app2 = app_factory( name=u"Something Second Something Something", description=u"Second dèsc" * 25, icon_type="image/png", icon_hash="fakehash", created=self.days_ago(3), manifest_url="http://rocket.example.com", ) self.app2.addondevicetype_set.create(device_type=amo.DEVICE_GAIA.id) self.app2.save() self.refresh("webapp")
class TestRocketbarApi(ESTestCase): fixtures = fixture("webapp_337141") def setUp(self): self.url = reverse("rocketbar-search-api") self.refresh("webapp") self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.save() self.app2 = app_factory( name=u"Second âpp", description=u"Second dèsc" * 25, icon_type="image/png", created=self.days_ago(3), manifest_url="http://testrocketbar.example.com", ) self.refresh("webapp") def tearDown(self): # Cleanup to remove these from the index. unindex_webapps([self.app1.id, self.app2.id]) self.app1.delete() self.app2.delete() def test_suggestions_filtered(self): response = self.client.get(self.url, data={"q": "Second", "lang": "en-US"}) parsed = json.loads(response.content) eq_( parsed, [ { "manifest_url": self.app2.get_manifest_url(), "icon": self.app2.get_icon_url(64), "name": unicode(self.app2.name), "slug": self.app2.app_slug, } ], )
class TestRocketbarApi(ESTestCase): fixtures = fixture('webapp_337141') def setUp(self): self.url = reverse('rocketbar-search-api') self.refresh('webapp') self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.save() self.app2 = app_factory( name=u'Second âpp', description=u'Second dèsc' * 25, icon_type='image/png', created=self.days_ago(3), manifest_url='http://testrocketbar.example.com') self.refresh('webapp') def tearDown(self): # Cleanup to remove these from the index. unindex_webapps([self.app1.id, self.app2.id]) self.app1.delete() self.app2.delete() def test_suggestions_filtered(self): response = self.client.get(self.url, data={ 'q': 'Second', 'lang': 'en-US' }) parsed = json.loads(response.content) eq_(parsed, [{ 'manifest_url': self.app2.get_manifest_url(), 'icon': self.app2.get_icon_url(64), 'name': unicode(self.app2.name), 'slug': self.app2.app_slug }])
class TestApi(RestOAuth, ESTestCase): fixtures = fixture('webapp_337141') def setUp(self): self.client = RestOAuthClient(None) self.url = reverse('search-api') self.webapp = Webapp.objects.get(pk=337141) self.category = 'books' self.webapp.icon_hash = 'fakehash' self.webapp.save() self.refresh('webapp') def tearDown(self): for w in Webapp.objects.all(): w.delete() unindex_webapps(list(Webapp.with_deleted.values_list('id', flat=True))) super(TestApi, self).tearDown() def test_verbs(self): self._allowed_verbs(self.url, ['get']) def test_has_cors(self): self.assertCORS(self.client.get(self.url), 'get') def test_meta(self): res = self.client.get(self.url) eq_(res.status_code, 200) eq_(set(res.json.keys()), set(['objects', 'meta'])) eq_(res.json['meta']['total_count'], 1) @patch('mkt.search.utils.statsd.timer') def test_statsd(self, _mock): self.client.get(self.url) assert _mock.called def test_search_published_apps(self): res = self.client.get(self.url) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 1) eq_(objs[0]['slug'], self.webapp.app_slug) def test_search_no_approved_apps(self): self.webapp.update(status=amo.STATUS_APPROVED) self.refresh('webapp') res = self.client.get(self.url) eq_(res.status_code, 200) eq_(res.json['objects'], []) def test_search_no_unlisted_apps(self): self.webapp.update(status=amo.STATUS_UNLISTED) self.refresh('webapp') res = self.client.get(self.url) eq_(res.status_code, 200) eq_(res.json['objects'], []) def test_wrong_category(self): res = self.client.get(self.url, data={'cat': self.category + 'xq'}) eq_(res.status_code, 400) eq_(res['Content-Type'], 'application/json') def test_wrong_sort(self): res = self.client.get(self.url, data={'sort': 'awesomeness'}) eq_(res.status_code, 400) def test_sort(self): # Make sure elasticsearch is actually accepting the params. for api_sort, es_sort in DEFAULT_SORTING.items(): res = self.client.get(self.url, [('sort', api_sort)]) eq_(res.status_code, 200) def test_multiple_sort(self): res = self.client.get(self.url, [('sort', 'rating'), ('sort', 'created')]) eq_(res.status_code, 200) def test_right_category(self): res = self.client.get(self.url, data={'cat': self.category}) eq_(res.status_code, 200) eq_(res.json['objects'], []) def create(self): self.webapp.update(categories=[self.category]) self.refresh('webapp') def test_right_category_present(self): self.create() res = self.client.get(self.url, data={'cat': self.category}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 1) def test_tarako_category(self): self.create() # tarako-lifestyle includes books. res = self.client.get(self.url, data={'cat': 'tarako-lifestyle'}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 1) # tarako-games includes only games. res = self.client.get(self.url, data={'cat': 'tarako-games'}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 0) # tarako-tools includes multiple categories, but not books. res = self.client.get(self.url, data={'cat': 'tarako-tools'}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 0) def test_user_info_with_shared_secret(self): user = UserProfile.objects.all()[0] def fakeauth(auth, req, **kw): req.user = user req.user = user with patch('mkt.api.middleware.RestSharedSecretMiddleware' '.process_request', fakeauth): with self.settings(SITE_URL=''): self.create() res = self.client.get(self.url, data={'cat': self.category}) obj = res.json['objects'][0] assert 'user' in obj def test_dehydrate(self): with self.settings(SITE_URL='http://hy.fr'): self.create() res = self.client.get(self.url, data={'cat': self.category}) eq_(res.status_code, 200) obj = res.json['objects'][0] content_ratings = obj['content_ratings'] eq_(obj['absolute_url'], absolutify(self.webapp.get_absolute_url())) eq_(obj['app_type'], self.webapp.app_type) eq_(obj['categories'], [self.category]) eq_(content_ratings['body'], 'generic') eq_(content_ratings['rating'], None) eq_(content_ratings['descriptors'], []) eq_(content_ratings['interactives'], []) eq_(obj['current_version'], u'1.0') eq_(obj['description'], {'en-US': self.webapp.description.localized_string}) eq_(obj['icons']['128'], self.webapp.get_icon_url(128)) ok_(obj['icons']['128'].endswith('?modified=fakehash')) eq_(obj['id'], long(self.webapp.id)) eq_(obj['is_offline'], False) eq_(obj['manifest_url'], self.webapp.get_manifest_url()) eq_(obj['package_path'], None) eq_(obj['payment_account'], None) self.assertApiUrlEqual(obj['privacy_policy'], '/apps/app/337141/privacy/') eq_(obj['public_stats'], self.webapp.public_stats) eq_(obj['ratings'], {'average': 0.0, 'count': 0}) self.assertApiUrlEqual(obj['resource_uri'], '/apps/app/337141/') eq_(obj['slug'], self.webapp.app_slug) eq_(obj['supported_locales'], ['en-US', 'es', 'pt-BR']) eq_(obj['tags'], []) ok_('1.0' in obj['versions']) self.assertApiUrlEqual(obj['versions']['1.0'], '/apps/versions/1268829/') # These only exists if requested by a reviewer. ok_('latest_version' not in obj) ok_('reviewer_flags' not in obj) @patch('mkt.webapps.models.Webapp.get_excluded_region_ids') def test_upsell(self, get_excluded_region_ids): get_excluded_region_ids.return_value = [] upsell = app_factory(premium_type=amo.ADDON_PREMIUM) AddonUpsell.objects.create(free=self.webapp, premium=upsell) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, {'premium_types': 'free'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 1) obj = res.json['objects'][0] eq_(obj['upsell']['id'], upsell.id) eq_(obj['upsell']['app_slug'], upsell.app_slug) eq_(obj['upsell']['name'], upsell.name) eq_(obj['upsell']['icon_url'], upsell.get_icon_url(128)) self.assertApiUrlEqual(obj['upsell']['resource_uri'], '/apps/app/%s/' % upsell.id) eq_(obj['upsell']['region_exclusions'], []) upsell.delete() unindex_webapps([upsell.id]) def test_dehydrate_regions(self): self.webapp.addonexcludedregion.create(region=mkt.regions.BR.id) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url) eq_(res.status_code, 200) obj = res.json['objects'][0] regions = obj['regions'] ok_(mkt.regions.BR.slug not in [r['slug'] for r in regions]) eq_(len(regions), len(mkt.regions.ALL_REGION_IDS) - 1) def test_region_filtering(self): self.webapp.addonexcludedregion.create(region=mkt.regions.BR.id) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'region': 'br'}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 0) def test_languages_filtering(self): # This webapp's supported_locales: [u'en-US', u'es', u'pt-BR'] res = self.client.get(self.url, data={'languages': 'fr'}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 0) for lang in ('fr,pt-BR', 'es, pt-BR', 'es', 'pt-BR'): res = self.client.get(self.url, data={'languages': lang}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_offline_filtering(self): def check(offline, visible): res = self.client.get(self.url, data={'offline': offline}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), int(visible)) # Should NOT show up in offline. # Should show up in online. # Should show up everywhere if not filtered. check(offline='True', visible=False) check(offline='False', visible=True) check(offline='None', visible=True) # Mark that app is capable offline. self.webapp.update(is_packaged=True) self.refresh('webapp') # Should show up in offline. # Should NOT show up in online. # Should show up everywhere if not filtered. check(offline='True', visible=True) check(offline='False', visible=False) check(offline='None', visible=True) def test_q(self): res = self.client.get(self.url, data={'q': 'something'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_q_num_requests(self): es = WebappIndexer.get_es() orig_search = es.search es.counter = 0 def monkey_search(*args, **kwargs): es.counter += 1 return orig_search(*args, **kwargs) es.search = monkey_search res = self.client.get(self.url, data={'q': 'something'}) eq_(res.status_code, 200) eq_(res.json['meta']['total_count'], 1) eq_(len(res.json['objects']), 1) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) # Verify only one search call was made. eq_(es.counter, 1) es.search = orig_search def test_q_num_requests_no_results(self): es = WebappIndexer.get_es() orig_search = es.search es.counter = 0 def monkey_search(*args, **kwargs): es.counter += 1 return orig_search(*args, **kwargs) es.search = monkey_search res = self.client.get(self.url, data={'q': 'noresults'}) eq_(res.status_code, 200) eq_(res.json['meta']['total_count'], 0) eq_(len(res.json['objects']), 0) # Verify only one search call was made. eq_(es.counter, 1) es.search = orig_search def test_q_exact(self): app1 = app_factory(name='test app test11') app2 = app_factory(name='test app test21') app3 = app_factory(name='test app test31') self.refresh('webapp') res = self.client.get(self.url, data={'q': 'test app test21'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 3) # app2 should be first since it's an exact match and is boosted higher. obj = res.json['objects'][0] eq_(obj['slug'], app2.app_slug) app1.delete() app2.delete() app3.delete() unindex_webapps([app1.id, app2.id, app3.id]) def test_q_is_tag(self): Tag(tag_text='whatsupp').save_tag(self.webapp) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'whatsupp'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_q_is_tag_misspelled(self): Tag(tag_text='whatsapp').save_tag(self.webapp) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'whatsupp'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_fuzzy_match(self): res = self.client.get(self.url, data={'q': 'soemthing'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_icu_folding(self): self.webapp.name = {'es': 'Páginas Amarillos'} self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'paginas'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_camel_case_word_splitting(self): self.webapp.name = 'AirCombat' self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'air combat'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_phrase_slop(self): self.webapp.name = {'es': 'Metro de Santiago', 'en': None} self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'metro santiago'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_name_localized(self): # First test no ?lang parameter returns all localizations. res = self.client.get(self.url, data={'q': 'something'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) eq_(obj['name'], {u'en-US': u'Something Something Steamcube!', u'es': u'Algo Algo Steamcube!'}) # Second test that adding ?lang returns only that localization. res = self.client.get(self.url, data={'q': 'something', 'lang': 'es'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) eq_(obj['name'], u'Algo Algo Steamcube!') def test_other_localized(self): # Test fields that should be localized. translations = {'en-US': u'Test in English', 'es': u'Test in Español'} self.webapp.homepage = translations self.webapp.support_email = translations self.webapp.support_url = translations self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'something'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['homepage'], translations) eq_(obj['support_email'], translations) eq_(obj['support_url'], translations) def test_name_localized_to_default_locale(self): self.webapp.update(default_locale='es') self.refresh('webapp') # Make a request in another language that we know will fail. res = self.client.get(self.url, data={'q': 'something', 'lang': 'de'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) eq_(obj['name'], u'Algo Algo Steamcube!') def test_device(self): AddonDeviceType.objects.create( addon=self.webapp, device_type=DEVICE_CHOICES_IDS['desktop']) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'dev': 'desktop'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_no_flash_on_firefoxos(self): AddonDeviceType.objects.create( addon=self.webapp, device_type=DEVICE_CHOICES_IDS['firefoxos']) f = self.webapp.get_latest_file() f.uses_flash = True f.save() self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'dev': 'firefoxos'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 0) def test_premium_types(self): res = self.client.get(self.url, data={'premium_types': 'free'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_premium_types_empty(self): res = self.client.get(self.url, data={'premium_types': 'premium'}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 0) def test_multiple_premium_types(self): res = self.client.get(self.url, data={'premium_types': ['free', 'premium']}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_app_type_hosted(self): res = self.client.get(self.url, data={'app_type': 'hosted'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) eq_(obj['is_packaged'], False) eq_(obj['is_offline'], False) eq_(obj['package_path'], None) @override_settings(SITE_URL='http://hy.fr') def test_app_type_packaged(self): self.webapp.update(is_packaged=True) f = self.webapp.current_version.all_files[0] self.refresh('webapp') res = self.client.get(self.url, data={'app_type': 'packaged'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) eq_(obj['is_packaged'], True) eq_(obj['is_offline'], True) eq_(obj['package_path'], '%s/downloads/file/%s/%s' % (settings.SITE_URL, f.id, f.filename)) def test_app_type_privileged(self): # Override the class-decorated patch. with patch('mkt.versions.models.Version.is_privileged', True): self.webapp.update(is_packaged=True) self.refresh('webapp') res = self.client.get(self.url, data={'app_type': 'packaged'}) eq_(res.status_code, 200) # Packaged also includes privileged, which is technically also a # packaged app. eq_(len(res.json['objects']), 1) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) res = self.client.get(self.url, data={'app_type': 'privileged'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 1) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_status_value_packaged(self): # When packaged and not a reviewer we exclude latest version status. self.webapp.update(is_packaged=True) res = self.client.get(self.url) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['status'], amo.STATUS_PUBLIC) eq_('latest_version' in obj, False) def test_addon_type_anon(self): res = self.client.get(self.url, data={'type': 'app'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) res = self.client.get(self.url, data={'type': 'vindaloo'}) eq_(res.status_code, 400) error = res.json['detail'] eq_(error.keys(), ['type']) def test_word_delimiter_preserves_original(self): self.webapp.description = { 'en-US': 'This is testing word delimiting preservation in long ' 'descriptions and here is what we want to find: WhatsApp' } self.webapp.save() self.reindex(Webapp, 'webapp') res = self.client.get(self.url, data={'q': 'whatsapp'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_pagination(self): Webapp.objects.get(pk=337141).delete() app1 = app_factory(name='test app test1') app2 = app_factory(name='test app test2') app3 = app_factory(name='test app test3') # Setting 'created' app_factory is unreliable and we need a reliable # order. app1.update(created=self.days_ago(1)) app2.update(created=self.days_ago(2)) app3.update(created=self.days_ago(3)) self.refresh('webapp') res = self.client.get(self.url, data={'limit': '2', 'sort': 'created'}) eq_(res.status_code, 200) data = json.loads(res.content) eq_(len(data['objects']), 2) eq_(int(data['objects'][0]['id']), app1.id) eq_(int(data['objects'][1]['id']), app2.id) eq_(data['meta']['total_count'], 3) eq_(data['meta']['limit'], 2) eq_(data['meta']['previous'], None) eq_(data['meta']['offset'], 0) next = urlparse(data['meta']['next']) eq_(next.path, self.url) eq_(QueryDict(next.query).dict(), {'limit': '2', 'offset': '2', 'sort': 'created'}) res = self.client.get(self.url, QueryDict(next.query).dict()) eq_(res.status_code, 200) data = json.loads(res.content) eq_(len(data['objects']), 1) eq_(int(data['objects'][0]['id']), app3.id) eq_(data['meta']['total_count'], 3) eq_(data['meta']['limit'], 2) prev = urlparse(data['meta']['previous']) eq_(next.path, self.url) eq_(QueryDict(prev.query).dict(), {'limit': '2', 'offset': '0', 'sort': 'created'}) eq_(data['meta']['offset'], 2) eq_(data['meta']['next'], None) def test_content_ratings_reindex(self): self.webapp.set_content_ratings({ mkt.ratingsbodies.GENERIC: mkt.ratingsbodies.GENERIC_18 }) self.refresh('webapp') res = self.client.get(self.url) obj = res.json['objects'][0] ok_(obj['content_ratings']['rating']) def test_usk_refused_exclude(self): geodata = self.webapp._geodata geodata.update(region_de_usk_exclude=True) self.reindex(Webapp, 'webapp') res = self.client.get(self.url, {'region': 'de'}) ok_(not res.json['objects']) def test_icon_url_never(self): self.webapp.update(icon_hash=None) self.refresh('webapp') res = self.client.get(self.url) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['icons']['64'], self.webapp.get_icon_url(64)) ok_(obj['icons']['64'].endswith('?modified=never')) def test_tag(self): tag1 = Tag.objects.create(tag_text='tagtagtag') tag2 = Tag.objects.create(tag_text='tarako') Tag.objects.create(tag_text='dummy') AddonTag.objects.create(addon=self.webapp, tag=tag1) AddonTag.objects.create(addon=self.webapp, tag=tag2) self.reindex(Webapp, 'webapp') res = self.client.get(self.url, {'tag': 'tarako'}) eq_(res.status_code, 200) obj = res.json['objects'][0] self.assertSetEqual(obj['tags'], ['tagtagtag', 'tarako']) def test_ratings_sort(self): app1 = self.webapp app2 = app_factory() user = user_factory() app1._reviews.create(user=user, rating=1) app2._reviews.create(user=user, rating=5) self.refresh() res = self.client.get(self.url, {'sort': 'rating'}) eq_(res.status_code, 200) eq_(res.json['objects'][0]['id'], app2.id) eq_(res.json['objects'][1]['id'], app1.id)
class TestApi(RestOAuth, ESTestCase): fixtures = fixture('webapp_337141') def setUp(self): self.client = RestOAuthClient(None) self.url = reverse('search-api') self.webapp = Webapp.objects.get(pk=337141) self.category = Category.objects.create(name='test', slug='test', type=amo.ADDON_WEBAPP) self.webapp.save() self.refresh('webapp') def tearDown(self): unindex_webapps(list(Webapp.with_deleted.values_list('id', flat=True))) Webapp.objects.all().delete() super(TestApi, self).tearDown() def test_verbs(self): self._allowed_verbs(self.url, ['get']) def test_has_cors(self): self.assertCORS(self.client.get(self.url), 'get') def test_meta(self): res = self.client.get(self.url) eq_(res.status_code, 200) eq_(set(res.json.keys()), set(['objects', 'meta'])) eq_(res.json['meta']['total_count'], 1) def test_wrong_category(self): res = self.client.get(self.url, data={'cat': self.category.slug + 'xq'}) eq_(res.status_code, 400) eq_(res['Content-Type'], 'application/json') def test_wrong_weight(self): self.category.update(weight=-1) res = self.client.get(self.url, data={'cat': self.category.slug}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 0) def test_wrong_sort(self): res = self.client.get(self.url, data={'sort': 'awesomeness'}) eq_(res.status_code, 400) def test_sort(self): # Mocked version, to make sure we are calling ES with the parameters # we want. with patch('mkt.webapps.models.Webapp.from_search') as mocked_search: mocked_qs = MagicMock() mocked_search.return_value = mocked_qs for api_sort, es_sort in DEFAULT_SORTING.items(): res = self.client.get(self.url, [('sort', api_sort)]) eq_(res.status_code, 200, res.content) mocked_qs.order_by.assert_called_with(es_sort) # Unmocked version, to make sure elasticsearch is actually accepting # the params. for api_sort, es_sort in DEFAULT_SORTING.items(): res = self.client.get(self.url, [('sort', api_sort)]) eq_(res.status_code, 200) def test_right_category(self): res = self.client.get(self.url, data={'cat': self.category.pk}) eq_(res.status_code, 200) eq_(res.json['objects'], []) def create(self): AddonCategory.objects.create(addon=self.webapp, category=self.category) self.webapp.save() self.refresh('webapp') def test_right_category_present(self): self.create() res = self.client.get( self.url, data={'cat': self.category.pk}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 1) def test_user_info_with_shared_secret(self): user = UserProfile.objects.all()[0] def fakeauth(auth, req, **kw): req.user = user.user req.amo_user = user with patch('mkt.api.middleware.RestSharedSecretMiddleware' '.process_request', fakeauth): with self.settings(SITE_URL=''): self.create() res = self.client.get( self.url, data={'cat': self.category.pk}) obj = res.json['objects'][0] assert 'user' in obj def test_dehydrate(self): with self.settings(SITE_URL='http://hy.fr'): self.create() res = self.client.get(self.url, data={'cat': self.category.pk}) eq_(res.status_code, 200) obj = res.json['objects'][0] content_ratings = obj['content_ratings'] eq_(obj['absolute_url'], absolutify(self.webapp.get_absolute_url())) eq_(obj['app_type'], self.webapp.app_type) eq_(content_ratings['descriptors'], {}) eq_(content_ratings['interactive_elements'], []) eq_(content_ratings['ratings'], None) eq_(obj['current_version'], u'1.0') eq_(obj['description'], {'en-US': self.webapp.description.localized_string}) eq_(obj['icons']['128'], self.webapp.get_icon_url(128)) eq_(obj['id'], long(self.webapp.id)) eq_(obj['manifest_url'], self.webapp.get_manifest_url()) eq_(obj['payment_account'], None) self.assertApiUrlEqual(obj['privacy_policy'], '/apps/app/337141/privacy/') eq_(obj['public_stats'], self.webapp.public_stats) eq_(obj['ratings'], {'average': 0.0, 'count': 0}) self.assertApiUrlEqual(obj['resource_uri'], '/apps/app/337141/') eq_(obj['slug'], self.webapp.app_slug) eq_(obj['supported_locales'], ['en-US', 'es', 'pt-BR']) ok_('1.0' in obj['versions']) self.assertApiUrlEqual(obj['versions']['1.0'], '/apps/versions/1268829/') # These only exists if requested by a reviewer. ok_('latest_version' not in obj) ok_('reviewer_flags' not in obj) @patch('mkt.webapps.models.Webapp.get_excluded_region_ids') def test_upsell(self, get_excluded_region_ids): get_excluded_region_ids.return_value = [] upsell = app_factory(premium_type=amo.ADDON_PREMIUM) AddonUpsell.objects.create(free=self.webapp, premium=upsell) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, {'premium_types': 'free'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 1) obj = res.json['objects'][0] eq_(obj['upsell']['id'], upsell.id) eq_(obj['upsell']['app_slug'], upsell.app_slug) eq_(obj['upsell']['name'], upsell.name) eq_(obj['upsell']['icon_url'], upsell.get_icon_url(128)) self.assertApiUrlEqual(obj['upsell']['resource_uri'], '/apps/app/%s/' % upsell.id) eq_(obj['upsell']['region_exclusions'], []) unindex_webapps([upsell.id]) upsell.delete() def test_dehydrate_regions(self): self.webapp.addonexcludedregion.create(region=mkt.regions.BR.id) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url) eq_(res.status_code, 200) obj = res.json['objects'][0] regions = obj['regions'] ok_(mkt.regions.BR.slug not in [r['slug'] for r in regions]) eq_(len(regions), len(mkt.regions.ALL_REGION_IDS) - 1) def test_region_filtering(self): self.webapp.addonexcludedregion.create(region=mkt.regions.BR.id) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'region': 'br'}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 0) def test_languages_filtering(self): # This webapp's supported_locales: [u'en-US', u'es', u'pt-BR'] res = self.client.get(self.url, data={'languages': 'fr'}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 0) for lang in ('fr,pt-BR', 'es, pt-BR', 'es', 'pt-BR'): res = self.client.get(self.url, data={'languages': lang}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_offline_filtering(self): def check(offline, visible): res = self.client.get(self.url, data={'offline': offline}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), int(visible)) # Should NOT show up in offline. # Should show up in online. # Should show up everywhere if not filtered. check(offline='True', visible=False) check(offline='False', visible=True) check(offline='None', visible=True) # Mark that app is capable offline. self.webapp.update(is_packaged=True) self.refresh('webapp') # Should show up in offline. # Should NOT show up in online. # Should show up everywhere if not filtered. check(offline='True', visible=True) check(offline='False', visible=False) check(offline='None', visible=True) def test_q(self): res = self.client.get(self.url, data={'q': 'something'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_q_num_requests(self): es = WebappIndexer.get_es() orig_search = es.search es.counter = 0 def monkey_search(*args, **kwargs): es.counter += 1 return orig_search(*args, **kwargs) es.search = monkey_search res = self.client.get(self.url, data={'q': 'something'}) eq_(res.status_code, 200) eq_(res.json['meta']['total_count'], 1) eq_(len(res.json['objects']), 1) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) # Verify only one search call was made. eq_(es.counter, 1) es.search = orig_search def test_q_num_requests_no_results(self): es = WebappIndexer.get_es() orig_search = es.search es.counter = 0 def monkey_search(*args, **kwargs): es.counter += 1 return orig_search(*args, **kwargs) es.search = monkey_search res = self.client.get(self.url, data={'q': 'noresults'}) eq_(res.status_code, 200) eq_(res.json['meta']['total_count'], 0) eq_(len(res.json['objects']), 0) # Verify only one search call was made. eq_(es.counter, 1) es.search = orig_search def test_q_exact(self): app1 = app_factory(name='test app test11') app2 = app_factory(name='test app test21') app3 = app_factory(name='test app test31') self.refresh('webapp') res = self.client.get(self.url, data={'q': 'test app test21'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 3) # app2 should be first since it's an exact match and is boosted higher. obj = res.json['objects'][0] eq_(obj['slug'], app2.app_slug) unindex_webapps([app1.id, app2.id, app3.id]) app1.delete() app2.delete() app3.delete() def test_q_is_tag(self): Tag(tag_text='whatsupp').save_tag(self.webapp) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'whatsupp'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_q_is_tag_misspelled(self): Tag(tag_text='whatsapp').save_tag(self.webapp) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'whatsupp'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_fuzzy_match(self): res = self.client.get(self.url, data={'q': 'soemthing'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_icu_folding(self): self.webapp.name = {'es': 'Páginas Amarillos'} self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'paginas'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_camel_case_word_splitting(self): self.webapp.name = 'AirCombat' self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'air combat'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_name_localized(self): # First test no ?lang parameter returns all localizations. res = self.client.get(self.url, data={'q': 'something'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) eq_(obj['name'], {u'en-US': u'Something Something Steamcube!', u'es': u'Algo Algo Steamcube!'}) # Second test that adding ?lang returns only that localization. res = self.client.get(self.url, data={'q': 'something', 'lang': 'es'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) eq_(obj['name'], u'Algo Algo Steamcube!') def test_other_localized(self): # Test fields that should be localized. translations = {'en-US': u'Test in English', 'es': u'Test in Español'} self.webapp.homepage = translations self.webapp.support_email = translations self.webapp.support_url = translations self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'something'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['homepage'], translations) eq_(obj['support_email'], translations) eq_(obj['support_url'], translations) def test_name_localized_to_default_locale(self): self.webapp.update(default_locale='es') self.refresh('webapp') # Make a request in another language that we know will fail. res = self.client.get(self.url, data={'q': 'something', 'lang': 'de'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) eq_(obj['name'], u'Algo Algo Steamcube!') def test_device(self): AddonDeviceType.objects.create( addon=self.webapp, device_type=DEVICE_CHOICES_IDS['desktop']) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'device': 'desktop'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_no_flash_on_firefoxos(self): AddonDeviceType.objects.create( addon=self.webapp, device_type=DEVICE_CHOICES_IDS['firefoxos']) f = self.webapp.get_latest_file() f.uses_flash = True f.save() self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'dev': 'firefoxos'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 0) def test_premium_types(self): res = self.client.get(self.url, data={'premium_types': 'free'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_premium_types_empty(self): res = self.client.get(self.url, data={'premium_types': 'premium'}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 0) def test_multiple_premium_types(self): res = self.client.get(self.url, data={'premium_types': ['free', 'premium']}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_app_type_hosted(self): res = self.client.get(self.url, data={'app_type': 'hosted'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_app_type_packaged(self): self.webapp.update(is_packaged=True) self.refresh('webapp') res = self.client.get(self.url, data={'app_type': 'packaged'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_app_type_privileged(self): # Override the class-decorated patch. with patch('versions.models.Version.is_privileged', True): self.webapp.update(is_packaged=True) self.refresh('webapp') res = self.client.get(self.url, data={'app_type': 'packaged'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 0) res = self.client.get(self.url, data={'app_type': 'privileged'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 1) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_status_value_packaged(self): # When packaged and not a reviewer we exclude latest version status. self.webapp.update(is_packaged=True) res = self.client.get(self.url) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['status'], amo.STATUS_PUBLIC) eq_('latest_version' in obj, False) def test_addon_type_anon(self): res = self.client.get(self.url, data={'type': 'app'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) res = self.client.get(self.url, data={'type': 'vindaloo'}) eq_(res.status_code, 400) error = res.json['detail'] eq_(error.keys(), ['type']) res = self.client.get(self.url, data={'type': 'theme'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 0) def test_adolescent_popularity(self): """ Adolescent regions use global popularity. Webapp: Global: 0, Regional: 0 Unknown1: Global: 1, Regional: 1 + 10 * 1 = 11 Unknown2: Global: 2, Regional: 0 """ user = UserProfile.objects.all()[0] cd = ClientData.objects.create(region=mkt.regions.BR.id) unknown1 = amo.tests.app_factory() Installed.objects.create(addon=unknown1, user=user, client_data=cd) unknown2 = amo.tests.app_factory() Installed.objects.create(addon=unknown2, user=user) Installed.objects.create(addon=unknown2, user=user) self.reindex(Webapp, 'webapp') res = self.client.get(self.url, data={'region': 'br'}) eq_(res.status_code, 200) objects = res.json['objects'] eq_(len(objects), 3) eq_(int(objects[0]['id']), unknown2.id) eq_(int(objects[1]['id']), unknown1.id) eq_(int(objects[2]['id']), self.webapp.id) # Cleanup to remove these from the index. unindex_webapps([unknown1.id, unknown2.id]) unknown1.delete() unknown2.delete() def test_word_delimiter_preserves_original(self): self.webapp.description = { 'en-US': 'This is testing word delimiting preservation in long ' 'descriptions and here is what we want to find: WhatsApp' } self.webapp.save() self.reindex(Webapp, 'webapp') res = self.client.get(self.url, data={'q': 'whatsapp'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_pagination(self): Webapp.objects.get(pk=337141).delete() app1 = app_factory(name='test app test1') app2 = app_factory(name='test app test2') app3 = app_factory(name='test app test3') # Setting 'created' app_factory is unreliable and we need a reliable # order. app1.update(created=self.days_ago(1)) app2.update(created=self.days_ago(2)) app3.update(created=self.days_ago(3)) self.refresh('webapp') res = self.client.get(self.url, data={'limit': '2', 'sort': 'created'}) eq_(res.status_code, 200) data = json.loads(res.content) eq_(len(data['objects']), 2) eq_(int(data['objects'][0]['id']), app1.id) eq_(int(data['objects'][1]['id']), app2.id) eq_(data['meta']['total_count'], 3) eq_(data['meta']['limit'], 2) eq_(data['meta']['previous'], None) eq_(data['meta']['offset'], 0) next = urlparse(data['meta']['next']) eq_(next.path, self.url) eq_(QueryDict(next.query).dict(), {'limit': '2', 'offset': '2', 'sort': 'created'}) res = self.client.get(self.url, QueryDict(next.query).dict()) eq_(res.status_code, 200) data = json.loads(res.content) eq_(len(data['objects']), 1) eq_(int(data['objects'][0]['id']), app3.id) eq_(data['meta']['total_count'], 3) eq_(data['meta']['limit'], 2) prev = urlparse(data['meta']['previous']) eq_(next.path, self.url) eq_(QueryDict(prev.query).dict(), {'limit': '2', 'offset': '0', 'sort': 'created'}) eq_(data['meta']['offset'], 2) eq_(data['meta']['next'], None) def test_content_ratings_reindex(self): self.webapp.set_content_ratings({ mkt.ratingsbodies.ESRB: mkt.ratingsbodies.ESRB_T }) self.refresh('webapp') res = self.client.get(self.url) obj = res.json['objects'][0] ok_(obj['content_ratings']['ratings']) def test_usk_refused_exclude(self): geodata = self.webapp._geodata geodata.update(region_de_usk_exclude=True) self.reindex(Webapp, 'webapp') res = self.client.get(self.url, {'region': 'de'}) ok_(not res.json['objects'])
class TestApiFeatures(RestOAuth, ESTestCase): fixtures = fixture('webapp_337141') def setUp(self): self.client = RestOAuthClient(None) self.url = reverse('search-api') self.webapp = Webapp.objects.get(pk=337141) self.category = Category.objects.create(name='test', type=amo.ADDON_WEBAPP) # Pick a few common device features. self.profile = FeatureProfile(apps=True, audio=True, fullscreen=True, geolocation=True, indexeddb=True, sms=True).to_signature() self.qs = {'q': 'something', 'pro': self.profile, 'dev': 'firefoxos'} def test_no_features(self): # Base test to make sure we find the app. self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data=self.qs) eq_(res.status_code, 200) obj = json.loads(res.content)['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_one_good_feature(self): # Enable an app feature that matches one in our profile. self.webapp.current_version.features.update(has_geolocation=True) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data=self.qs) eq_(res.status_code, 200) obj = json.loads(res.content)['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_one_bad_feature(self): # Enable an app feature that doesn't match one in our profile. self.webapp.current_version.features.update(has_pay=True) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data=self.qs) eq_(res.status_code, 200) objs = json.loads(res.content)['objects'] eq_(len(objs), 0) def test_all_good_features(self): # Enable app features so they exactly match our device profile. fp = FeatureProfile.from_signature(self.profile) self.webapp.current_version.features.update( **dict(('has_%s' % k, v) for k, v in fp.items())) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data=self.qs) eq_(res.status_code, 200) obj = json.loads(res.content)['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_bad_profile_on_desktop(self): # Enable an app feature that doesn't match one in our profile. qs = self.qs.copy() del qs['dev'] # Desktop doesn't send a device. self.webapp.current_version.features.update(has_pay=True) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data=qs) eq_(res.status_code, 200) obj = json.loads(res.content)['objects'][0] eq_(obj['slug'], self.webapp.app_slug)
class TestRocketbarApi(ESTestCase): fixtures = fixture('user_2519', 'webapp_337141') def setUp(self): self.url = reverse('rocketbar-search-api') self.refresh('webapp') self.client = RestOAuthClient(None) self.profile = UserProfile.objects.get(pk=2519) self.app1 = Webapp.objects.get(pk=337141) self.app1.addondevicetype_set.create(device_type=amo.DEVICE_GAIA.id) self.app1.save() self.app2 = app_factory(name=u'Something Second Something Something', description=u'Second dèsc' * 25, icon_type='image/png', icon_hash='fakehash', created=self.days_ago(3), manifest_url='http://rocket.example.com') self.app2.addondevicetype_set.create(device_type=amo.DEVICE_GAIA.id) # Add 2 installed records so this app is boosted higher than app1. Installed.objects.create(user=self.profile, addon=self.app2) Installed.objects.create(user=self.profile, addon=self.app2) self.app2.save() self.refresh('webapp') def tearDown(self): # Cleanup to remove these from the index. self.app1.delete() self.app2.delete() unindex_webapps([self.app1.id, self.app2.id]) # Required to purge the suggestions data structure. In Lucene, a # document is not deleted from a segment, just marked as deleted. WebappIndexer.get_es().optimize(WebappIndexer.get_index(), only_expunge_deletes=True) def test_no_results(self): with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'whatever', 'lang': 'en-US'}) parsed = json.loads(response.content) eq_(parsed, []) def test_suggestions(self): with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'Something Second', 'lang': 'en-US'}) parsed = json.loads(response.content) eq_(len(parsed), 1) eq_(parsed[0], {'manifest_url': self.app2.get_manifest_url(), 'icon': self.app2.get_icon_url(64), 'name': unicode(self.app2.name), 'slug': self.app2.app_slug}) ok_(self.app2.get_icon_url(64).endswith('?modified=fakehash')) def test_suggestion_default_locale(self): self.app2.name.locale = 'es' self.app2.name.save() self.app2.default_locale = 'es' self.app2.save() with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'Something Second', 'lang': 'en-US'}) parsed = json.loads(response.content) eq_(len(parsed), 1) eq_(parsed[0], {'manifest_url': self.app2.get_manifest_url(), 'icon': self.app2.get_icon_url(64), 'name': unicode(self.app2.name), 'slug': self.app2.app_slug}) def test_suggestions_multiple_results(self): with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'Something', 'lang': 'en-US'}) parsed = json.loads(response.content) eq_(len(parsed), 2) # Show app2 first since it gets boosted higher b/c of installs. eq_(parsed[0], {'manifest_url': self.app2.get_manifest_url(), 'icon': self.app2.get_icon_url(64), 'name': unicode(self.app2.name), 'slug': self.app2.app_slug}) eq_(parsed[1], {'manifest_url': self.app1.get_manifest_url(), 'icon': self.app1.get_icon_url(64), 'name': unicode(self.app1.name), 'slug': self.app1.app_slug}) def test_suggestion_non_gaia_apps(self): AddonDeviceType.objects.all().delete() self.app1.save() self.app2.save() self.refresh('webapp') with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'something'}) parsed = json.loads(response.content) eq_(parsed, []) def test_suggestions_limit(self): with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'something', 'lang': 'en-US', 'limit': 1}) parsed = json.loads(response.content) eq_(len(parsed), 1) eq_(parsed[0], {'manifest_url': self.app2.get_manifest_url(), 'icon': self.app2.get_icon_url(64), 'name': unicode(self.app2.name), 'slug': self.app2.app_slug})
def setup_client(self, user): access = Access.objects.create(key='test_oauth_key_owner', secret=generate(), user=user) return RestOAuthClient(access)
class TestApi(RestOAuth, ESTestCase): fixtures = fixture('webapp_337141') def setUp(self): self.client = RestOAuthClient(None) self.url = reverse('search-api') self.webapp = Webapp.objects.get(pk=337141) self.category = Category.objects.create(name='test', slug='test', type=amo.ADDON_WEBAPP) self.webapp.icon_hash = 'fakehash' self.webapp.save() self.refresh('webapp') def tearDown(self): for w in Webapp.objects.all(): w.delete() unindex_webapps(list(Webapp.with_deleted.values_list('id', flat=True))) super(TestApi, self).tearDown() def test_verbs(self): self._allowed_verbs(self.url, ['get']) def test_has_cors(self): self.assertCORS(self.client.get(self.url), 'get') def test_meta(self): res = self.client.get(self.url) eq_(res.status_code, 200) eq_(set(res.json.keys()), set(['objects', 'meta'])) eq_(res.json['meta']['total_count'], 1) def test_wrong_category(self): res = self.client.get(self.url, data={'cat': self.category.slug + 'xq'}) eq_(res.status_code, 400) eq_(res['Content-Type'], 'application/json') def test_wrong_weight(self): self.category.update(weight=-1) res = self.client.get(self.url, data={'cat': self.category.slug}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 0) def test_wrong_sort(self): res = self.client.get(self.url, data={'sort': 'awesomeness'}) eq_(res.status_code, 400) def test_sort(self): # Mocked version, to make sure we are calling ES with the parameters # we want. with patch('mkt.webapps.models.Webapp.from_search') as mocked_search: mocked_qs = MagicMock() mocked_search.return_value = mocked_qs for api_sort, es_sort in DEFAULT_SORTING.items(): res = self.client.get(self.url, [('sort', api_sort)]) eq_(res.status_code, 200, res.content) mocked_qs.order_by.assert_called_with(es_sort) # Unmocked version, to make sure elasticsearch is actually accepting # the params. for api_sort, es_sort in DEFAULT_SORTING.items(): res = self.client.get(self.url, [('sort', api_sort)]) eq_(res.status_code, 200) def test_right_category(self): res = self.client.get(self.url, data={'cat': self.category.pk}) eq_(res.status_code, 200) eq_(res.json['objects'], []) def create(self): AddonCategory.objects.create(addon=self.webapp, category=self.category) self.webapp.save() self.refresh('webapp') def test_right_category_present(self): self.create() res = self.client.get( self.url, data={'cat': self.category.pk}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 1) def test_user_info_with_shared_secret(self): user = UserProfile.objects.all()[0] def fakeauth(auth, req, **kw): req.user = user.user req.amo_user = user with patch('mkt.api.middleware.RestSharedSecretMiddleware' '.process_request', fakeauth): with self.settings(SITE_URL=''): self.create() res = self.client.get( self.url, data={'cat': self.category.pk}) obj = res.json['objects'][0] assert 'user' in obj def test_dehydrate(self): with self.settings(SITE_URL='http://hy.fr'): self.create() res = self.client.get(self.url, data={'cat': self.category.pk}) eq_(res.status_code, 200) obj = res.json['objects'][0] content_ratings = obj['content_ratings'] eq_(obj['absolute_url'], absolutify(self.webapp.get_absolute_url())) eq_(obj['app_type'], self.webapp.app_type) eq_(content_ratings['body'], 'generic') eq_(content_ratings['rating'], None) eq_(content_ratings['descriptors'], []) eq_(content_ratings['interactives'], []) eq_(obj['current_version'], u'1.0') eq_(obj['description'], {'en-US': self.webapp.description.localized_string}) eq_(obj['icons']['128'], self.webapp.get_icon_url(128)) ok_(obj['icons']['128'].endswith('?modified=fakehash')) eq_(obj['id'], long(self.webapp.id)) eq_(obj['manifest_url'], self.webapp.get_manifest_url()) eq_(obj['payment_account'], None) self.assertApiUrlEqual(obj['privacy_policy'], '/apps/app/337141/privacy/') eq_(obj['public_stats'], self.webapp.public_stats) eq_(obj['ratings'], {'average': 0.0, 'count': 0}) self.assertApiUrlEqual(obj['resource_uri'], '/apps/app/337141/') eq_(obj['slug'], self.webapp.app_slug) eq_(obj['supported_locales'], ['en-US', 'es', 'pt-BR']) ok_('1.0' in obj['versions']) self.assertApiUrlEqual(obj['versions']['1.0'], '/apps/versions/1268829/') # These only exists if requested by a reviewer. ok_('latest_version' not in obj) ok_('reviewer_flags' not in obj) @patch('mkt.webapps.models.Webapp.get_excluded_region_ids') def test_upsell(self, get_excluded_region_ids): get_excluded_region_ids.return_value = [] upsell = app_factory(premium_type=amo.ADDON_PREMIUM) AddonUpsell.objects.create(free=self.webapp, premium=upsell) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, {'premium_types': 'free'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 1) obj = res.json['objects'][0] eq_(obj['upsell']['id'], upsell.id) eq_(obj['upsell']['app_slug'], upsell.app_slug) eq_(obj['upsell']['name'], upsell.name) eq_(obj['upsell']['icon_url'], upsell.get_icon_url(128)) self.assertApiUrlEqual(obj['upsell']['resource_uri'], '/apps/app/%s/' % upsell.id) eq_(obj['upsell']['region_exclusions'], []) upsell.delete() unindex_webapps([upsell.id]) def test_dehydrate_regions(self): self.webapp.addonexcludedregion.create(region=mkt.regions.BR.id) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url) eq_(res.status_code, 200) obj = res.json['objects'][0] regions = obj['regions'] ok_(mkt.regions.BR.slug not in [r['slug'] for r in regions]) eq_(len(regions), len(mkt.regions.ALL_REGION_IDS) - 1) def test_region_filtering(self): self.webapp.addonexcludedregion.create(region=mkt.regions.BR.id) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'region': 'br'}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 0) def test_languages_filtering(self): # This webapp's supported_locales: [u'en-US', u'es', u'pt-BR'] res = self.client.get(self.url, data={'languages': 'fr'}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 0) for lang in ('fr,pt-BR', 'es, pt-BR', 'es', 'pt-BR'): res = self.client.get(self.url, data={'languages': lang}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_offline_filtering(self): def check(offline, visible): res = self.client.get(self.url, data={'offline': offline}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), int(visible)) # Should NOT show up in offline. # Should show up in online. # Should show up everywhere if not filtered. check(offline='True', visible=False) check(offline='False', visible=True) check(offline='None', visible=True) # Mark that app is capable offline. self.webapp.update(is_packaged=True) self.refresh('webapp') # Should show up in offline. # Should NOT show up in online. # Should show up everywhere if not filtered. check(offline='True', visible=True) check(offline='False', visible=False) check(offline='None', visible=True) def test_q(self): res = self.client.get(self.url, data={'q': 'something'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_q_num_requests(self): es = WebappIndexer.get_es() orig_search = es.search es.counter = 0 def monkey_search(*args, **kwargs): es.counter += 1 return orig_search(*args, **kwargs) es.search = monkey_search res = self.client.get(self.url, data={'q': 'something'}) eq_(res.status_code, 200) eq_(res.json['meta']['total_count'], 1) eq_(len(res.json['objects']), 1) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) # Verify only one search call was made. eq_(es.counter, 1) es.search = orig_search def test_q_num_requests_no_results(self): es = WebappIndexer.get_es() orig_search = es.search es.counter = 0 def monkey_search(*args, **kwargs): es.counter += 1 return orig_search(*args, **kwargs) es.search = monkey_search res = self.client.get(self.url, data={'q': 'noresults'}) eq_(res.status_code, 200) eq_(res.json['meta']['total_count'], 0) eq_(len(res.json['objects']), 0) # Verify only one search call was made. eq_(es.counter, 1) es.search = orig_search def test_q_exact(self): app1 = app_factory(name='test app test11') app2 = app_factory(name='test app test21') app3 = app_factory(name='test app test31') self.refresh('webapp') res = self.client.get(self.url, data={'q': 'test app test21'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 3) # app2 should be first since it's an exact match and is boosted higher. obj = res.json['objects'][0] eq_(obj['slug'], app2.app_slug) app1.delete() app2.delete() app3.delete() unindex_webapps([app1.id, app2.id, app3.id]) def test_q_is_tag(self): Tag(tag_text='whatsupp').save_tag(self.webapp) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'whatsupp'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_q_is_tag_misspelled(self): Tag(tag_text='whatsapp').save_tag(self.webapp) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'whatsupp'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_fuzzy_match(self): res = self.client.get(self.url, data={'q': 'soemthing'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_icu_folding(self): self.webapp.name = {'es': 'Páginas Amarillos'} self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'paginas'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_camel_case_word_splitting(self): self.webapp.name = 'AirCombat' self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'air combat'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_name_localized(self): # First test no ?lang parameter returns all localizations. res = self.client.get(self.url, data={'q': 'something'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) eq_(obj['name'], {u'en-US': u'Something Something Steamcube!', u'es': u'Algo Algo Steamcube!'}) # Second test that adding ?lang returns only that localization. res = self.client.get(self.url, data={'q': 'something', 'lang': 'es'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) eq_(obj['name'], u'Algo Algo Steamcube!') def test_other_localized(self): # Test fields that should be localized. translations = {'en-US': u'Test in English', 'es': u'Test in Español'} self.webapp.homepage = translations self.webapp.support_email = translations self.webapp.support_url = translations self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'q': 'something'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['homepage'], translations) eq_(obj['support_email'], translations) eq_(obj['support_url'], translations) def test_name_localized_to_default_locale(self): self.webapp.update(default_locale='es') self.refresh('webapp') # Make a request in another language that we know will fail. res = self.client.get(self.url, data={'q': 'something', 'lang': 'de'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) eq_(obj['name'], u'Algo Algo Steamcube!') def test_device(self): AddonDeviceType.objects.create( addon=self.webapp, device_type=DEVICE_CHOICES_IDS['desktop']) self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'device': 'desktop'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_no_flash_on_firefoxos(self): AddonDeviceType.objects.create( addon=self.webapp, device_type=DEVICE_CHOICES_IDS['firefoxos']) f = self.webapp.get_latest_file() f.uses_flash = True f.save() self.webapp.save() self.refresh('webapp') res = self.client.get(self.url, data={'dev': 'firefoxos'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 0) def test_premium_types(self): res = self.client.get(self.url, data={'premium_types': 'free'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_premium_types_empty(self): res = self.client.get(self.url, data={'premium_types': 'premium'}) eq_(res.status_code, 200) objs = res.json['objects'] eq_(len(objs), 0) def test_multiple_premium_types(self): res = self.client.get(self.url, data={'premium_types': ['free', 'premium']}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_app_type_hosted(self): res = self.client.get(self.url, data={'app_type': 'hosted'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_app_type_packaged(self): self.webapp.update(is_packaged=True) self.refresh('webapp') res = self.client.get(self.url, data={'app_type': 'packaged'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_app_type_privileged(self): # Override the class-decorated patch. with patch('versions.models.Version.is_privileged', True): self.webapp.update(is_packaged=True) self.refresh('webapp') res = self.client.get(self.url, data={'app_type': 'packaged'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 0) res = self.client.get(self.url, data={'app_type': 'privileged'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 1) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_status_value_packaged(self): # When packaged and not a reviewer we exclude latest version status. self.webapp.update(is_packaged=True) res = self.client.get(self.url) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['status'], amo.STATUS_PUBLIC) eq_('latest_version' in obj, False) def test_addon_type_anon(self): res = self.client.get(self.url, data={'type': 'app'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) res = self.client.get(self.url, data={'type': 'vindaloo'}) eq_(res.status_code, 400) error = res.json['detail'] eq_(error.keys(), ['type']) res = self.client.get(self.url, data={'type': 'theme'}) eq_(res.status_code, 200) eq_(len(res.json['objects']), 0) def test_adolescent_popularity(self): """ Adolescent regions use global popularity. Webapp: Global: 0, Regional: 0 Unknown1: Global: 1, Regional: 1 + 10 * 1 = 11 Unknown2: Global: 2, Regional: 0 """ user = UserProfile.objects.all()[0] cd = ClientData.objects.create(region=mkt.regions.BR.id) unknown1 = amo.tests.app_factory() Installed.objects.create(addon=unknown1, user=user, client_data=cd) unknown2 = amo.tests.app_factory() Installed.objects.create(addon=unknown2, user=user) Installed.objects.create(addon=unknown2, user=user) self.reindex(Webapp, 'webapp') res = self.client.get(self.url, data={'region': 'br'}) eq_(res.status_code, 200) objects = res.json['objects'] eq_(len(objects), 3) eq_(int(objects[0]['id']), unknown2.id) eq_(int(objects[1]['id']), unknown1.id) eq_(int(objects[2]['id']), self.webapp.id) # Cleanup to remove these from the index. unknown1.delete() unknown2.delete() unindex_webapps([unknown1.id, unknown2.id]) def test_word_delimiter_preserves_original(self): self.webapp.description = { 'en-US': 'This is testing word delimiting preservation in long ' 'descriptions and here is what we want to find: WhatsApp' } self.webapp.save() self.reindex(Webapp, 'webapp') res = self.client.get(self.url, data={'q': 'whatsapp'}) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['slug'], self.webapp.app_slug) def test_pagination(self): Webapp.objects.get(pk=337141).delete() app1 = app_factory(name='test app test1') app2 = app_factory(name='test app test2') app3 = app_factory(name='test app test3') # Setting 'created' app_factory is unreliable and we need a reliable # order. app1.update(created=self.days_ago(1)) app2.update(created=self.days_ago(2)) app3.update(created=self.days_ago(3)) self.refresh('webapp') res = self.client.get(self.url, data={'limit': '2', 'sort': 'created'}) eq_(res.status_code, 200) data = json.loads(res.content) eq_(len(data['objects']), 2) eq_(int(data['objects'][0]['id']), app1.id) eq_(int(data['objects'][1]['id']), app2.id) eq_(data['meta']['total_count'], 3) eq_(data['meta']['limit'], 2) eq_(data['meta']['previous'], None) eq_(data['meta']['offset'], 0) next = urlparse(data['meta']['next']) eq_(next.path, self.url) eq_(QueryDict(next.query).dict(), {'limit': '2', 'offset': '2', 'sort': 'created'}) res = self.client.get(self.url, QueryDict(next.query).dict()) eq_(res.status_code, 200) data = json.loads(res.content) eq_(len(data['objects']), 1) eq_(int(data['objects'][0]['id']), app3.id) eq_(data['meta']['total_count'], 3) eq_(data['meta']['limit'], 2) prev = urlparse(data['meta']['previous']) eq_(next.path, self.url) eq_(QueryDict(prev.query).dict(), {'limit': '2', 'offset': '0', 'sort': 'created'}) eq_(data['meta']['offset'], 2) eq_(data['meta']['next'], None) def test_content_ratings_reindex(self): self.webapp.set_content_ratings({ mkt.ratingsbodies.GENERIC: mkt.ratingsbodies.GENERIC_18 }) self.refresh('webapp') res = self.client.get(self.url) obj = res.json['objects'][0] ok_(obj['content_ratings']['rating']) def test_usk_refused_exclude(self): geodata = self.webapp._geodata geodata.update(region_de_usk_exclude=True) self.reindex(Webapp, 'webapp') res = self.client.get(self.url, {'region': 'de'}) ok_(not res.json['objects']) def test_icon_url_never(self): self.webapp.update(icon_hash=None) self.refresh('webapp') res = self.client.get(self.url) eq_(res.status_code, 200) obj = res.json['objects'][0] eq_(obj['icons']['64'], self.webapp.get_icon_url(64)) ok_(obj['icons']['64'].endswith('?modified=never'))
class TestRocketbarApi(ESTestCase): fixtures = fixture('webapp_337141') def setUp(self): self.url = reverse('rocketbar-search-api') self.refresh('webapp') self.client = RestOAuthClient(None) self.app1 = Webapp.objects.get(pk=337141) self.app1.addondevicetype_set.create(device_type=amo.DEVICE_GAIA.id) self.app1.save() self.app2 = app_factory(name=u'Something Second Something Something', description=u'Second dèsc' * 25, icon_type='image/png', created=self.days_ago(3), manifest_url='http://rocket.example.com') self.app2.addondevicetype_set.create(device_type=amo.DEVICE_GAIA.id) self.app2.save() self.refresh('webapp') def tearDown(self): # Cleanup to remove these from the index. unindex_webapps([self.app1.id, self.app2.id]) self.app1.delete() self.app2.delete() def test_no_results(self): with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'whatever', 'lang': 'en-US'}) parsed = json.loads(response.content) eq_(parsed, []) def test_suggestions(self): with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'Something Second', 'lang': 'en-US'}) parsed = json.loads(response.content) eq_(len(parsed), 1) eq_(parsed[0], {'manifest_url': self.app2.get_manifest_url(), 'icon': self.app2.get_icon_url(64), 'name': unicode(self.app2.name), 'slug': self.app2.app_slug}) def test_suggestions_multiple_results(self): with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'Something', 'lang': 'en-US'}) parsed = json.loads(response.content) eq_(len(parsed), 2) eq_(parsed[0], {'manifest_url': self.app1.get_manifest_url(), 'icon': self.app1.get_icon_url(64), 'name': unicode(self.app1.name), 'slug': self.app1.app_slug}) eq_(parsed[1], {'manifest_url': self.app2.get_manifest_url(), 'icon': self.app2.get_icon_url(64), 'name': unicode(self.app2.name), 'slug': self.app2.app_slug}) def test_suggestion_non_gaia_apps(self): AddonDeviceType.objects.all().delete() self.app1.save() self.app2.save() self.refresh('webapp') with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'something'}) parsed = json.loads(response.content) eq_(parsed, []) def test_suggestions_limit(self): with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'something', 'lang': 'en-US', 'limit': 1}) parsed = json.loads(response.content) eq_(len(parsed), 1) eq_(parsed[0], {'manifest_url': self.app1.get_manifest_url(), 'icon': self.app1.get_icon_url(64), 'name': unicode(self.app1.name), 'slug': self.app1.app_slug})
class TestRocketbarApi(ESTestCase): fixtures = fixture('user_2519', 'webapp_337141') def setUp(self): self.url = reverse('rocketbar-search-api') self.refresh('webapp') self.client = RestOAuthClient(None) self.profile = UserProfile.objects.get(pk=2519) self.app1 = Webapp.objects.get(pk=337141) self.app1.addondevicetype_set.create(device_type=amo.DEVICE_GAIA.id) self.app1.save() self.app2 = app_factory(name=u'Something Second Something Something', description=u'Second dèsc' * 25, icon_type='image/png', icon_hash='fakehash', created=self.days_ago(3), manifest_url='http://rocket.example.com') self.app2.addondevicetype_set.create(device_type=amo.DEVICE_GAIA.id) # Add 2 installed records so this app is boosted higher than app1. Installed.objects.create(user=self.profile, addon=self.app2) Installed.objects.create(user=amo.tests.user_factory(), addon=self.app2) self.app2.save() self.refresh('webapp') def tearDown(self): # Cleanup to remove these from the index. self.app1.delete() self.app2.delete() unindex_webapps([self.app1.id, self.app2.id]) # Required to purge the suggestions data structure. In Lucene, a # document is not deleted from a segment, just marked as deleted. WebappIndexer.get_es().optimize(WebappIndexer.get_index(), only_expunge_deletes=True) def test_no_results(self): with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'whatever', 'lang': 'en-US'}) parsed = json.loads(response.content) eq_(parsed, []) def test_suggestions(self): with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'Something Second', 'lang': 'en-US'}) parsed = json.loads(response.content) eq_(len(parsed), 1) eq_(parsed[0], {'manifest_url': self.app2.get_manifest_url(), 'icon': self.app2.get_icon_url(64), 'name': unicode(self.app2.name), 'slug': self.app2.app_slug}) ok_(self.app2.get_icon_url(64).endswith('?modified=fakehash')) def test_suggestion_default_locale(self): self.app2.name.locale = 'es' self.app2.name.save() self.app2.default_locale = 'es' self.app2.save() self.refresh() with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'Something Second', 'lang': 'en-US'}) parsed = json.loads(response.content) eq_(len(parsed), 1) eq_(parsed[0], {'manifest_url': self.app2.get_manifest_url(), 'icon': self.app2.get_icon_url(64), 'name': unicode(self.app2.name), 'slug': self.app2.app_slug}) def test_suggestions_multiple_results(self): with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'Something', 'lang': 'en-US'}) parsed = json.loads(response.content) eq_(len(parsed), 2) # Show app2 first since it gets boosted higher b/c of installs. eq_(parsed[0], {'manifest_url': self.app2.get_manifest_url(), 'icon': self.app2.get_icon_url(64), 'name': unicode(self.app2.name), 'slug': self.app2.app_slug}) eq_(parsed[1], {'manifest_url': self.app1.get_manifest_url(), 'icon': self.app1.get_icon_url(64), 'name': unicode(self.app1.name), 'slug': self.app1.app_slug}) def test_suggestion_non_gaia_apps(self): AddonDeviceType.objects.all().delete() self.app1.save() self.app2.save() self.refresh('webapp') with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'something'}) parsed = json.loads(response.content) eq_(parsed, []) def test_suggestions_limit(self): with self.assertNumQueries(0): response = self.client.get(self.url, data={'q': 'something', 'lang': 'en-US', 'limit': 1}) parsed = json.loads(response.content) eq_(len(parsed), 1) eq_(parsed[0], {'manifest_url': self.app2.get_manifest_url(), 'icon': self.app2.get_icon_url(64), 'name': unicode(self.app2.name), 'slug': self.app2.app_slug})