# -*- coding: utf-8 -*-
import json

from nose.tools import eq_, ok_
from rest_framework.exceptions import ParseError

from django.contrib.auth.models import AnonymousUser
from django.test.client import RequestFactory
from django.test.utils import override_settings

import mkt
from mkt.constants.applications import DEVICE_CHOICES_IDS
from mkt.constants.features import FeatureProfile
from mkt.search.filters import (DeviceTypeFilter, ProfileFilter,
                                PublicAppsFilter, PublicSearchFormFilter,
                                RegionFilter, SearchQueryFilter, SortingFilter,
                                ValidAppsFilter)
from mkt.search.forms import TARAKO_CATEGORIES_MAPPING
from mkt.search.views import SearchView
from mkt.site.tests import TestCase
from mkt.webapps.indexers import WebappIndexer


class FilterTestsBase(TestCase):

    def setUp(self):
        super(FilterTestsBase, self).setUp()
        self.req = RequestFactory().get('/')
        self.req.user = AnonymousUser()
        self.view_class = SearchView

    def _filter(self, req=None, data=None):
        req = req or RequestFactory().get('/', data=data or {})
        req.user = AnonymousUser()
        queryset = WebappIndexer.search()
        for filter_class in self.filter_classes:
            queryset = filter_class().filter_queryset(req, queryset,
                                                      self.view_class)
        return queryset.to_dict()


class TestQueryFilter(FilterTestsBase):

    filter_classes = [SearchQueryFilter]

    def test_q(self):
        qs = self._filter(data={'q': 'search terms'})
        # Spot check a few queries.
        should = (qs['query']['function_score']['query']['bool']['should'])
        ok_({'match': {'name': {'query': 'search terms', 'boost': 4,
                                'slop': 1, 'type': 'phrase'}}}
            in should)
        ok_({'prefix': {'name': {'boost': 1.5, 'value': 'search terms'}}}
            in should)
        ok_({'match': {'name_english': {'query': 'search terms',
                                        'boost': 2.5}}}
            in should)
        ok_({'match': {'description_english': {'query': 'search terms',
                                               'boost': 0.6,
                                               'analyzer': 'english_analyzer',
                                               'type': 'phrase'}}}
            in should)

    def test_fuzzy_single_word(self):
        qs = self._filter(data={'q': 'term'})
        should = (qs['query']['function_score']['query']['bool']['should'])
        ok_({'fuzzy': {'tags': {'prefix_length': 1, 'value': 'term'}}}
            in should)

    def test_no_fuzzy_multi_word(self):
        qs = self._filter(data={'q': 'search terms'})
        qs_str = json.dumps(qs)
        ok_('fuzzy' not in qs_str)

    @override_settings(ES_USE_PLUGINS=True)
    def test_polish_analyzer(self):
        """
        Test that the polish analyzer is included correctly since it is an
        exception to the rest b/c it is a plugin.
        """
        with self.activate(locale='pl'):
            qs = self._filter(data={'q': u'próba'})
            should = (qs['query']['function_score']['query']['bool']['should'])
            ok_({'match': {'name_polish': {'query': u'pr\xf3ba',
                                           'boost': 2.5}}}
                in should)
            ok_({'match': {'description_polish': {'query': u'pr\xf3ba',
                                                  'boost': 0.6,
                                                  'analyzer': 'polish',
                                                  'type': 'phrase'}}}
                in should)


class TestFormFilter(FilterTestsBase):

    filter_classes = [PublicSearchFormFilter]

    def test_category(self):
        qs = self._filter(data={'cat': 'games'})
        ok_({'terms': {'category': ['games']}}
            in qs['query']['filtered']['filter']['bool']['must'])

    def test_tag(self):
        qs = self._filter(data={'tag': 'tarako'})
        ok_({'term': {'tags': 'tarako'}}
            in qs['query']['filtered']['filter']['bool']['must'])

    def test_tarako_categories(self):
        qs = self._filter(data={'cat': 'tarako-lifestyle'})
        ok_({'terms':
             {'category': TARAKO_CATEGORIES_MAPPING['tarako-lifestyle']}}
            in qs['query']['filtered']['filter']['bool']['must'])

        qs = self._filter(data={'cat': 'tarako-games'})
        ok_({'terms': {'category': TARAKO_CATEGORIES_MAPPING['tarako-games']}}
            in qs['query']['filtered']['filter']['bool']['must'])

        qs = self._filter(data={'cat': 'tarako-tools'})
        ok_({'terms': {'category': TARAKO_CATEGORIES_MAPPING['tarako-tools']}}
            in qs['query']['filtered']['filter']['bool']['must'])

    def test_app_type(self):
        qs = self._filter(data={'app_type': ['hosted']})
        ok_({'terms': {'app_type': [1]}}
            in qs['query']['filtered']['filter']['bool']['must'])

    def test_app_type_packaged(self):
        """Test packaged also includes privileged."""
        qs = self._filter(data={'app_type': ['packaged']})
        ok_({'terms': {'app_type': [2, 3]}}
            in qs['query']['filtered']['filter']['bool']['must'])

    def test_manifest_url(self):
        url = 'http://hy.fr/manifest.webapp'
        qs = self._filter(data={'manifest_url': url})
        ok_({'term': {'manifest_url': url}}
            in qs['query']['filtered']['filter']['bool']['must'])

    def test_offline(self):
        """Ensure we are filtering by offline-capable apps."""
        qs = self._filter(data={'offline': 'True'})
        ok_({'term': {'is_offline': True}}
            in qs['query']['filtered']['filter']['bool']['must'])

    def test_online(self):
        """Ensure we are filtering by apps that require online access."""
        qs = self._filter(data={'offline': 'False'})
        ok_({'term': {'is_offline': False}}
            in qs['query']['filtered']['filter']['bool']['must'])

    def test_offline_and_online(self):
        """Ensure we are not filtering by offline/online by default."""
        # Pass any form values other than 'offline' to create the dict.
        qs = self._filter(data={'cat': 'games'})
        ok_({'term': {'is_offline': True}}
            not in qs['query']['filtered']['filter']['bool']['must'])
        ok_({'term': {'is_offline': False}}
            not in qs['query']['filtered']['filter']['bool']['must'])

    def test_languages(self):
        qs = self._filter(data={'languages': 'fr'})
        ok_({'terms': {'supported_locales': ['fr']}}
            in qs['query']['filtered']['filter']['bool']['must'])

        qs = self._filter(data={'languages': 'ar,en-US'})
        ok_({'terms': {'supported_locales': ['ar', 'en-US']}}
            in qs['query']['filtered']['filter']['bool']['must'])

    def test_author(self):
        qs = self._filter(data={'author': 'Mozilla LABS'})
        ok_({'term': {'author.raw': u'mozilla labs'}}
            in qs['query']['filtered']['filter']['bool']['must'])

    def test_installs_allowed_from(self):
        qs = self._filter(data={'installs_allowed_from': '*'})
        ok_({'term': {'installs_allowed_from': u'*'}}
            in qs['query']['filtered']['filter']['bool']['must'])
        # Test that we don't filter by this field if not provided.
        qs = self._filter()
        ok_('installs_allowed_from' not in json.dumps(qs),
            "Unexpected 'installs_allowed_from' in query")

    def test_premium_types(self):
        def ptype(p):
            return mkt.ADDON_PREMIUM_API_LOOKUP.get(p)

        # Test a single premium type.
        qs = self._filter(data={'premium_types': ['free']})
        ok_({'terms': {'premium_type': [ptype('free')]}}
            in qs['query']['filtered']['filter']['bool']['must'])
        # Test many premium types.
        qs = self._filter(data={'premium_types': ['free', 'free-inapp']})
        ok_({'terms': {'premium_type': [ptype('free'), ptype('free-inapp')]}}
            in qs['query']['filtered']['filter']['bool']['must'])
        # Test a non-existent premium type.
        with self.assertRaises(ParseError):
            self._filter(data={'premium_types': ['free', 'platinum']})

    def test_device(self):
        qs = self._filter(data={'dev': 'desktop'})
        ok_({'term': {'device': DEVICE_CHOICES_IDS['desktop']}}
            in qs['query']['filtered']['filter']['bool']['must'])

    def test_no_device_with_device_type(self):
        """Test that providing a device type w/o device doesn't filter."""
        qs = self._filter(data={'dev': '', 'device': 'firefoxos'})
        ok_('filtered' not in qs['query'].keys())


class TestPublicAppsFilter(FilterTestsBase):

    filter_classes = [PublicAppsFilter]

    def test_status(self):
        qs = self._filter(self.req)
        ok_({'term': {'status': mkt.STATUS_PUBLIC}}
            in qs['query']['filtered']['filter']['bool']['must'])
        ok_({'term': {'is_disabled': False}}
            in qs['query']['filtered']['filter']['bool']['must'])


class TestValidAppsFilter(FilterTestsBase):

    filter_classes = [ValidAppsFilter]

    def test_status(self):
        qs = self._filter(self.req)
        ok_({'terms': {'status': mkt.VALID_STATUSES}}
            in qs['query']['filtered']['filter']['bool']['must'])
        ok_({'term': {'is_disabled': False}}
            in qs['query']['filtered']['filter']['bool']['must'])


class TestDeviceTypeFilter(FilterTestsBase):

    filter_classes = [DeviceTypeFilter]

    def test_no_filters(self):
        qs = self._filter(self.req)
        ok_('filtered' not in qs['query'].keys())

    def test_mobile(self):
        self.req.MOBILE = True
        qs = self._filter(self.req)
        ok_({'term': {'uses_flash': False}}
            in qs['query']['filtered']['filter']['bool']['must'])

    def test_gaia(self):
        self.req.GAIA = True
        qs = self._filter(self.req)
        ok_({'term': {'uses_flash': False}}
            in qs['query']['filtered']['filter']['bool']['must'])

    def test_tablet(self):
        self.req.TABLET = True
        qs = self._filter(self.req)
        ok_('filtered' not in qs['query'].keys())

    def test_device_in_querystring(self):
        qs = self._filter(data={'dev': 'desktop'})
        ok_({'term': {'device': 1}}
            in qs['query']['filtered']['filter']['bool']['must'])
        qs = self._filter(data={'dev': 'android', 'device': 'mobile'})
        ok_({'term': {'device': 2}}
            in qs['query']['filtered']['filter']['bool']['must'])
        qs = self._filter(data={'dev': 'android', 'device': 'tablet'})
        ok_({'term': {'device': 3}}
            in qs['query']['filtered']['filter']['bool']['must'])
        qs = self._filter(data={'dev': 'firefoxos'})
        ok_({'term': {'device': 4}}
            in qs['query']['filtered']['filter']['bool']['must'])


class TestRegionFilter(FilterTestsBase):

    filter_classes = [RegionFilter]

    def test_no_region_default(self):
        qs = self._filter(self.req)
        ok_({'term': {'region_exclusions': mkt.regions.RESTOFWORLD.id}}
            in qs['query']['filtered']['filter']['bool']['must_not'])

    def test_region(self):
        self.req.REGION = mkt.regions.BRA
        qs = self._filter(self.req)
        ok_({'term': {'region_exclusions': mkt.regions.BRA.id}}
            in qs['query']['filtered']['filter']['bool']['must_not'])


class TestProfileFilter(FilterTestsBase):

    filter_classes = [ProfileFilter]

    def profile_qs(self, disabled_features=None):
        if disabled_features is None:
            disabled_features = {}
        profile = FeatureProfile().fromkeys(FeatureProfile(), True)
        for feature in disabled_features:
            profile[feature] = False
        return {'pro': profile.to_signature(), 'dev': 'firefoxos'}

    def test_filter_all_features_present(self):
        qs = self._filter(data=self.profile_qs())
        ok_('filtered' not in qs['query'].keys())

    def test_filter_one_feature_present(self):
        qs = self._filter(data=self.profile_qs(disabled_features=['sms']))
        ok_({'term': {'features.has_sms': True}}
            in qs['query']['filtered']['filter']['bool']['must_not'])

    def test_filter_one_feature_present_desktop(self):
        data = self.profile_qs(disabled_features=['sms'])
        data['dev'] = 'desktop'
        qs = self._filter(data=data)
        ok_('filtered' not in qs['query'].keys())

    def test_filter_multiple_features_present(self):
        qs = self._filter(
            data=self.profile_qs(disabled_features=['sms', 'apps']))
        ok_({'term': {'features.has_sms': True}}
            in qs['query']['filtered']['filter']['bool']['must_not'])
        ok_({'term': {'features.has_apps': True}}
            in qs['query']['filtered']['filter']['bool']['must_not'])


class TestSortingFilter(FilterTestsBase):

    filter_classes = [SortingFilter]

    def test_sort(self):
        for api_sort, es_sort in SortingFilter.DEFAULT_SORTING.items():
            qs = self._filter(data={'sort': [api_sort]})
            if es_sort.startswith('-'):
                ok_({es_sort[1:]: {'order': 'desc'}} in qs['sort'], qs)
            else:
                eq_([es_sort], qs['sort'], qs)

    def test_sort_multiple(self):
        qs = self._filter(data={'sort': ['rating', 'created']})
        ok_({'bayesian_rating': {'order': 'desc'}} in qs['sort'])
        ok_({'created': {'order': 'desc'}} in qs['sort'])

    def test_sort_regional(self):
        """Popularity and trending use regional sorting for mature regions."""
        req = RequestFactory().get('/')
        req.REGION = mkt.regions.BRA
        # Default empty query searches use popularity.
        qs = self._filter(req)
        ok_({'popularity_%s'
             % mkt.regions.BRA.id: {'order': 'desc'}} in qs['sort'])
        # Popularity.
        req = RequestFactory().get('/', data={'sort': ['popularity']})
        req.REGION = mkt.regions.BRA
        qs = self._filter(req)
        ok_({'popularity_%s'
             % mkt.regions.BRA.id: {'order': 'desc'}} in qs['sort'])
        # Trending.
        req = RequestFactory().get('/', data={'sort': ['trending']})
        req.REGION = mkt.regions.BRA
        qs = self._filter(req)
        ok_({'trending_%s' % mkt.regions.BRA.id: {'order': 'desc'}}
            in qs['sort'])


class TestCombinedFilter(FilterTestsBase):
    """
    Basic test to ensure that when filters are combined they result in the
    expected query structure.

    """
    filter_classes = [SearchQueryFilter, PublicSearchFormFilter,
                      PublicAppsFilter, SortingFilter]

    def test_combined(self):
        qs = self._filter(data={'q': 'test', 'cat': 'games',
                                'sort': 'trending'})
        ok_(qs['query']['filtered']['query']['function_score'])
        ok_(qs['query']['filtered']['filter'])

        must = qs['query']['filtered']['filter']['bool']['must']
        ok_({'terms': {'category': ['games']}} in must)
        ok_({'term': {'status': 4}} in must)
        ok_({'term': {'is_disabled': False}} in must)

        ok_({'trending': {'order': 'desc'}} in qs['sort'])

        query = qs['query']['filtered']['query']
        ok_({'field_value_factor': {'field': 'boost'}}
            in query['function_score']['functions'])
        ok_({'match': {'name_english': {'boost': 2.5, 'query': u'test'}}}
            in query['function_score']['query']['bool']['should'])

[((2859, 2897), 'django.test.utils.override_settings', 'override_settings', ([], {'ES_USE_PLUGINS': '(True)'}), '(ES_USE_PLUGINS=True)\n', (2876, 2897), False, 'from django.test.utils import override_settings\n'), ((1003, 1018), 'django.contrib.auth.models.AnonymousUser', 'AnonymousUser', ([], {}), '()\n', (1016, 1018), False, 'from django.contrib.auth.models import AnonymousUser\n'), ((1184, 1199), 'django.contrib.auth.models.AnonymousUser', 'AnonymousUser', ([], {}), '()\n', (1197, 1199), False, 'from django.contrib.auth.models import AnonymousUser\n'), ((1219, 1241), 'mkt.webapps.indexers.WebappIndexer.search', 'WebappIndexer.search', ([], {}), '()\n', (1239, 1241), False, 'from mkt.webapps.indexers import WebappIndexer\n'), ((1746, 1852), 'nose.tools.ok_', 'ok_', (["({'match': {'name': {'query': 'search terms', 'boost': 4, 'slop': 1, 'type':\n    'phrase'}}} in should)"], {}), "({'match': {'name': {'query': 'search terms', 'boost': 4, 'slop': 1,\n    'type': 'phrase'}}} in should)\n", (1749, 1852), False, 'from nose.tools import eq_, ok_\n'), ((1901, 1977), 'nose.tools.ok_', 'ok_', (["({'prefix': {'name': {'boost': 1.5, 'value': 'search terms'}}} in should)"], {}), "({'prefix': {'name': {'boost': 1.5, 'value': 'search terms'}}} in should)\n", (1904, 1977), False, 'from nose.tools import eq_, ok_\n'), ((1998, 2085), 'nose.tools.ok_', 'ok_', (["({'match': {'name_english': {'query': 'search terms', 'boost': 2.5}}} in should\n    )"], {}), "({'match': {'name_english': {'query': 'search terms', 'boost': 2.5}}} in\n    should)\n", (2001, 2085), False, 'from nose.tools import eq_, ok_\n'), ((2142, 2287), 'nose.tools.ok_', 'ok_', (["({'match': {'description_english': {'query': 'search terms', 'boost': 0.6,\n    'analyzer': 'english_analyzer', 'type': 'phrase'}}} in should)"], {}), "({'match': {'description_english': {'query': 'search terms', 'boost': \n    0.6, 'analyzer': 'english_analyzer', 'type': 'phrase'}}} in should)\n", (2145, 2287), False, 'from nose.tools import eq_, ok_\n'), ((2605, 2678), 'nose.tools.ok_', 'ok_', (["({'fuzzy': {'tags': {'prefix_length': 1, 'value': 'term'}}} in should)"], {}), "({'fuzzy': {'tags': {'prefix_length': 1, 'value': 'term'}}} in should)\n", (2608, 2678), False, 'from nose.tools import eq_, ok_\n'), ((2803, 2817), 'json.dumps', 'json.dumps', (['qs'], {}), '(qs)\n', (2813, 2817), False, 'import json\n'), ((2826, 2852), 'nose.tools.ok_', 'ok_', (["('fuzzy' not in qs_str)"], {}), "('fuzzy' not in qs_str)\n", (2829, 2852), False, 'from nose.tools import eq_, ok_\n'), ((3887, 3984), 'nose.tools.ok_', 'ok_', (["({'terms': {'category': ['games']}} in qs['query']['filtered']['filter'][\n    'bool']['must'])"], {}), "({'terms': {'category': ['games']}} in qs['query']['filtered']['filter']\n    ['bool']['must'])\n", (3890, 3984), False, 'from nose.tools import eq_, ok_\n'), ((4075, 4166), 'nose.tools.ok_', 'ok_', (["({'term': {'tags': 'tarako'}} in qs['query']['filtered']['filter']['bool'][\n    'must'])"], {}), "({'term': {'tags': 'tarako'}} in qs['query']['filtered']['filter'][\n    'bool']['must'])\n", (4078, 4166), False, 'from nose.tools import eq_, ok_\n'), ((4281, 4413), 'nose.tools.ok_', 'ok_', (["({'terms': {'category': TARAKO_CATEGORIES_MAPPING['tarako-lifestyle']}} in\n    qs['query']['filtered']['filter']['bool']['must'])"], {}), "({'terms': {'category': TARAKO_CATEGORIES_MAPPING['tarako-lifestyle']}} in\n    qs['query']['filtered']['filter']['bool']['must'])\n", (4284, 4413), False, 'from nose.tools import eq_, ok_\n'), ((4500, 4628), 'nose.tools.ok_', 'ok_', (["({'terms': {'category': TARAKO_CATEGORIES_MAPPING['tarako-games']}} in qs[\n    'query']['filtered']['filter']['bool']['must'])"], {}), "({'terms': {'category': TARAKO_CATEGORIES_MAPPING['tarako-games']}} in\n    qs['query']['filtered']['filter']['bool']['must'])\n", (4503, 4628), False, 'from nose.tools import eq_, ok_\n'), ((4702, 4830), 'nose.tools.ok_', 'ok_', (["({'terms': {'category': TARAKO_CATEGORIES_MAPPING['tarako-tools']}} in qs[\n    'query']['filtered']['filter']['bool']['must'])"], {}), "({'terms': {'category': TARAKO_CATEGORIES_MAPPING['tarako-tools']}} in\n    qs['query']['filtered']['filter']['bool']['must'])\n", (4705, 4830), False, 'from nose.tools import eq_, ok_\n'), ((4934, 5025), 'nose.tools.ok_', 'ok_', (["({'terms': {'app_type': [1]}} in qs['query']['filtered']['filter']['bool'][\n    'must'])"], {}), "({'terms': {'app_type': [1]}} in qs['query']['filtered']['filter'][\n    'bool']['must'])\n", (4937, 5025), False, 'from nose.tools import eq_, ok_\n'), ((5193, 5287), 'nose.tools.ok_', 'ok_', (["({'terms': {'app_type': [2, 3]}} in qs['query']['filtered']['filter'][\n    'bool']['must'])"], {}), "({'terms': {'app_type': [2, 3]}} in qs['query']['filtered']['filter'][\n    'bool']['must'])\n", (5196, 5287), False, 'from nose.tools import eq_, ok_\n'), ((5436, 5530), 'nose.tools.ok_', 'ok_', (["({'term': {'manifest_url': url}} in qs['query']['filtered']['filter'][\n    'bool']['must'])"], {}), "({'term': {'manifest_url': url}} in qs['query']['filtered']['filter'][\n    'bool']['must'])\n", (5439, 5530), False, 'from nose.tools import eq_, ok_\n'), ((5690, 5783), 'nose.tools.ok_', 'ok_', (["({'term': {'is_offline': True}} in qs['query']['filtered']['filter']['bool'\n    ]['must'])"], {}), "({'term': {'is_offline': True}} in qs['query']['filtered']['filter'][\n    'bool']['must'])\n", (5693, 5783), False, 'from nose.tools import eq_, ok_\n'), ((5954, 6048), 'nose.tools.ok_', 'ok_', (["({'term': {'is_offline': False}} in qs['query']['filtered']['filter'][\n    'bool']['must'])"], {}), "({'term': {'is_offline': False}} in qs['query']['filtered']['filter'][\n    'bool']['must'])\n", (5957, 6048), False, 'from nose.tools import eq_, ok_\n'), ((6297, 6394), 'nose.tools.ok_', 'ok_', (["({'term': {'is_offline': True}} not in qs['query']['filtered']['filter'][\n    'bool']['must'])"], {}), "({'term': {'is_offline': True}} not in qs['query']['filtered']['filter']\n    ['bool']['must'])\n", (6300, 6394), False, 'from nose.tools import eq_, ok_\n'), ((6410, 6508), 'nose.tools.ok_', 'ok_', (["({'term': {'is_offline': False}} not in qs['query']['filtered']['filter'][\n    'bool']['must'])"], {}), "({'term': {'is_offline': False}} not in qs['query']['filtered']['filter'\n    ]['bool']['must'])\n", (6413, 6508), False, 'from nose.tools import eq_, ok_\n'), ((6607, 6710), 'nose.tools.ok_', 'ok_', (["({'terms': {'supported_locales': ['fr']}} in qs['query']['filtered'][\n    'filter']['bool']['must'])"], {}), "({'terms': {'supported_locales': ['fr']}} in qs['query']['filtered'][\n    'filter']['bool']['must'])\n", (6610, 6710), False, 'from nose.tools import eq_, ok_\n'), ((6785, 6897), 'nose.tools.ok_', 'ok_', (["({'terms': {'supported_locales': ['ar', 'en-US']}} in qs['query'][\n    'filtered']['filter']['bool']['must'])"], {}), "({'terms': {'supported_locales': ['ar', 'en-US']}} in qs['query'][\n    'filtered']['filter']['bool']['must'])\n", (6788, 6897), False, 'from nose.tools import eq_, ok_\n'), ((7000, 7104), 'nose.tools.ok_', 'ok_', (["({'term': {'author.raw': u'mozilla labs'}} in qs['query']['filtered'][\n    'filter']['bool']['must'])"], {}), "({'term': {'author.raw': u'mozilla labs'}} in qs['query']['filtered'][\n    'filter']['bool']['must'])\n", (7003, 7104), False, 'from nose.tools import eq_, ok_\n'), ((7226, 7330), 'nose.tools.ok_', 'ok_', (["({'term': {'installs_allowed_from': u'*'}} in qs['query']['filtered'][\n    'filter']['bool']['must'])"], {}), "({'term': {'installs_allowed_from': u'*'}} in qs['query']['filtered'][\n    'filter']['bool']['must'])\n", (7229, 7330), False, 'from nose.tools import eq_, ok_\n'), ((8384, 8498), 'nose.tools.ok_', 'ok_', (["({'term': {'device': DEVICE_CHOICES_IDS['desktop']}} in qs['query'][\n    'filtered']['filter']['bool']['must'])"], {}), "({'term': {'device': DEVICE_CHOICES_IDS['desktop']}} in qs['query'][\n    'filtered']['filter']['bool']['must'])\n", (8387, 8498), False, 'from nose.tools import eq_, ok_\n'), ((8906, 9008), 'nose.tools.ok_', 'ok_', (["({'term': {'status': mkt.STATUS_PUBLIC}} in qs['query']['filtered'][\n    'filter']['bool']['must'])"], {}), "({'term': {'status': mkt.STATUS_PUBLIC}} in qs['query']['filtered'][\n    'filter']['bool']['must'])\n", (8909, 9008), False, 'from nose.tools import eq_, ok_\n'), ((9024, 9119), 'nose.tools.ok_', 'ok_', (["({'term': {'is_disabled': False}} in qs['query']['filtered']['filter'][\n    'bool']['must'])"], {}), "({'term': {'is_disabled': False}} in qs['query']['filtered']['filter'][\n    'bool']['must'])\n", (9027, 9119), False, 'from nose.tools import eq_, ok_\n'), ((9285, 9389), 'nose.tools.ok_', 'ok_', (["({'terms': {'status': mkt.VALID_STATUSES}} in qs['query']['filtered'][\n    'filter']['bool']['must'])"], {}), "({'terms': {'status': mkt.VALID_STATUSES}} in qs['query']['filtered'][\n    'filter']['bool']['must'])\n", (9288, 9389), False, 'from nose.tools import eq_, ok_\n'), ((9405, 9500), 'nose.tools.ok_', 'ok_', (["({'term': {'is_disabled': False}} in qs['query']['filtered']['filter'][\n    'bool']['must'])"], {}), "({'term': {'is_disabled': False}} in qs['query']['filtered']['filter'][\n    'bool']['must'])\n", (9408, 9500), False, 'from nose.tools import eq_, ok_\n'), ((9817, 9911), 'nose.tools.ok_', 'ok_', (["({'term': {'uses_flash': False}} in qs['query']['filtered']['filter'][\n    'bool']['must'])"], {}), "({'term': {'uses_flash': False}} in qs['query']['filtered']['filter'][\n    'bool']['must'])\n", (9820, 9911), False, 'from nose.tools import eq_, ok_\n'), ((10018, 10112), 'nose.tools.ok_', 'ok_', (["({'term': {'uses_flash': False}} in qs['query']['filtered']['filter'][\n    'bool']['must'])"], {}), "({'term': {'uses_flash': False}} in qs['query']['filtered']['filter'][\n    'bool']['must'])\n", (10021, 10112), False, 'from nose.tools import eq_, ok_\n'), ((10367, 10453), 'nose.tools.ok_', 'ok_', (["({'term': {'device': 1}} in qs['query']['filtered']['filter']['bool']['must'])"], {}), "({'term': {'device': 1}} in qs['query']['filtered']['filter']['bool'][\n    'must'])\n", (10370, 10453), False, 'from nose.tools import eq_, ok_\n'), ((10540, 10626), 'nose.tools.ok_', 'ok_', (["({'term': {'device': 2}} in qs['query']['filtered']['filter']['bool']['must'])"], {}), "({'term': {'device': 2}} in qs['query']['filtered']['filter']['bool'][\n    'must'])\n", (10543, 10626), False, 'from nose.tools import eq_, ok_\n'), ((10713, 10799), 'nose.tools.ok_', 'ok_', (["({'term': {'device': 3}} in qs['query']['filtered']['filter']['bool']['must'])"], {}), "({'term': {'device': 3}} in qs['query']['filtered']['filter']['bool'][\n    'must'])\n", (10716, 10799), False, 'from nose.tools import eq_, ok_\n'), ((10868, 10954), 'nose.tools.ok_', 'ok_', (["({'term': {'device': 4}} in qs['query']['filtered']['filter']['bool']['must'])"], {}), "({'term': {'device': 4}} in qs['query']['filtered']['filter']['bool'][\n    'must'])\n", (10871, 10954), False, 'from nose.tools import eq_, ok_\n'), ((11125, 11251), 'nose.tools.ok_', 'ok_', (["({'term': {'region_exclusions': mkt.regions.RESTOFWORLD.id}} in qs['query']\n    ['filtered']['filter']['bool']['must_not'])"], {}), "({'term': {'region_exclusions': mkt.regions.RESTOFWORLD.id}} in qs[\n    'query']['filtered']['filter']['bool']['must_not'])\n", (11128, 11251), False, 'from nose.tools import eq_, ok_\n'), ((11373, 11491), 'nose.tools.ok_', 'ok_', (["({'term': {'region_exclusions': mkt.regions.BRA.id}} in qs['query'][\n    'filtered']['filter']['bool']['must_not'])"], {}), "({'term': {'region_exclusions': mkt.regions.BRA.id}} in qs['query'][\n    'filtered']['filter']['bool']['must_not'])\n", (11376, 11491), False, 'from nose.tools import eq_, ok_\n'), ((12199, 12302), 'nose.tools.ok_', 'ok_', (["({'term': {'features.has_sms': True}} in qs['query']['filtered']['filter'][\n    'bool']['must_not'])"], {}), "({'term': {'features.has_sms': True}} in qs['query']['filtered'][\n    'filter']['bool']['must_not'])\n", (12202, 12302), False, 'from nose.tools import eq_, ok_\n'), ((12701, 12804), 'nose.tools.ok_', 'ok_', (["({'term': {'features.has_sms': True}} in qs['query']['filtered']['filter'][\n    'bool']['must_not'])"], {}), "({'term': {'features.has_sms': True}} in qs['query']['filtered'][\n    'filter']['bool']['must_not'])\n", (12704, 12804), False, 'from nose.tools import eq_, ok_\n'), ((12820, 12924), 'nose.tools.ok_', 'ok_', (["({'term': {'features.has_apps': True}} in qs['query']['filtered']['filter']\n    ['bool']['must_not'])"], {}), "({'term': {'features.has_apps': True}} in qs['query']['filtered'][\n    'filter']['bool']['must_not'])\n", (12823, 12924), False, 'from nose.tools import eq_, ok_\n'), ((13073, 13110), 'mkt.search.filters.SortingFilter.DEFAULT_SORTING.items', 'SortingFilter.DEFAULT_SORTING.items', ([], {}), '()\n', (13108, 13110), False, 'from mkt.search.filters import DeviceTypeFilter, ProfileFilter, PublicAppsFilter, PublicSearchFormFilter, RegionFilter, SearchQueryFilter, SortingFilter, ValidAppsFilter\n'), ((13453, 13510), 'nose.tools.ok_', 'ok_', (["({'bayesian_rating': {'order': 'desc'}} in qs['sort'])"], {}), "({'bayesian_rating': {'order': 'desc'}} in qs['sort'])\n", (13456, 13510), False, 'from nose.tools import eq_, ok_\n'), ((13519, 13568), 'nose.tools.ok_', 'ok_', (["({'created': {'order': 'desc'}} in qs['sort'])"], {}), "({'created': {'order': 'desc'}} in qs['sort'])\n", (13522, 13568), False, 'from nose.tools import eq_, ok_\n'), ((13854, 13932), 'nose.tools.ok_', 'ok_', (["({('popularity_%s' % mkt.regions.BRA.id): {'order': 'desc'}} in qs['sort'])"], {}), "({('popularity_%s' % mkt.regions.BRA.id): {'order': 'desc'}} in qs['sort'])\n", (13857, 13932), False, 'from nose.tools import eq_, ok_\n'), ((14113, 14191), 'nose.tools.ok_', 'ok_', (["({('popularity_%s' % mkt.regions.BRA.id): {'order': 'desc'}} in qs['sort'])"], {}), "({('popularity_%s' % mkt.regions.BRA.id): {'order': 'desc'}} in qs['sort'])\n", (14116, 14191), False, 'from nose.tools import eq_, ok_\n'), ((14368, 14444), 'nose.tools.ok_', 'ok_', (["({('trending_%s' % mkt.regions.BRA.id): {'order': 'desc'}} in qs['sort'])"], {}), "({('trending_%s' % mkt.regions.BRA.id): {'order': 'desc'}} in qs['sort'])\n", (14371, 14444), False, 'from nose.tools import eq_, ok_\n'), ((14894, 14949), 'nose.tools.ok_', 'ok_', (["qs['query']['filtered']['query']['function_score']"], {}), "(qs['query']['filtered']['query']['function_score'])\n", (14897, 14949), False, 'from nose.tools import eq_, ok_\n'), ((14958, 14996), 'nose.tools.ok_', 'ok_', (["qs['query']['filtered']['filter']"], {}), "(qs['query']['filtered']['filter'])\n", (14961, 14996), False, 'from nose.tools import eq_, ok_\n'), ((15071, 15118), 'nose.tools.ok_', 'ok_', (["({'terms': {'category': ['games']}} in must)"], {}), "({'terms': {'category': ['games']}} in must)\n", (15074, 15118), False, 'from nose.tools import eq_, ok_\n'), ((15127, 15163), 'nose.tools.ok_', 'ok_', (["({'term': {'status': 4}} in must)"], {}), "({'term': {'status': 4}} in must)\n", (15130, 15163), False, 'from nose.tools import eq_, ok_\n'), ((15172, 15217), 'nose.tools.ok_', 'ok_', (["({'term': {'is_disabled': False}} in must)"], {}), "({'term': {'is_disabled': False}} in must)\n", (15175, 15217), False, 'from nose.tools import eq_, ok_\n'), ((15227, 15277), 'nose.tools.ok_', 'ok_', (["({'trending': {'order': 'desc'}} in qs['sort'])"], {}), "({'trending': {'order': 'desc'}} in qs['sort'])\n", (15230, 15277), False, 'from nose.tools import eq_, ok_\n'), ((15336, 15428), 'nose.tools.ok_', 'ok_', (["({'field_value_factor': {'field': 'boost'}} in query['function_score'][\n    'functions'])"], {}), "({'field_value_factor': {'field': 'boost'}} in query['function_score'][\n    'functions'])\n", (15339, 15428), False, 'from nose.tools import eq_, ok_\n'), ((15444, 15569), 'nose.tools.ok_', 'ok_', (["({'match': {'name_english': {'boost': 2.5, 'query': u'test'}}} in query[\n    'function_score']['query']['bool']['should'])"], {}), "({'match': {'name_english': {'boost': 2.5, 'query': u'test'}}} in query[\n    'function_score']['query']['bool']['should'])\n", (15447, 15569), False, 'from nose.tools import eq_, ok_\n'), ((3268, 3344), 'nose.tools.ok_', 'ok_', (["({'match': {'name_polish': {'query': u'próba', 'boost': 2.5}}} in should)"], {}), "({'match': {'name_polish': {'query': u'próba', 'boost': 2.5}}} in should)\n", (3271, 3344), False, 'from nose.tools import eq_, ok_\n'), ((3419, 3546), 'nose.tools.ok_', 'ok_', (["({'match': {'description_polish': {'query': u'próba', 'boost': 0.6,\n    'analyzer': 'polish', 'type': 'phrase'}}} in should)"], {}), "({'match': {'description_polish': {'query': u'próba', 'boost': 0.6,\n    'analyzer': 'polish', 'type': 'phrase'}}} in should)\n", (3422, 3546), False, 'from nose.tools import eq_, ok_\n'), ((7627, 7662), 'mkt.ADDON_PREMIUM_API_LOOKUP.get', 'mkt.ADDON_PREMIUM_API_LOOKUP.get', (['p'], {}), '(p)\n', (7659, 7662), False, 'import mkt\n'), ((11749, 11765), 'mkt.constants.features.FeatureProfile', 'FeatureProfile', ([], {}), '()\n', (11763, 11765), False, 'from mkt.constants.features import FeatureProfile\n'), ((953, 969), 'django.test.client.RequestFactory', 'RequestFactory', ([], {}), '()\n', (967, 969), False, 'from django.test.client import RequestFactory\n'), ((7476, 7490), 'json.dumps', 'json.dumps', (['qs'], {}), '(qs)\n', (7486, 7490), False, 'import json\n'), ((11723, 11739), 'mkt.constants.features.FeatureProfile', 'FeatureProfile', ([], {}), '()\n', (11737, 11739), False, 'from mkt.constants.features import FeatureProfile\n'), ((13225, 13280), 'nose.tools.ok_', 'ok_', (["({es_sort[1:]: {'order': 'desc'}} in qs['sort'])", 'qs'], {}), "({es_sort[1:]: {'order': 'desc'}} in qs['sort'], qs)\n", (13228, 13280), False, 'from nose.tools import eq_, ok_\n'), ((13315, 13345), 'nose.tools.eq_', 'eq_', (['[es_sort]', "qs['sort']", 'qs'], {}), "([es_sort], qs['sort'], qs)\n", (13318, 13345), False, 'from nose.tools import eq_, ok_\n'), ((13697, 13713), 'django.test.client.RequestFactory', 'RequestFactory', ([], {}), '()\n', (13711, 13713), False, 'from django.test.client import RequestFactory\n'), ((13980, 13996), 'django.test.client.RequestFactory', 'RequestFactory', ([], {}), '()\n', (13994, 13996), False, 'from django.test.client import RequestFactory\n'), ((14237, 14253), 'django.test.client.RequestFactory', 'RequestFactory', ([], {}), '()\n', (14251, 14253), False, 'from django.test.client import RequestFactory\n'), ((1122, 1138), 'django.test.client.RequestFactory', 'RequestFactory', ([], {}), '()\n', (1136, 1138), False, 'from django.test.client import RequestFactory\n')]