예제 #1
0
class WhooshSearchBackendTestCase(TestCase):
    fixtures = ['bulk_data.json']

    def setUp(self):
        super(WhooshSearchBackendTestCase, self).setUp()

        # Stow.
        temp_path = os.path.join('tmp', 'test_whoosh_query')
        self.old_whoosh_path = getattr(settings, 'HAYSTACK_WHOOSH_PATH',
                                       temp_path)
        settings.HAYSTACK_WHOOSH_PATH = temp_path

        self.site = SearchSite()
        self.sb = SearchBackend(site=self.site)
        self.smmi = WhooshMockSearchIndex(MockModel, backend=self.sb)
        self.wmtmmi = WhooshMaintainTypeMockSearchIndex(MockModel,
                                                        backend=self.sb)
        self.site.register(MockModel, WhooshMockSearchIndex)

        # With the models registered, you get the proper bits.
        import haystack

        # Stow.
        self.old_site = haystack.site
        haystack.site = self.site

        self.sb.setup()
        self.raw_whoosh = self.sb.index
        self.parser = QueryParser(self.sb.content_field_name,
                                  schema=self.sb.schema)
        self.sb.delete_index()

        self.sample_objs = MockModel.objects.all()

    def tearDown(self):
        if os.path.exists(settings.HAYSTACK_WHOOSH_PATH):
            shutil.rmtree(settings.HAYSTACK_WHOOSH_PATH)

        settings.HAYSTACK_WHOOSH_PATH = self.old_whoosh_path

        # Restore.
        import haystack
        haystack.site = self.old_site

        super(WhooshSearchBackendTestCase, self).tearDown()

    def whoosh_search(self, query):
        self.raw_whoosh = self.raw_whoosh.refresh()
        searcher = self.raw_whoosh.searcher()
        return searcher.search(self.parser.parse(query), limit=1000)

    def test_update(self):
        self.sb.update(self.smmi, self.sample_objs)

        # Check what Whoosh thinks is there.
        self.assertEqual(len(self.whoosh_search(u'*')), 23)
        self.assertEqual(
            [doc.fields()['id'] for doc in self.whoosh_search(u'*')],
            [u'core.mockmodel.%s' % i for i in xrange(1, 24)])

    def test_remove(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.sb.index.doc_count(), 23)

        self.sb.remove(self.sample_objs[0])
        self.assertEqual(self.sb.index.doc_count(), 22)

    def test_clear(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.sb.index.doc_count(), 23)

        self.sb.clear()
        self.assertEqual(self.sb.index.doc_count(), 0)

        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.sb.index.doc_count(), 23)

        self.sb.clear([AnotherMockModel])
        self.assertEqual(self.sb.index.doc_count(), 23)

        self.sb.clear([MockModel])
        self.assertEqual(self.sb.index.doc_count(), 0)

        self.sb.index.refresh()
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.sb.index.doc_count(), 23)

        self.sb.clear([AnotherMockModel, MockModel])
        self.assertEqual(self.raw_whoosh.doc_count(), 0)

    def test_search(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(len(self.whoosh_search(u'*')), 23)

        # No query string should always yield zero results.
        self.assertEqual(self.sb.search(u''), {'hits': 0, 'results': []})

        # A one letter query string gets nabbed by a stopwords filter. Should
        # always yield zero results.
        self.assertEqual(self.sb.search(u'a'), {'hits': 0, 'results': []})

        # Possible AttributeError?
        # self.assertEqual(self.sb.search(u'a b'), {'hits': 0, 'results': [], 'spelling_suggestion': '', 'facets': {}})

        self.assertEqual(self.sb.search(u'*')['hits'], 23)
        self.assertEqual(
            [result.pk for result in self.sb.search(u'*')['results']],
            [u'%s' % i for i in xrange(1, 24)])

        self.assertEqual(self.sb.search(u'', highlight=True), {
            'hits': 0,
            'results': []
        })
        self.assertEqual(self.sb.search(u'index*', highlight=True)['hits'], 23)
        # DRL_FIXME: Uncomment once highlighting works.
        # self.assertEqual([result.highlighted['text'][0] for result in self.sb.search('Index*', highlight=True)['results']], ['<em>Indexed</em>!\n3', '<em>Indexed</em>!\n2', '<em>Indexed</em>!\n1'])

        self.assertEqual(self.sb.search(u'Indx')['hits'], 0)
        self.assertEqual(
            self.sb.search(u'Indx')['spelling_suggestion'], u'index')

        self.assertEqual(self.sb.search(u'', facets=['name']), {
            'hits': 0,
            'results': []
        })
        results = self.sb.search(u'Index*', facets=['name'])
        results = self.sb.search(u'index*', facets=['name'])
        self.assertEqual(results['hits'], 23)
        self.assertEqual(results['facets'], {})

        self.assertEqual(
            self.sb.search(u'',
                           date_facets={
                               'pub_date': {
                                   'start_date': date(2008, 2, 26),
                                   'end_date': date(2008, 2, 26),
                                   'gap': '/MONTH'
                               }
                           }), {
                               'hits': 0,
                               'results': []
                           })
        results = self.sb.search(u'Index*',
                                 date_facets={
                                     'pub_date': {
                                         'start_date': date(2008, 2, 26),
                                         'end_date': date(2008, 2, 26),
                                         'gap': '/MONTH'
                                     }
                                 })
        results = self.sb.search(u'index*',
                                 date_facets={
                                     'pub_date': {
                                         'start_date': date(2008, 2, 26),
                                         'end_date': date(2008, 2, 26),
                                         'gap': '/MONTH'
                                     }
                                 })
        self.assertEqual(results['hits'], 23)
        self.assertEqual(results['facets'], {})

        self.assertEqual(
            self.sb.search(u'', query_facets={'name': '[* TO e]'}), {
                'hits': 0,
                'results': []
            })
        results = self.sb.search(u'Index*', query_facets={'name': '[* TO e]'})
        results = self.sb.search(u'index*', query_facets={'name': '[* TO e]'})
        self.assertEqual(results['hits'], 23)
        self.assertEqual(results['facets'], {})

        # self.assertEqual(self.sb.search('', narrow_queries=set(['name:daniel1'])), {'hits': 0, 'results': []})
        # results = self.sb.search('Index*', narrow_queries=set(['name:daniel1']))
        # self.assertEqual(results['hits'], 1)

        # Ensure that swapping the ``result_class`` works.
        self.assertTrue(
            isinstance(
                self.sb.search(u'Index*',
                               result_class=MockSearchResult)['results'][0],
                MockSearchResult))

        # Check the use of ``limit_to_registered_models``.
        self.assertEqual(self.sb.search(u'', limit_to_registered_models=False),
                         {
                             'hits': 0,
                             'results': []
                         })
        self.assertEqual(
            self.sb.search(u'*', limit_to_registered_models=False)['hits'], 23)
        self.assertEqual([
            result.pk for result in self.sb.search(
                u'*', limit_to_registered_models=False)['results']
        ], [u'%s' % i for i in xrange(1, 24)])

        # Stow.
        old_limit_to_registered_models = getattr(
            settings, 'HAYSTACK_LIMIT_TO_REGISTERED_MODELS', True)
        settings.HAYSTACK_LIMIT_TO_REGISTERED_MODELS = False

        self.assertEqual(self.sb.search(u''), {'hits': 0, 'results': []})
        self.assertEqual(self.sb.search(u'*')['hits'], 23)
        self.assertEqual(
            [result.pk for result in self.sb.search(u'*')['results']],
            [u'%s' % i for i in xrange(1, 24)])

        # Restore.
        settings.HAYSTACK_LIMIT_TO_REGISTERED_MODELS = old_limit_to_registered_models

    def test_more_like_this(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(len(self.whoosh_search(u'*')), 23)

        # Unsupported by Whoosh. Should see empty results.
        self.assertEqual(
            self.sb.more_like_this(self.sample_objs[0])['hits'], 0)

        # Make sure that swapping the ``result_class`` doesn't blow up.
        try:
            self.sb.search(u'index document', result_class=MockSearchResult)
        except:
            self.fail()

    def test_delete_index(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assert_(self.sb.index.doc_count() > 0)

        self.sb.delete_index()
        self.assertEqual(self.sb.index.doc_count(), 0)

    def test_order_by(self):
        self.sb.update(self.smmi, self.sample_objs)

        results = self.sb.search(u'*', sort_by=['pub_date'])
        self.assertEqual([result.pk for result in results['results']], [
            u'1', u'3', u'2', u'4', u'5', u'6', u'7', u'8', u'9', u'10', u'11',
            u'12', u'13', u'14', u'15', u'16', u'17', u'18', u'19', u'20',
            u'21', u'22', u'23'
        ])

        results = self.sb.search(u'*', sort_by=['-pub_date'])
        self.assertEqual([result.pk for result in results['results']], [
            u'23', u'22', u'21', u'20', u'19', u'18', u'17', u'16', u'15',
            u'14', u'13', u'12', u'11', u'10', u'9', u'8', u'7', u'6', u'5',
            u'4', u'2', u'3', u'1'
        ])

        results = self.sb.search(u'*', sort_by=['id'])
        self.assertEqual([result.pk for result in results['results']], [
            u'1', u'10', u'11', u'12', u'13', u'14', u'15', u'16', u'17',
            u'18', u'19', u'2', u'20', u'21', u'22', u'23', u'3', u'4', u'5',
            u'6', u'7', u'8', u'9'
        ])

        results = self.sb.search(u'*', sort_by=['-id'])
        self.assertEqual([result.pk for result in results['results']], [
            u'9', u'8', u'7', u'6', u'5', u'4', u'3', u'23', u'22', u'21',
            u'20', u'2', u'19', u'18', u'17', u'16', u'15', u'14', u'13',
            u'12', u'11', u'10', u'1'
        ])

    def test__from_python(self):
        self.assertEqual(self.sb._from_python('abc'), u'abc')
        self.assertEqual(self.sb._from_python(1), 1)
        self.assertEqual(self.sb._from_python(2653), 2653)
        self.assertEqual(self.sb._from_python(25.5), 25.5)
        self.assertEqual(self.sb._from_python([1, 2, 3]), u'1,2,3')
        self.assertEqual(self.sb._from_python({
            'a': 1,
            'c': 3,
            'b': 2
        }), u"{'a': 1, 'c': 3, 'b': 2}")
        self.assertEqual(self.sb._from_python(datetime(2009, 5, 9, 16, 14)),
                         datetime(2009, 5, 9, 16, 14))
        self.assertEqual(self.sb._from_python(datetime(2009, 5, 9, 0, 0)),
                         datetime(2009, 5, 9, 0, 0))
        self.assertEqual(self.sb._from_python(datetime(1899, 5, 18, 0, 0)),
                         datetime(1899, 5, 18, 0, 0))
        self.assertEqual(
            self.sb._from_python(datetime(2009, 5, 18, 1, 16, 30, 250)),
            datetime(2009, 5, 18, 1, 16, 30, 250))

    def test__to_python(self):
        self.assertEqual(self.sb._to_python('abc'), 'abc')
        self.assertEqual(self.sb._to_python('1'), 1)
        self.assertEqual(self.sb._to_python('2653'), 2653)
        self.assertEqual(self.sb._to_python('25.5'), 25.5)
        self.assertEqual(self.sb._to_python('[1, 2, 3]'), [1, 2, 3])
        self.assertEqual(self.sb._to_python('{"a": 1, "b": 2, "c": 3}'), {
            'a': 1,
            'c': 3,
            'b': 2
        })
        self.assertEqual(self.sb._to_python('2009-05-09T16:14:00'),
                         datetime(2009, 5, 9, 16, 14))
        self.assertEqual(self.sb._to_python('2009-05-09T00:00:00'),
                         datetime(2009, 5, 9, 0, 0))
        self.assertEqual(self.sb._to_python(None), None)

    def test_range_queries(self):
        self.sb.update(self.smmi, self.sample_objs)

        self.assertEqual(len(self.whoosh_search(u'[d TO]')), 23)
        self.assertEqual(len(self.whoosh_search(u'name:[d TO]')), 23)
        self.assertEqual(len(self.whoosh_search(u'Ind* AND name:[d TO]')), 23)
        self.assertEqual(len(self.whoosh_search(u'Ind* AND name:[TO c]')), 0)

    def test_date_queries(self):
        self.sb.update(self.smmi, self.sample_objs)

        self.assertEqual(len(self.whoosh_search(u"pub_date:20090717T003000")),
                         1)
        self.assertEqual(len(self.whoosh_search(u"pub_date:20090717T000000")),
                         0)
        self.assertEqual(
            len(self.whoosh_search(u'Ind* AND pub_date:[TO 20090717T003000]')),
            3)

    def test_escaped_characters_queries(self):
        self.sb.update(self.smmi, self.sample_objs)

        self.assertEqual(len(self.whoosh_search(u"Indexed\!")), 23)
        self.assertEqual(
            len(self.whoosh_search(u"http\:\/\/www\.example\.com")), 0)

    def test_build_schema(self):
        self.site.unregister(MockModel)
        self.site.register(MockModel, AllTypesWhooshMockSearchIndex)

        (content_field_name,
         schema) = self.sb.build_schema(self.site.all_searchfields())
        self.assertEqual(content_field_name, 'text')
        self.assertEqual(len(schema.names()), 8)
        self.assertEqual(schema.names(), [
            'django_ct', 'django_id', 'id', 'name', 'pub_date', 'seen_count',
            'sites', 'text'
        ])
        self.assert_(isinstance(schema._fields['text'], TEXT))
        self.assert_(isinstance(schema._fields['pub_date'], DATETIME))
        self.assert_(isinstance(schema._fields['seen_count'], NUMERIC))
        self.assert_(isinstance(schema._fields['sites'], KEYWORD))

    def test_verify_type(self):
        import haystack
        haystack.site.unregister(MockModel)
        haystack.site.register(MockModel, WhooshMaintainTypeMockSearchIndex)
        self.sb.setup()
        self.sb.update(self.wmtmmi, self.sample_objs)

        self.assertEqual(self.sb.search(u'*')['hits'], 23)
        self.assertEqual(
            [result.month for result in self.sb.search(u'*')['results']], [
                u'06', u'07', u'06', u'07', u'07', u'07', u'07', u'07', u'07',
                u'07', u'07', u'07', u'07', u'07', u'07', u'07', u'07', u'07',
                u'07', u'07', u'07', u'07', u'07'
            ])

    def test_writable(self):
        if getattr(settings, 'HAYSTACK_WHOOSH_STORAGE', 'file') == 'file':
            if not os.path.exists(settings.HAYSTACK_WHOOSH_PATH):
                os.makedirs(settings.HAYSTACK_WHOOSH_PATH)

            os.chmod(settings.HAYSTACK_WHOOSH_PATH, 0400)

            try:
                self.sb.setup()
                self.fail()
            except IOError:
                # Yay. We failed
                pass

            os.chmod(settings.HAYSTACK_WHOOSH_PATH, 0755)

    def test_slicing(self):
        self.sb.update(self.smmi, self.sample_objs)

        page_1 = self.sb.search(u'*', start_offset=0, end_offset=20)
        page_2 = self.sb.search(u'*', start_offset=20, end_offset=30)
        self.assertEqual(len(page_1['results']), 20)
        self.assertEqual([result.pk for result in page_1['results']],
                         [u'%s' % i for i in xrange(1, 21)])
        self.assertEqual(len(page_2['results']), 3)
        self.assertEqual([result.pk for result in page_2['results']],
                         [u'21', u'22', u'23'])

        # This used to throw an error.
        page_0 = self.sb.search(u'*', start_offset=0, end_offset=0)
        self.assertEqual(len(page_0['results']), 1)

    def test_scoring(self):
        self.sb.update(self.smmi, self.sample_objs)

        page_1 = self.sb.search(u'index', start_offset=0, end_offset=20)
        page_2 = self.sb.search(u'index', start_offset=20, end_offset=30)
        self.assertEqual(len(page_1['results']), 20)
        self.assertEqual(
            ["%0.2f" % result.score for result in page_1['results']], [
                '0.51', '0.51', '0.51', '0.51', '0.51', '0.51', '0.51', '0.51',
                '0.51', '0.40', '0.40', '0.40', '0.40', '0.40', '0.40', '0.40',
                '0.40', '0.40', '0.40', '0.40'
            ])
        self.assertEqual(len(page_2['results']), 3)
        self.assertEqual(
            ["%0.2f" % result.score for result in page_2['results']],
            ['0.40', '0.40', '0.40'])
class WhooshSearchBackendTestCase(TestCase):
    fixtures = ['bulk_data.json']
    
    def setUp(self):
        super(WhooshSearchBackendTestCase, self).setUp()
        
        # Stow.
        temp_path = os.path.join('tmp', 'test_whoosh_query')
        self.old_whoosh_path = getattr(settings, 'HAYSTACK_WHOOSH_PATH', temp_path)
        settings.HAYSTACK_WHOOSH_PATH = temp_path
        
        self.site = SearchSite()
        self.sb = SearchBackend(site=self.site)
        self.smmi = WhooshMockSearchIndex(MockModel, backend=self.sb)
        self.wmtmmi = WhooshMaintainTypeMockSearchIndex(MockModel, backend=self.sb)
        self.site.register(MockModel, WhooshMockSearchIndex)
        
        # With the models registered, you get the proper bits.
        import haystack
        
        # Stow.
        self.old_site = haystack.site
        haystack.site = self.site
        
        self.sb.setup()
        self.raw_whoosh = self.sb.index
        self.parser = QueryParser(self.sb.content_field_name, schema=self.sb.schema)
        self.sb.delete_index()
        
        self.sample_objs = MockModel.objects.all()
    
    def tearDown(self):
        if os.path.exists(settings.HAYSTACK_WHOOSH_PATH):
            shutil.rmtree(settings.HAYSTACK_WHOOSH_PATH)
        
        settings.HAYSTACK_WHOOSH_PATH = self.old_whoosh_path
        
        # Restore.
        import haystack
        haystack.site = self.old_site
        
        super(WhooshSearchBackendTestCase, self).tearDown()
    
    def whoosh_search(self, query):
        self.raw_whoosh = self.raw_whoosh.refresh()
        searcher = self.raw_whoosh.searcher()
        return searcher.search(self.parser.parse(query), limit=1000)
    
    def test_update(self):
        self.sb.update(self.smmi, self.sample_objs)
        
        # Check what Whoosh thinks is there.
        self.assertEqual(len(self.whoosh_search(u'*')), 23)
        self.assertEqual([doc.fields()['id'] for doc in self.whoosh_search(u'*')], [u'core.mockmodel.%s' % i for i in xrange(1, 24)])
    
    def test_remove(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.sb.index.doc_count(), 23)
        
        self.sb.remove(self.sample_objs[0])
        self.assertEqual(self.sb.index.doc_count(), 22)
    
    def test_clear(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.sb.index.doc_count(), 23)
        
        self.sb.clear()
        self.assertEqual(self.sb.index.doc_count(), 0)
        
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.sb.index.doc_count(), 23)
        
        self.sb.clear([AnotherMockModel])
        self.assertEqual(self.sb.index.doc_count(), 23)
        
        self.sb.clear([MockModel])
        self.assertEqual(self.sb.index.doc_count(), 0)
        
        self.sb.index.refresh()
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.sb.index.doc_count(), 23)
        
        self.sb.clear([AnotherMockModel, MockModel])
        self.assertEqual(self.raw_whoosh.doc_count(), 0)
    
    def test_search(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(len(self.whoosh_search(u'*')), 23)
        
        # No query string should always yield zero results.
        self.assertEqual(self.sb.search(u''), {'hits': 0, 'results': []})
        
        # A one letter query string gets nabbed by a stopwords filter. Should
        # always yield zero results.
        self.assertEqual(self.sb.search(u'a'), {'hits': 0, 'results': []})
        
        # Possible AttributeError?
        # self.assertEqual(self.sb.search(u'a b'), {'hits': 0, 'results': [], 'spelling_suggestion': '', 'facets': {}})
        
        self.assertEqual(self.sb.search(u'*')['hits'], 23)
        self.assertEqual([result.pk for result in self.sb.search(u'*')['results']], [u'%s' % i for i in xrange(1, 24)])
        
        self.assertEqual(self.sb.search(u'', highlight=True), {'hits': 0, 'results': []})
        self.assertEqual(self.sb.search(u'index*', highlight=True)['hits'], 23)
        # DRL_FIXME: Uncomment once highlighting works.
        # self.assertEqual([result.highlighted['text'][0] for result in self.sb.search('Index*', highlight=True)['results']], ['<em>Indexed</em>!\n3', '<em>Indexed</em>!\n2', '<em>Indexed</em>!\n1'])
        
        self.assertEqual(self.sb.search(u'Indx')['hits'], 0)
        self.assertEqual(self.sb.search(u'Indx')['spelling_suggestion'], u'index')
        
        self.assertEqual(self.sb.search(u'', facets=['name']), {'hits': 0, 'results': []})
        results = self.sb.search(u'Index*', facets=['name'])
        results = self.sb.search(u'index*', facets=['name'])
        self.assertEqual(results['hits'], 23)
        self.assertEqual(results['facets'], {})
        
        self.assertEqual(self.sb.search(u'', date_facets={'pub_date': {'start_date': date(2008, 2, 26), 'end_date': date(2008, 2, 26), 'gap': '/MONTH'}}), {'hits': 0, 'results': []})
        results = self.sb.search(u'Index*', date_facets={'pub_date': {'start_date': date(2008, 2, 26), 'end_date': date(2008, 2, 26), 'gap': '/MONTH'}})
        results = self.sb.search(u'index*', date_facets={'pub_date': {'start_date': date(2008, 2, 26), 'end_date': date(2008, 2, 26), 'gap': '/MONTH'}})
        self.assertEqual(results['hits'], 23)
        self.assertEqual(results['facets'], {})
        
        self.assertEqual(self.sb.search(u'', query_facets={'name': '[* TO e]'}), {'hits': 0, 'results': []})
        results = self.sb.search(u'Index*', query_facets={'name': '[* TO e]'})
        results = self.sb.search(u'index*', query_facets={'name': '[* TO e]'})
        self.assertEqual(results['hits'], 23)
        self.assertEqual(results['facets'], {})
        
        # self.assertEqual(self.sb.search('', narrow_queries=set(['name:daniel1'])), {'hits': 0, 'results': []})
        # results = self.sb.search('Index*', narrow_queries=set(['name:daniel1']))
        # self.assertEqual(results['hits'], 1)
        
        # Ensure that swapping the ``result_class`` works.
        self.assertTrue(isinstance(self.sb.search(u'Index*', result_class=MockSearchResult)['results'][0], MockSearchResult))
        
        # Check the use of ``limit_to_registered_models``.
        self.assertEqual(self.sb.search(u'', limit_to_registered_models=False), {'hits': 0, 'results': []})
        self.assertEqual(self.sb.search(u'*', limit_to_registered_models=False)['hits'], 23)
        self.assertEqual([result.pk for result in self.sb.search(u'*', limit_to_registered_models=False)['results']], [u'%s' % i for i in xrange(1, 24)])
        
        # Stow.
        old_limit_to_registered_models = getattr(settings, 'HAYSTACK_LIMIT_TO_REGISTERED_MODELS', True)
        settings.HAYSTACK_LIMIT_TO_REGISTERED_MODELS = False
        
        self.assertEqual(self.sb.search(u''), {'hits': 0, 'results': []})
        self.assertEqual(self.sb.search(u'*')['hits'], 23)
        self.assertEqual([result.pk for result in self.sb.search(u'*')['results']], [u'%s' % i for i in xrange(1, 24)])
        
        # Restore.
        settings.HAYSTACK_LIMIT_TO_REGISTERED_MODELS = old_limit_to_registered_models
    
    def test_more_like_this(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(len(self.whoosh_search(u'*')), 23)
        
        # Unsupported by Whoosh. Should see empty results.
        self.assertEqual(self.sb.more_like_this(self.sample_objs[0])['hits'], 0)
        
        # Make sure that swapping the ``result_class`` doesn't blow up.
        try:
            self.sb.search(u'index document', result_class=MockSearchResult)
        except:
            self.fail()
    
    def test_delete_index(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assert_(self.sb.index.doc_count() > 0)
        
        self.sb.delete_index()
        self.assertEqual(self.sb.index.doc_count(), 0)
    
    def test_order_by(self):
        self.sb.update(self.smmi, self.sample_objs)
        
        results = self.sb.search(u'*', sort_by=['pub_date'])
        self.assertEqual([result.pk for result in results['results']], [u'1', u'3', u'2', u'4', u'5', u'6', u'7', u'8', u'9', u'10', u'11', u'12', u'13', u'14', u'15', u'16', u'17', u'18', u'19', u'20', u'21', u'22', u'23'])
        
        results = self.sb.search(u'*', sort_by=['-pub_date'])
        self.assertEqual([result.pk for result in results['results']], [u'23', u'22', u'21', u'20', u'19', u'18', u'17', u'16', u'15', u'14', u'13', u'12', u'11', u'10', u'9', u'8', u'7', u'6', u'5', u'4', u'2', u'3', u'1'])
        
        results = self.sb.search(u'*', sort_by=['id'])
        self.assertEqual([result.pk for result in results['results']], [u'1', u'10', u'11', u'12', u'13', u'14', u'15', u'16', u'17', u'18', u'19', u'2', u'20', u'21', u'22', u'23', u'3', u'4', u'5', u'6', u'7', u'8', u'9'])
        
        results = self.sb.search(u'*', sort_by=['-id'])
        self.assertEqual([result.pk for result in results['results']], [u'9', u'8', u'7', u'6', u'5', u'4', u'3', u'23', u'22', u'21', u'20', u'2', u'19', u'18', u'17', u'16', u'15', u'14', u'13', u'12', u'11', u'10', u'1'])
    
    def test__from_python(self):
        self.assertEqual(self.sb._from_python('abc'), u'abc')
        self.assertEqual(self.sb._from_python(1), 1)
        self.assertEqual(self.sb._from_python(2653), 2653)
        self.assertEqual(self.sb._from_python(25.5), 25.5)
        self.assertEqual(self.sb._from_python([1, 2, 3]), u'1,2,3')
        self.assertEqual(self.sb._from_python({'a': 1, 'c': 3, 'b': 2}), u"{'a': 1, 'c': 3, 'b': 2}")
        self.assertEqual(self.sb._from_python(datetime(2009, 5, 9, 16, 14)), datetime(2009, 5, 9, 16, 14))
        self.assertEqual(self.sb._from_python(datetime(2009, 5, 9, 0, 0)), datetime(2009, 5, 9, 0, 0))
        self.assertEqual(self.sb._from_python(datetime(1899, 5, 18, 0, 0)), datetime(1899, 5, 18, 0, 0))
        self.assertEqual(self.sb._from_python(datetime(2009, 5, 18, 1, 16, 30, 250)), datetime(2009, 5, 18, 1, 16, 30, 250))
    
    def test__to_python(self):
        self.assertEqual(self.sb._to_python('abc'), 'abc')
        self.assertEqual(self.sb._to_python('1'), 1)
        self.assertEqual(self.sb._to_python('2653'), 2653)
        self.assertEqual(self.sb._to_python('25.5'), 25.5)
        self.assertEqual(self.sb._to_python('[1, 2, 3]'), [1, 2, 3])
        self.assertEqual(self.sb._to_python('{"a": 1, "b": 2, "c": 3}'), {'a': 1, 'c': 3, 'b': 2})
        self.assertEqual(self.sb._to_python('2009-05-09T16:14:00'), datetime(2009, 5, 9, 16, 14))
        self.assertEqual(self.sb._to_python('2009-05-09T00:00:00'), datetime(2009, 5, 9, 0, 0))
        self.assertEqual(self.sb._to_python(None), None)
    
    def test_range_queries(self):
        self.sb.update(self.smmi, self.sample_objs)
        
        self.assertEqual(len(self.whoosh_search(u'[d TO]')), 23)
        self.assertEqual(len(self.whoosh_search(u'name:[d TO]')), 23)
        self.assertEqual(len(self.whoosh_search(u'Ind* AND name:[d TO]')), 23)
        self.assertEqual(len(self.whoosh_search(u'Ind* AND name:[TO c]')), 0)
    
    def test_date_queries(self):
        self.sb.update(self.smmi, self.sample_objs)
        
        self.assertEqual(len(self.whoosh_search(u"pub_date:20090717T003000")), 1)
        self.assertEqual(len(self.whoosh_search(u"pub_date:20090717T000000")), 0)
        self.assertEqual(len(self.whoosh_search(u'Ind* AND pub_date:[TO 20090717T003000]')), 3)
    
    def test_escaped_characters_queries(self):
        self.sb.update(self.smmi, self.sample_objs)
        
        self.assertEqual(len(self.whoosh_search(u"Indexed\!")), 23)
        self.assertEqual(len(self.whoosh_search(u"http\:\/\/www\.example\.com")), 0)
    
    def test_build_schema(self):
        self.site.unregister(MockModel)
        self.site.register(MockModel, AllTypesWhooshMockSearchIndex)
        
        (content_field_name, schema) = self.sb.build_schema(self.site.all_searchfields())
        self.assertEqual(content_field_name, 'text')
        self.assertEqual(len(schema.names()), 8)
        self.assertEqual(schema.names(), ['django_ct', 'django_id', 'id', 'name', 'pub_date', 'seen_count', 'sites', 'text'])
        self.assert_(isinstance(schema._fields['text'], TEXT))
        self.assert_(isinstance(schema._fields['pub_date'], DATETIME))
        self.assert_(isinstance(schema._fields['seen_count'], NUMERIC))
        self.assert_(isinstance(schema._fields['sites'], KEYWORD))
    
    def test_verify_type(self):
        import haystack
        haystack.site.unregister(MockModel)
        haystack.site.register(MockModel, WhooshMaintainTypeMockSearchIndex)
        self.sb.setup()
        self.sb.update(self.wmtmmi, self.sample_objs)
        
        self.assertEqual(self.sb.search(u'*')['hits'], 23)
        self.assertEqual([result.month for result in self.sb.search(u'*')['results']], [u'06', u'07', u'06', u'07', u'07', u'07', u'07', u'07', u'07', u'07', u'07', u'07', u'07', u'07', u'07', u'07', u'07', u'07', u'07', u'07', u'07', u'07', u'07'])
    
    def test_writable(self):
        if getattr(settings, 'HAYSTACK_WHOOSH_STORAGE', 'file') == 'file':
            if not os.path.exists(settings.HAYSTACK_WHOOSH_PATH):
                os.makedirs(settings.HAYSTACK_WHOOSH_PATH)
            
            os.chmod(settings.HAYSTACK_WHOOSH_PATH, 0400)
            
            try:
                self.sb.setup()
                self.fail()
            except IOError:
                # Yay. We failed
                pass
            
            os.chmod(settings.HAYSTACK_WHOOSH_PATH, 0755)
    
    def test_slicing(self):
        self.sb.update(self.smmi, self.sample_objs)
        
        page_1 = self.sb.search(u'*', start_offset=0, end_offset=20)
        page_2 = self.sb.search(u'*', start_offset=20, end_offset=30)
        self.assertEqual(len(page_1['results']), 20)
        self.assertEqual([result.pk for result in page_1['results']], [u'%s' % i for i in xrange(1, 21)])
        self.assertEqual(len(page_2['results']), 3)
        self.assertEqual([result.pk for result in page_2['results']], [u'21', u'22', u'23'])
        
        # This used to throw an error.
        page_0 = self.sb.search(u'*', start_offset=0, end_offset=0)
        self.assertEqual(len(page_0['results']), 1)
    
    def test_scoring(self):
        self.sb.update(self.smmi, self.sample_objs)
        
        page_1 = self.sb.search(u'index', start_offset=0, end_offset=20)
        page_2 = self.sb.search(u'index', start_offset=20, end_offset=30)
        self.assertEqual(len(page_1['results']), 20)
        self.assertEqual(["%0.2f" % result.score for result in page_1['results']], ['0.51', '0.51', '0.51', '0.51', '0.51', '0.51', '0.51', '0.51', '0.51', '0.40', '0.40', '0.40', '0.40', '0.40', '0.40', '0.40', '0.40', '0.40', '0.40', '0.40'])
        self.assertEqual(len(page_2['results']), 3)
        self.assertEqual(["%0.2f" % result.score for result in page_2['results']], ['0.40', '0.40', '0.40'])
예제 #3
0
class SolrSearchBackendTestCase(TestCase):
    def setUp(self):
        super(SolrSearchBackendTestCase, self).setUp()

        # Stow.
        self.old_solr_url = getattr(settings, "HAYSTACK_SOLR_URL", "http://localhost:9001/solr/test_default")
        settings.HAYSTACK_SOLR_URL = "http://localhost:9001/solr/test_default"

        self.raw_solr = pysolr.Solr(settings.HAYSTACK_SOLR_URL)
        self.raw_solr.delete(q="*:*")

        self.site = SearchSite()
        self.sb = SearchBackend(site=self.site)
        self.smmi = SolrMockSearchIndex(MockModel, backend=self.sb)
        self.smtmmi = SolrMaintainTypeMockSearchIndex(MockModel, backend=self.sb)
        self.site.register(MockModel, SolrMockSearchIndex)

        # Stow.
        import haystack

        self.old_site = haystack.site
        haystack.site = self.site

        self.sample_objs = []

        for i in xrange(1, 4):
            mock = MockModel()
            mock.id = i
            mock.author = "daniel%s" % i
            mock.pub_date = datetime.date(2009, 2, 25) - datetime.timedelta(days=i)
            self.sample_objs.append(mock)

    def tearDown(self):
        import haystack

        haystack.site = self.old_site
        settings.HAYSTACK_SOLR_URL = self.old_solr_url
        super(SolrSearchBackendTestCase, self).tearDown()

    def test_update(self):
        self.sb.update(self.smmi, self.sample_objs)

        # Check what Solr thinks is there.
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)
        self.assertEqual(
            self.raw_solr.search("*:*").docs,
            [
                {
                    "django_id": "1",
                    "django_ct": "core.mockmodel",
                    "name": "daniel1",
                    "text": "Indexed!\n1",
                    "pub_date": "2009-02-24T00:00:00Z",
                    "id": "core.mockmodel.1",
                },
                {
                    "django_id": "2",
                    "django_ct": "core.mockmodel",
                    "name": "daniel2",
                    "text": "Indexed!\n2",
                    "pub_date": "2009-02-23T00:00:00Z",
                    "id": "core.mockmodel.2",
                },
                {
                    "django_id": "3",
                    "django_ct": "core.mockmodel",
                    "name": "daniel3",
                    "text": "Indexed!\n3",
                    "pub_date": "2009-02-22T00:00:00Z",
                    "id": "core.mockmodel.3",
                },
            ],
        )

    def test_remove(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)

        self.sb.remove(self.sample_objs[0])
        self.assertEqual(self.raw_solr.search("*:*").hits, 2)
        self.assertEqual(
            self.raw_solr.search("*:*").docs,
            [
                {
                    "django_id": "2",
                    "django_ct": "core.mockmodel",
                    "name": "daniel2",
                    "text": "Indexed!\n2",
                    "pub_date": "2009-02-23T00:00:00Z",
                    "id": "core.mockmodel.2",
                },
                {
                    "django_id": "3",
                    "django_ct": "core.mockmodel",
                    "name": "daniel3",
                    "text": "Indexed!\n3",
                    "pub_date": "2009-02-22T00:00:00Z",
                    "id": "core.mockmodel.3",
                },
            ],
        )

    def test_clear(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)

        self.sb.clear()
        self.assertEqual(self.raw_solr.search("*:*").hits, 0)

        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)

        self.sb.clear([AnotherMockModel])
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)

        self.sb.clear([MockModel])
        self.assertEqual(self.raw_solr.search("*:*").hits, 0)

        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)

        self.sb.clear([AnotherMockModel, MockModel])
        self.assertEqual(self.raw_solr.search("*:*").hits, 0)

    def test_search(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)

        self.assertEqual(self.sb.search(""), {"hits": 0, "results": []})
        self.assertEqual(self.sb.search("*:*")["hits"], 3)
        self.assertEqual([result.pk for result in self.sb.search("*:*")["results"]], ["1", "2", "3"])

        self.assertEqual(self.sb.search("", highlight=True), {"hits": 0, "results": []})
        self.assertEqual(self.sb.search("Index", highlight=True)["hits"], 3)
        self.assertEqual(
            [result.highlighted["text"][0] for result in self.sb.search("Index", highlight=True)["results"]],
            ["<em>Indexed</em>!\n1", "<em>Indexed</em>!\n2", "<em>Indexed</em>!\n3"],
        )

        self.assertEqual(self.sb.search("Indx")["hits"], 0)
        self.assertEqual(self.sb.search("Indx")["spelling_suggestion"], "index")
        self.assertEqual(self.sb.search("Indx", spelling_query="indexy")["spelling_suggestion"], "index")

        self.assertEqual(self.sb.search("", facets=["name"]), {"hits": 0, "results": []})
        results = self.sb.search("Index", facets=["name"])
        self.assertEqual(results["hits"], 3)
        self.assertEqual(results["facets"]["fields"]["name"], [("daniel1", 1), ("daniel2", 1), ("daniel3", 1)])

        self.assertEqual(
            self.sb.search(
                "",
                date_facets={
                    "pub_date": {
                        "start_date": datetime.date(2008, 2, 26),
                        "end_date": datetime.date(2008, 3, 26),
                        "gap_by": "month",
                        "gap_amount": 1,
                    }
                },
            ),
            {"hits": 0, "results": []},
        )
        results = self.sb.search(
            "Index",
            date_facets={
                "pub_date": {
                    "start_date": datetime.date(2008, 2, 26),
                    "end_date": datetime.date(2008, 3, 26),
                    "gap_by": "month",
                    "gap_amount": 1,
                }
            },
        )
        self.assertEqual(results["hits"], 3)
        # DRL_TODO: Correct output but no counts. Another case of needing better test data?
        # self.assertEqual(results['facets']['dates']['pub_date'], {'end': '2008-02-26T00:00:00Z', 'gap': '/MONTH'})

        self.assertEqual(self.sb.search("", query_facets={"name": "[* TO e]"}), {"hits": 0, "results": []})
        results = self.sb.search("Index", query_facets={"name": "[* TO e]"})
        self.assertEqual(results["hits"], 3)
        self.assertEqual(results["facets"]["queries"], {"name:[* TO e]": 3})

        self.assertEqual(self.sb.search("", narrow_queries=set(["name:daniel1"])), {"hits": 0, "results": []})
        results = self.sb.search("Index", narrow_queries=set(["name:daniel1"]))
        self.assertEqual(results["hits"], 1)

    def test_more_like_this(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)

        # A functional MLT example with enough data to work is below. Rely on
        # this to ensure the API is correct enough.
        self.assertEqual(self.sb.more_like_this(self.sample_objs[0])["hits"], 0)
        self.assertEqual([result.pk for result in self.sb.more_like_this(self.sample_objs[0])["results"]], [])

    def test_build_schema(self):
        (content_field_name, fields) = self.sb.build_schema(self.site.all_searchfields())
        self.assertEqual(content_field_name, "text")
        self.assertEqual(len(fields), 3)
        self.assertEqual(
            fields,
            [
                {"indexed": "true", "type": "text", "field_name": "text", "multi_valued": "false"},
                {"indexed": "true", "type": "date", "field_name": "pub_date", "multi_valued": "false"},
                {"indexed": "true", "type": "text", "field_name": "name", "multi_valued": "false"},
            ],
        )

    def test_verify_type(self):
        import haystack

        haystack.site.unregister(MockModel)
        haystack.site.register(MockModel, SolrMaintainTypeMockSearchIndex)
        self.sb.update(self.smtmmi, self.sample_objs)

        self.assertEqual(self.sb.search("*:*")["hits"], 3)
        self.assertEqual([result.month for result in self.sb.search("*:*")["results"]], [u"02", u"02", u"02"])
예제 #4
0
class SearchSiteTestCase(TestCase):
    def setUp(self):
        super(SearchSiteTestCase, self).setUp()
        self.site = SearchSite()

    def test_register(self):
        self.assertRaises(AttributeError, self.site.register, MockNotAModel)

        self.site.register(MockModel)
        self.assertEqual(len(self.site._registry), 1)
        self.assert_(MockModel in self.site._registry)

        self.assertRaises(AlreadyRegistered, self.site.register, MockModel)

    def test_unregister(self):
        self.assertRaises(NotRegistered, self.site.unregister, MockModel)

        # Depends on proper function of register.
        self.site.register(MockModel)
        self.site.unregister(MockModel)
        self.assertEqual(len(self.site._registry), 0)
        self.assertFalse(MockModel in self.site._registry)

    def test_get_index(self):
        self.assertRaises(NotRegistered, self.site.get_index, MockModel)

        self.site.register(MockModel)
        self.assert_(isinstance(self.site.get_index(MockModel), BasicSearchIndex))

    def test_get_indexes(self):
        self.assertEqual(self.site.get_indexes(), {})

        self.site.register(MockModel)
        indexes = self.site.get_indexes()
        self.assert_(isinstance(indexes, dict))
        self.assertEqual(len(indexes), 1)
        self.assert_(MockModel in indexes)

    def test_get_indexed_models(self):
        self.assertEqual(self.site.get_indexed_models(), [])

        self.site.register(MockModel)
        indexed_models = self.site.get_indexed_models()
        self.assertEqual(len(indexed_models), 1)
        self.assert_(MockModel in indexed_models)

    def test_all_searchfields(self):
        self.site.register(MockModel)
        fields = self.site.all_searchfields()
        self.assertEqual(len(fields), 1)
        self.assert_("text" in fields)
        self.assert_(isinstance(fields["text"], CharField))
        self.assertEqual(fields["text"].document, True)
        self.assertEqual(fields["text"].use_template, True)

        self.site.register(AnotherMockModel)
        fields = self.site.all_searchfields()
        self.assertEqual(len(fields), 1)
        self.assert_("text" in fields)
        self.assert_(isinstance(fields["text"], CharField))
        self.assertEqual(fields["text"].document, True)
        self.assertEqual(fields["text"].use_template, True)

        self.site.unregister(AnotherMockModel)
        self.site.register(AnotherMockModel, InvalidSeachIndex)
        self.assertRaises(SearchFieldError, self.site.all_searchfields)

    def test_update_object(self):
        self.site.register(MockModel, FakeSearchIndex)

        mock = MockModel()
        mock.pk = 20
        mock.user = "******" % mock.id
        mock.pub_date = datetime.datetime(2009, 1, 31, 4, 19, 0)

        self.assertEqual(self.site.update_object(mock), True)

    def test_remove_object(self):
        self.site.register(MockModel, FakeSearchIndex)

        mock = MockModel()
        mock.pk = 20

        self.assertEqual(self.site.remove_object(mock), True)
예제 #5
0
class SearchSiteTestCase(TestCase):
    def setUp(self):
        super(SearchSiteTestCase, self).setUp()
        self.site = SearchSite()

    def test_register(self):
        self.assertRaises(AttributeError, self.site.register, MockNotAModel)

        self.site.register(MockModel)
        self.assertEqual(len(self.site._registry), 1)
        self.assert_(MockModel in self.site._registry)

        self.assertRaises(AlreadyRegistered, self.site.register, MockModel)

    def test_unregister(self):
        self.assertRaises(NotRegistered, self.site.unregister, MockModel)

        # Depends on proper function of register.
        self.site.register(MockModel)
        self.site.unregister(MockModel)
        self.assertEqual(len(self.site._registry), 0)
        self.assertFalse(MockModel in self.site._registry)

    def test_get_index(self):
        self.assertRaises(NotRegistered, self.site.get_index, MockModel)

        self.site.register(MockModel)
        self.assert_(
            isinstance(self.site.get_index(MockModel), BasicSearchIndex))

    def test_get_indexes(self):
        self.assertEqual(self.site.get_indexes(), {})

        self.site.register(MockModel)
        indexes = self.site.get_indexes()
        self.assert_(isinstance(indexes, dict))
        self.assertEqual(len(indexes), 1)
        self.assert_(MockModel in indexes)

    def test_get_indexed_models(self):
        self.assertEqual(self.site.get_indexed_models(), [])

        self.site.register(MockModel)
        indexed_models = self.site.get_indexed_models()
        self.assertEqual(len(indexed_models), 1)
        self.assert_(MockModel in indexed_models)

    def test_all_searchfields(self):
        self.site.register(MockModel)
        fields = self.site.all_searchfields()
        self.assertEqual(len(fields), 1)
        self.assert_('text' in fields)
        self.assert_(isinstance(fields['text'], CharField))
        self.assertEqual(fields['text'].document, True)
        self.assertEqual(fields['text'].use_template, True)

        self.site.register(AnotherMockModel)
        fields = self.site.all_searchfields()
        self.assertEqual(len(fields), 1)
        self.assert_('text' in fields)
        self.assert_(isinstance(fields['text'], CharField))
        self.assertEqual(fields['text'].document, True)
        self.assertEqual(fields['text'].use_template, True)

        self.site.unregister(AnotherMockModel)
        self.site.register(AnotherMockModel, AlternateValidSearchIndex)
        fields = self.site.all_searchfields()
        self.assertEqual(len(fields), 3)
        self.assertEqual(sorted(fields.keys()), ['author', 'text', 'title'])
        self.assert_('text' in fields)
        self.assert_(isinstance(fields['text'], CharField))
        self.assertEqual(fields['text'].document, True)
        self.assertEqual(fields['text'].use_template, True)
        self.assert_('title' in fields)
        self.assert_(isinstance(fields['title'], CharField))
        self.assertEqual(fields['title'].document, False)
        self.assertEqual(fields['title'].use_template, False)
        self.assertEqual(fields['title'].faceted, True)
        self.assertEqual(fields['title'].indexed, True)
        self.assert_('author' in fields)
        self.assert_(isinstance(fields['author'], CharField))
        self.assertEqual(fields['author'].document, False)
        self.assertEqual(fields['author'].use_template, False)
        self.assertEqual(fields['author'].faceted, True)
        self.assertEqual(fields['author'].index_fieldname, 'author')

        self.site.unregister(MockModel)
        self.site.register(MockModel, ValidSearchIndex)
        fields = self.site.all_searchfields()
        self.assertEqual(len(fields), 4)
        self.assertEqual(sorted(fields.keys()),
                         ['author', 'name', 'text', 'title'])
        self.assert_('text' in fields)
        self.assert_(isinstance(fields['text'], CharField))
        self.assertEqual(fields['text'].document, True)
        self.assertEqual(fields['text'].use_template, False)
        self.assert_('title' in fields)
        self.assert_(isinstance(fields['title'], CharField))
        self.assertEqual(fields['title'].document, False)
        self.assertEqual(fields['title'].use_template, False)
        self.assertEqual(fields['title'].faceted, True)
        self.assertEqual(fields['title'].indexed, True)
        self.assert_('author' in fields)
        self.assert_(isinstance(fields['author'], CharField))
        self.assertEqual(fields['author'].document, False)
        self.assertEqual(fields['author'].use_template, False)
        self.assertEqual(fields['author'].faceted, True)
        self.assertEqual(fields['author'].index_fieldname, 'author')
        self.assertEqual(fields['name'].document, False)
        self.assertEqual(fields['name'].use_template, False)
        self.assertEqual(fields['name'].faceted, False)
        self.assertEqual(fields['name'].index_fieldname, 'name')

        self.site.unregister(AnotherMockModel)
        self.site.register(AnotherMockModel, InvalidSearchIndex)
        self.assertRaises(SearchFieldError, self.site.all_searchfields)

    def test_get_index_fieldname(self):
        self.assertEqual(self.site._field_mapping, None)

        self.site.register(MockModel, ValidSearchIndex)
        self.site.register(AnotherMockModel)
        field = self.site.get_index_fieldname('text')
        self.assertEqual(self.site._field_mapping, {
            'text': 'text',
            'title': 'title',
            'author': 'name'
        })
        self.assertEqual(self.site.get_index_fieldname('text'), 'text')
        self.assertEqual(self.site.get_index_fieldname('author'), 'name')
        self.assertEqual(self.site.get_index_fieldname('title'), 'title')

        # Reset the internal state to test the invalid case.
        self.site._field_mapping = None
        self.assertEqual(self.site._field_mapping, None)

        self.site.unregister(AnotherMockModel)
        self.site.register(AnotherMockModel, AlternateValidSearchIndex)
        self.assertRaises(SearchFieldError, self.site.get_index_fieldname,
                          'text')

    def test_update_object(self):
        self.site.register(MockModel, FakeSearchIndex)

        mock = MockModel()
        mock.pk = 20
        mock.user = '******' % mock.id
        mock.pub_date = datetime.datetime(2009, 1, 31, 4, 19, 0)

        self.assertEqual(self.site.update_object(mock), True)

    def test_remove_object(self):
        self.site.register(MockModel, FakeSearchIndex)

        mock = MockModel()
        mock.pk = 20

        self.assertEqual(self.site.remove_object(mock), True)
예제 #6
0
class SolrSearchBackendTestCase(TestCase):
    def setUp(self):
        super(SolrSearchBackendTestCase, self).setUp()
        
        # Wipe it clean.
        self.raw_solr = pysolr.Solr(settings.HAYSTACK_SOLR_URL)
        clear_solr_index()
        
        self.site = SearchSite()
        self.sb = SearchBackend(site=self.site)
        self.smmi = SolrMockSearchIndex(MockModel, backend=self.sb)
        self.smtmmi = SolrMaintainTypeMockSearchIndex(MockModel, backend=self.sb)
        self.site.register(MockModel, SolrMockSearchIndex)
        
        # Stow.
        import haystack
        self.old_site = haystack.site
        haystack.site = self.site
        
        self.sample_objs = []
        
        for i in xrange(1, 4):
            mock = MockModel()
            mock.id = i
            mock.author = 'daniel%s' % i
            mock.pub_date = datetime.date(2009, 2, 25) - datetime.timedelta(days=i)
            self.sample_objs.append(mock)
    
    def tearDown(self):
        import haystack
        haystack.site = self.old_site
        super(SolrSearchBackendTestCase, self).tearDown()
    
    def test_update(self):
        self.sb.update(self.smmi, self.sample_objs)
        
        # Check what Solr thinks is there.
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)
        self.assertEqual(self.raw_solr.search('*:*').docs, [
            {
                'django_id': '1',
                'django_ct': 'core.mockmodel',
                'name': 'daniel1',
                'name_exact': 'daniel1',
                'text': 'Indexed!\n1',
                'pub_date': '2009-02-24T00:00:00Z',
                'id': 'core.mockmodel.1'
            },
            {
                'django_id': '2',
                'django_ct': 'core.mockmodel',
                'name': 'daniel2',
                'name_exact': 'daniel2',
                'text': 'Indexed!\n2',
                'pub_date': '2009-02-23T00:00:00Z',
                'id': 'core.mockmodel.2'
            },
            {
                'django_id': '3',
                'django_ct': 'core.mockmodel',
                'name': 'daniel3',
                'name_exact': 'daniel3',
                'text': 'Indexed!\n3',
                'pub_date': '2009-02-22T00:00:00Z',
                'id': 'core.mockmodel.3'
            }
        ])
    
    def test_remove(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)
        
        self.sb.remove(self.sample_objs[0])
        self.assertEqual(self.raw_solr.search('*:*').hits, 2)
        self.assertEqual(self.raw_solr.search('*:*').docs, [
            {
                'django_id': '2',
                'django_ct': 'core.mockmodel',
                'name': 'daniel2',
                'name_exact': 'daniel2',
                'text': 'Indexed!\n2',
                'pub_date': '2009-02-23T00:00:00Z',
                'id': 'core.mockmodel.2'
            },
            {
                'django_id': '3',
                'django_ct': 'core.mockmodel',
                'name': 'daniel3',
                'name_exact': 'daniel3',
                'text': 'Indexed!\n3',
                'pub_date': '2009-02-22T00:00:00Z',
                'id': 'core.mockmodel.3'
            }
        ])
    
    def test_clear(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)
        
        self.sb.clear()
        self.assertEqual(self.raw_solr.search('*:*').hits, 0)
        
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)
        
        self.sb.clear([AnotherMockModel])
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)
        
        self.sb.clear([MockModel])
        self.assertEqual(self.raw_solr.search('*:*').hits, 0)
        
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)
        
        self.sb.clear([AnotherMockModel, MockModel])
        self.assertEqual(self.raw_solr.search('*:*').hits, 0)
    
    def test_search(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)
        
        self.assertEqual(self.sb.search(''), {'hits': 0, 'results': []})
        self.assertEqual(self.sb.search('*:*')['hits'], 3)
        self.assertEqual([result.pk for result in self.sb.search('*:*')['results']], ['1', '2', '3'])
        
        self.assertEqual(self.sb.search('', highlight=True), {'hits': 0, 'results': []})
        self.assertEqual(self.sb.search('Index', highlight=True)['hits'], 3)
        self.assertEqual([result.highlighted['text'][0] for result in self.sb.search('Index', highlight=True)['results']], ['<em>Indexed</em>!\n1', '<em>Indexed</em>!\n2', '<em>Indexed</em>!\n3'])
        
        self.assertEqual(self.sb.search('Indx')['hits'], 0)
        self.assertEqual(self.sb.search('Indx')['spelling_suggestion'], 'index')
        self.assertEqual(self.sb.search('Indx', spelling_query='indexy')['spelling_suggestion'], 'index')
        
        self.assertEqual(self.sb.search('', facets=['name']), {'hits': 0, 'results': []})
        results = self.sb.search('Index', facets=['name'])
        self.assertEqual(results['hits'], 3)
        self.assertEqual(results['facets']['fields']['name'], [('daniel1', 1), ('daniel2', 1), ('daniel3', 1)])
        
        self.assertEqual(self.sb.search('', date_facets={'pub_date': {'start_date': datetime.date(2008, 2, 26), 'end_date': datetime.date(2008, 3, 26), 'gap_by': 'month', 'gap_amount': 1}}), {'hits': 0, 'results': []})
        results = self.sb.search('Index', date_facets={'pub_date': {'start_date': datetime.date(2008, 2, 26), 'end_date': datetime.date(2008, 3, 26), 'gap_by': 'month', 'gap_amount': 1}})
        self.assertEqual(results['hits'], 3)
        # DRL_TODO: Correct output but no counts. Another case of needing better test data?
        # self.assertEqual(results['facets']['dates']['pub_date'], {'end': '2008-02-26T00:00:00Z', 'gap': '/MONTH'})
        
        self.assertEqual(self.sb.search('', query_facets=[('name', '[* TO e]')]), {'hits': 0, 'results': []})
        results = self.sb.search('Index', query_facets=[('name', '[* TO e]')])
        self.assertEqual(results['hits'], 3)
        self.assertEqual(results['facets']['queries'], {'name:[* TO e]': 3})
        
        self.assertEqual(self.sb.search('', narrow_queries=set(['name:daniel1'])), {'hits': 0, 'results': []})
        results = self.sb.search('Index', narrow_queries=set(['name:daniel1']))
        self.assertEqual(results['hits'], 1)
        
        # Check the use of ``limit_to_registered_models``.
        self.assertEqual(self.sb.search('', limit_to_registered_models=False), {'hits': 0, 'results': []})
        self.assertEqual(self.sb.search('*:*', limit_to_registered_models=False)['hits'], 3)
        self.assertEqual([result.pk for result in self.sb.search('*:*', limit_to_registered_models=False)['results']], ['1', '2', '3'])
        
        # Stow.
        old_limit_to_registered_models = getattr(settings, 'HAYSTACK_LIMIT_TO_REGISTERED_MODELS', True)
        settings.HAYSTACK_LIMIT_TO_REGISTERED_MODELS = False
        
        self.assertEqual(self.sb.search(''), {'hits': 0, 'results': []})
        self.assertEqual(self.sb.search('*:*')['hits'], 3)
        self.assertEqual([result.pk for result in self.sb.search('*:*')['results']], ['1', '2', '3'])
        
        # Restore.
        settings.HAYSTACK_LIMIT_TO_REGISTERED_MODELS = old_limit_to_registered_models
    
    def test_more_like_this(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)
        
        # A functional MLT example with enough data to work is below. Rely on
        # this to ensure the API is correct enough.
        self.assertEqual(self.sb.more_like_this(self.sample_objs[0])['hits'], 0)
        self.assertEqual([result.pk for result in self.sb.more_like_this(self.sample_objs[0])['results']], [])
    
    def test_build_schema(self):
        (content_field_name, fields) = self.sb.build_schema(self.site.all_searchfields())
        self.assertEqual(content_field_name, 'text')
        self.assertEqual(len(fields), 4)
        self.assertEqual(fields, [
            {
                'indexed': 'true',
                'type': 'text',
                'stored': 'true',
                'field_name': 'text',
                'multi_valued': 'false'
            },
            {
                'indexed': 'true',
                'type': 'date',
                'stored': 'true',
                'field_name': 'pub_date',
                'multi_valued': 'false'
            },
            {
                'indexed': 'true',
                'type': 'text',
                'stored': 'true',
                'field_name': 'name',
                'multi_valued': 'false'
            },
            {
                'indexed': 'true',
                'field_name': 'name_exact',
                'stored': 'true',
                'type': 'string',
                'multi_valued': 'false'
            }
        ])
        
        self.site.unregister(MockModel)
        self.site.register(MockModel, SolrComplexFacetsMockSearchIndex)
        (content_field_name, fields) = self.sb.build_schema(self.site.all_searchfields())
        self.assertEqual(content_field_name, 'text')
        self.assertEqual(len(fields), 15)
        self.assertEqual(fields, [
            {
                'indexed': 'true',
                'type': 'text',
                'stored': 'true',
                'field_name': 'name',
                'multi_valued': 'false'
            },
            {
                'indexed': 'true',
                'type': 'boolean',
                'stored': 'true',
                'field_name': 'is_active_exact',
                'multi_valued': 'false'
            },
            {
                'indexed': 'true',
                'type': 'date',
                'stored': 'true',
                'field_name': 'created',
                'multi_valued': 'false'
            },
            {
                'indexed': 'true',
                'type': 'slong',
                'stored': 'true',
                'field_name': 'post_count',
                'multi_valued': 'false'
            },
            {
                'indexed': 'true',
                'type': 'date',
                'stored': 'true',
                'field_name': 'created_exact',
                'multi_valued': 'false'
            },
            {
                'indexed': 'true',
                'type': 'string',
                'stored': 'true',
                'field_name': 'sites_exact',
                'multi_valued': 'true'
            },
            {
                'indexed': 'true',
                'type': 'boolean',
                'stored': 'true',
                'field_name': 'is_active',
                'multi_valued': 'false'
            },
            {
                'indexed': 'true',
                'type': 'text',
                'stored': 'true',
                'field_name': 'sites',
                'multi_valued': 'true'
            },
            {
                'indexed': 'true',
                'type': 'slong',
                'stored': 'true',
                'field_name': 'post_count_i',
                'multi_valued': 'false'
            },
            {
                'indexed': 'true',
                'type': 'sfloat',
                'stored': 'true',
                'field_name': 'average_rating',
                'multi_valued': 'false'
            },
            {
                'indexed': 'true',
                'type': 'text',
                'stored': 'true',
                'field_name': 'text',
                'multi_valued': 'false'
            },
            {
                'indexed': 'true',
                'type': 'date',
                'stored': 'true',
                'field_name': 'pub_date_exact',
                'multi_valued': 'false'
            },
            {
                'indexed': 'true',
                'type': 'string',
                'stored': 'true',
                'field_name': 'name_exact',
                'multi_valued': 'false'
            },
            {
                'indexed': 'true',
                'type': 'date',
                'stored': 'true',
                'field_name': 'pub_date',
                'multi_valued': 'false'
            },
            {
                'indexed': 'true',
                'type': 'sfloat',
                'stored': 'true',
                'field_name': 'average_rating_exact',
                'multi_valued': 'false'
            }
        ])
    
    def test_verify_type(self):
        import haystack
        haystack.site.unregister(MockModel)
        haystack.site.register(MockModel, SolrMaintainTypeMockSearchIndex)
        self.sb.update(self.smtmmi, self.sample_objs)
        
        self.assertEqual(self.sb.search('*:*')['hits'], 3)
        self.assertEqual([result.month for result in self.sb.search('*:*')['results']], [u'02', u'02', u'02'])
예제 #7
0
class SearchSiteTestCase(TestCase):
    def setUp(self):
        super(SearchSiteTestCase, self).setUp()
        self.site = SearchSite()
    
    def test_register(self):
        self.assertRaises(AttributeError, self.site.register, MockNotAModel)
        
        self.site.register(MockModel)
        self.assertEqual(len(self.site._registry), 1)
        self.assert_(MockModel in self.site._registry)
        
        self.assertRaises(AlreadyRegistered, self.site.register, MockModel)
    
    def test_unregister(self):
        self.assertRaises(NotRegistered, self.site.unregister, MockModel)
        
        # Depends on proper function of register.
        self.site.register(MockModel)
        self.site.unregister(MockModel)
        self.assertEqual(len(self.site._registry), 0)
        self.assertFalse(MockModel in self.site._registry)
    
    def test_get_index(self):
        self.assertRaises(NotRegistered, self.site.get_index, MockModel)
        
        self.site.register(MockModel)
        self.assert_(isinstance(self.site.get_index(MockModel), BasicSearchIndex))
    
    def test_get_indexes(self):
        self.assertEqual(self.site.get_indexes(), {})
        
        self.site.register(MockModel)
        indexes = self.site.get_indexes()
        self.assert_(isinstance(indexes, dict))
        self.assertEqual(len(indexes), 1)
        self.assert_(MockModel in indexes)
    
    def test_get_indexed_models(self):
        self.assertEqual(self.site.get_indexed_models(), [])
        
        self.site.register(MockModel)
        indexed_models = self.site.get_indexed_models()
        self.assertEqual(len(indexed_models), 1)
        self.assert_(MockModel in indexed_models)
    
    def test_all_searchfields(self):
        self.site.register(MockModel)
        fields = self.site.all_searchfields()
        self.assertEqual(len(fields), 1)
        self.assert_('text' in fields)
        self.assert_(isinstance(fields['text'], CharField))
        self.assertEqual(fields['text'].document, True)
        self.assertEqual(fields['text'].use_template, True)
        
        self.site.register(AnotherMockModel)
        fields = self.site.all_searchfields()
        self.assertEqual(len(fields), 1)
        self.assert_('text' in fields)
        self.assert_(isinstance(fields['text'], CharField))
        self.assertEqual(fields['text'].document, True)
        self.assertEqual(fields['text'].use_template, True)
        
        self.site.unregister(AnotherMockModel)
        self.site.register(AnotherMockModel, AlternateValidSearchIndex)
        fields = self.site.all_searchfields()
        self.assertEqual(len(fields), 5)
        self.assertEqual(sorted(fields.keys()), ['author', 'author_exact', 'text', 'title', 'title_exact'])
        self.assert_('text' in fields)
        self.assert_(isinstance(fields['text'], CharField))
        self.assertEqual(fields['text'].document, True)
        self.assertEqual(fields['text'].use_template, True)
        self.assert_('title' in fields)
        self.assert_(isinstance(fields['title'], CharField))
        self.assertEqual(fields['title'].document, False)
        self.assertEqual(fields['title'].use_template, False)
        self.assertEqual(fields['title'].faceted, True)
        self.assertEqual(fields['title'].indexed, True)
        self.assert_('author' in fields)
        self.assert_(isinstance(fields['author'], CharField))
        self.assertEqual(fields['author'].document, False)
        self.assertEqual(fields['author'].use_template, False)
        self.assertEqual(fields['author'].faceted, True)
        self.assertEqual(fields['author'].stored, True)
        self.assertEqual(fields['author'].index_fieldname, 'author')
        
        self.site.unregister(MockModel)
        self.site.register(MockModel, ValidSearchIndex)
        fields = self.site.all_searchfields()
        self.assertEqual(len(fields), 6)
        self.assertEqual(sorted(fields.keys()), ['author', 'author_exact', 'name', 'text', 'title', 'title_exact'])
        self.assert_('text' in fields)
        self.assert_(isinstance(fields['text'], CharField))
        self.assertEqual(fields['text'].document, True)
        self.assertEqual(fields['text'].use_template, False)
        self.assert_('title' in fields)
        self.assert_(isinstance(fields['title'], CharField))
        self.assertEqual(fields['title'].document, False)
        self.assertEqual(fields['title'].use_template, False)
        self.assertEqual(fields['title'].faceted, True)
        self.assertEqual(fields['title'].indexed, True)
        self.assert_('author' in fields)
        self.assert_(isinstance(fields['author'], CharField))
        self.assertEqual(fields['author'].document, False)
        self.assertEqual(fields['author'].use_template, False)
        self.assertEqual(fields['author'].faceted, True)
        self.assertEqual(fields['author'].index_fieldname, 'author')
        self.assertEqual(fields['name'].document, False)
        self.assertEqual(fields['name'].use_template, False)
        self.assertEqual(fields['name'].faceted, False)
        self.assertEqual(fields['name'].index_fieldname, 'name')
        
        self.site.unregister(AnotherMockModel)
        self.site.register(AnotherMockModel, MultiValueValidSearchIndex)
        fields = self.site.all_searchfields()
        self.assertEqual(len(fields), 4)
        self.assertEqual(sorted(fields.keys()), ['author', 'name', 'text', 'title'])
        self.assert_('text' in fields)
        self.assert_(isinstance(fields['text'], CharField))
        self.assertEqual(fields['text'].document, True)
        self.assertEqual(fields['text'].use_template, False)
        self.assert_('title' in fields)
        self.assert_(isinstance(fields['title'], CharField))
        self.assertEqual(fields['title'].document, False)
        self.assertEqual(fields['title'].use_template, False)
        self.assertEqual(fields['title'].faceted, False)
        self.assertEqual(fields['title'].indexed, False)
        self.assert_('author' in fields)
        self.assert_(isinstance(fields['author'], MultiValueField))
        self.assertEqual(fields['author'].document, False)
        self.assertEqual(fields['author'].use_template, False)
        self.assertEqual(fields['author'].stored, False)
        self.assertEqual(fields['author'].faceted, False)
        self.assertEqual(fields['author'].index_fieldname, 'author')
        
        self.site.unregister(AnotherMockModel)
        self.site.register(AnotherMockModel, InvalidSearchIndex)
        self.assertRaises(SearchFieldError, self.site.all_searchfields)
    
    def test_get_index_fieldname(self):
        self.assertEqual(self.site._cached_field_mapping, None)
        
        self.site.register(MockModel, ValidSearchIndex)
        self.site.register(AnotherMockModel)
        self.site.get_index_fieldname('text')
        self.assertEqual(self.site._cached_field_mapping, {
            'text': {'index_fieldname': 'text', 'facet_fieldname': None},
            'title': {'index_fieldname': 'title', 'facet_fieldname': None},
            'author': {'index_fieldname': 'name', 'facet_fieldname': None},
            })
        self.assertEqual(self.site.get_index_fieldname('text'), 'text')
        self.assertEqual(self.site.get_index_fieldname('author'), 'name')
        self.assertEqual(self.site.get_index_fieldname('title'), 'title')
        
        # Reset the internal state to test the invalid case.
        self.site._cached_field_mapping = None
        self.assertEqual(self.site._cached_field_mapping, None)
        
        self.site.unregister(AnotherMockModel)
        self.site.register(AnotherMockModel, AlternateValidSearchIndex)
        self.assertRaises(SearchFieldError, self.site.get_index_fieldname, 'text')

    def test_basic_get_facet_field_name(self):
        self.assertEqual(self.site._cached_field_mapping, None)
        
        self.site.register(MockModel, AlternateValidSearchIndex)
        self.site.register(AnotherMockModel)
        self.site.get_facet_field_name('text')
        self.assertEqual(self.site._cached_field_mapping, {
            'author': {'facet_fieldname': None, 'index_fieldname': 'author'},
            'author_exact': {'facet_fieldname': 'author',
            'index_fieldname': 'author_exact'},
            'text': {'facet_fieldname': None, 'index_fieldname': 'text'},
            'title': {'facet_fieldname': None, 'index_fieldname': 'title'},
            'title_exact': {'facet_fieldname': 'title', 'index_fieldname': 'title_exact'},
        })
        self.assertEqual(self.site.get_index_fieldname('text'), 'text')
        self.assertEqual(self.site.get_index_fieldname('author'), 'author')
        self.assertEqual(self.site.get_index_fieldname('title'), 'title')

        self.assertEqual(self.site.get_facet_field_name('text'), 'text')
        self.assertEqual(self.site.get_facet_field_name('author'), 'author')
        self.assertEqual(self.site.get_facet_field_name('title'), 'title')

    def test_more_advanced_get_facet_field_name(self):
        self.assertEqual(self.site._cached_field_mapping, None)

        self.site.register(MockModel, ExplicitFacetSearchIndex)
        self.site.register(AnotherMockModel)

        self.site.get_facet_field_name('text')
        self.assertEqual(self.site._cached_field_mapping, {
            'author': {'facet_fieldname': None, 'index_fieldname': 'author'},
            'author_exact': {'facet_fieldname': 'author', 'index_fieldname': 'author_exact'},
            'bare_facet': {'facet_fieldname': 'bare_facet', 'index_fieldname': 'bare_facet'},
            'text': {'facet_fieldname': None, 'index_fieldname': 'text'},
            'title': {'facet_fieldname': None, 'index_fieldname': 'title'},
            'title_facet': {'facet_fieldname': 'title', 'index_fieldname': 'title_facet'},
        })
        self.assertEqual(self.site.get_facet_field_name('title'), 'title')

        self.assertEqual(self.site.get_facet_field_name('title'), 'title')
        self.assertEqual(self.site.get_facet_field_name('bare_facet'), 'bare_facet')

    
    def test_update_object(self):
        self.site.register(MockModel, FakeSearchIndex)
        
        mock = MockModel()
        mock.pk = 20
        mock.user = '******' % mock.id
        mock.pub_date = datetime.datetime(2009, 1, 31, 4, 19, 0)
        
        self.assertEqual(self.site.update_object(mock), True)
    
    def test_remove_object(self):
        self.site.register(MockModel, FakeSearchIndex)
        
        mock = MockModel()
        mock.pk = 20
        
        self.assertEqual(self.site.remove_object(mock), True)
예제 #8
0
class SolrSearchBackendTestCase(TestCase):
    def setUp(self):
        super(SolrSearchBackendTestCase, self).setUp()

        # Wipe it clean.
        self.raw_solr = pysolr.Solr(settings.HAYSTACK_SOLR_URL)
        clear_solr_index()

        self.site = SearchSite()
        self.sb = SearchBackend(site=self.site)
        self.smmi = SolrMockSearchIndex(MockModel, backend=self.sb)
        self.smtmmi = SolrMaintainTypeMockSearchIndex(MockModel,
                                                      backend=self.sb)
        self.site.register(MockModel, SolrMockSearchIndex)

        # Stow.
        import haystack
        self.old_site = haystack.site
        haystack.site = self.site

        self.sample_objs = []

        for i in xrange(1, 4):
            mock = MockModel()
            mock.id = i
            mock.author = 'daniel%s' % i
            mock.pub_date = datetime.date(2009, 2,
                                          25) - datetime.timedelta(days=i)
            self.sample_objs.append(mock)

    def tearDown(self):
        import haystack
        haystack.site = self.old_site
        super(SolrSearchBackendTestCase, self).tearDown()

    def test_update(self):
        self.sb.update(self.smmi, self.sample_objs)

        # Check what Solr thinks is there.
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)
        self.assertEqual(
            self.raw_solr.search('*:*').docs, [{
                'django_id': '1',
                'django_ct': 'core.mockmodel',
                'name': 'daniel1',
                'name_exact': 'daniel1',
                'text': 'Indexed!\n1',
                'pub_date': '2009-02-24T00:00:00Z',
                'id': 'core.mockmodel.1'
            }, {
                'django_id': '2',
                'django_ct': 'core.mockmodel',
                'name': 'daniel2',
                'name_exact': 'daniel2',
                'text': 'Indexed!\n2',
                'pub_date': '2009-02-23T00:00:00Z',
                'id': 'core.mockmodel.2'
            }, {
                'django_id': '3',
                'django_ct': 'core.mockmodel',
                'name': 'daniel3',
                'name_exact': 'daniel3',
                'text': 'Indexed!\n3',
                'pub_date': '2009-02-22T00:00:00Z',
                'id': 'core.mockmodel.3'
            }])

    def test_remove(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)

        self.sb.remove(self.sample_objs[0])
        self.assertEqual(self.raw_solr.search('*:*').hits, 2)
        self.assertEqual(
            self.raw_solr.search('*:*').docs, [{
                'django_id': '2',
                'django_ct': 'core.mockmodel',
                'name': 'daniel2',
                'name_exact': 'daniel2',
                'text': 'Indexed!\n2',
                'pub_date': '2009-02-23T00:00:00Z',
                'id': 'core.mockmodel.2'
            }, {
                'django_id': '3',
                'django_ct': 'core.mockmodel',
                'name': 'daniel3',
                'name_exact': 'daniel3',
                'text': 'Indexed!\n3',
                'pub_date': '2009-02-22T00:00:00Z',
                'id': 'core.mockmodel.3'
            }])

    def test_clear(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)

        self.sb.clear()
        self.assertEqual(self.raw_solr.search('*:*').hits, 0)

        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)

        self.sb.clear([AnotherMockModel])
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)

        self.sb.clear([MockModel])
        self.assertEqual(self.raw_solr.search('*:*').hits, 0)

        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)

        self.sb.clear([AnotherMockModel, MockModel])
        self.assertEqual(self.raw_solr.search('*:*').hits, 0)

    def test_search(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)

        self.assertEqual(self.sb.search(''), {'hits': 0, 'results': []})
        self.assertEqual(self.sb.search('*:*')['hits'], 3)
        self.assertEqual(
            [result.pk for result in self.sb.search('*:*')['results']],
            ['1', '2', '3'])

        self.assertEqual(self.sb.search('', highlight=True), {
            'hits': 0,
            'results': []
        })
        self.assertEqual(self.sb.search('Index', highlight=True)['hits'], 3)
        self.assertEqual([
            result.highlighted['text'][0]
            for result in self.sb.search('Index', highlight=True)['results']
        ], [
            '<em>Indexed</em>!\n1', '<em>Indexed</em>!\n2',
            '<em>Indexed</em>!\n3'
        ])

        self.assertEqual(self.sb.search('Indx')['hits'], 0)
        self.assertEqual(
            self.sb.search('Indx')['spelling_suggestion'], 'index')
        self.assertEqual(
            self.sb.search('Indx',
                           spelling_query='indexy')['spelling_suggestion'],
            'index')

        self.assertEqual(self.sb.search('', facets=['name']), {
            'hits': 0,
            'results': []
        })
        results = self.sb.search('Index', facets=['name'])
        self.assertEqual(results['hits'], 3)
        self.assertEqual(results['facets']['fields']['name'], [('daniel1', 1),
                                                               ('daniel2', 1),
                                                               ('daniel3', 1)])

        self.assertEqual(
            self.sb.search('',
                           date_facets={
                               'pub_date': {
                                   'start_date': datetime.date(2008, 2, 26),
                                   'end_date': datetime.date(2008, 3, 26),
                                   'gap_by': 'month',
                                   'gap_amount': 1
                               }
                           }), {
                               'hits': 0,
                               'results': []
                           })
        results = self.sb.search('Index',
                                 date_facets={
                                     'pub_date': {
                                         'start_date':
                                         datetime.date(2008, 2, 26),
                                         'end_date':
                                         datetime.date(2008, 3, 26),
                                         'gap_by': 'month',
                                         'gap_amount': 1
                                     }
                                 })
        self.assertEqual(results['hits'], 3)
        # DRL_TODO: Correct output but no counts. Another case of needing better test data?
        # self.assertEqual(results['facets']['dates']['pub_date'], {'end': '2008-02-26T00:00:00Z', 'gap': '/MONTH'})

        self.assertEqual(
            self.sb.search('', query_facets=[('name', '[* TO e]')]), {
                'hits': 0,
                'results': []
            })
        results = self.sb.search('Index', query_facets=[('name', '[* TO e]')])
        self.assertEqual(results['hits'], 3)
        self.assertEqual(results['facets']['queries'], {'name:[* TO e]': 3})

        self.assertEqual(
            self.sb.search('', narrow_queries=set(['name:daniel1'])), {
                'hits': 0,
                'results': []
            })
        results = self.sb.search('Index', narrow_queries=set(['name:daniel1']))
        self.assertEqual(results['hits'], 1)

        # Ensure that swapping the ``result_class`` works.
        self.assertTrue(
            isinstance(
                self.sb.search(u'index document',
                               result_class=MockSearchResult)['results'][0],
                MockSearchResult))

        # Check the use of ``limit_to_registered_models``.
        self.assertEqual(self.sb.search('', limit_to_registered_models=False),
                         {
                             'hits': 0,
                             'results': []
                         })
        self.assertEqual(
            self.sb.search('*:*', limit_to_registered_models=False)['hits'], 3)
        self.assertEqual([
            result.pk for result in self.sb.search(
                '*:*', limit_to_registered_models=False)['results']
        ], ['1', '2', '3'])

        # Stow.
        old_limit_to_registered_models = getattr(
            settings, 'HAYSTACK_LIMIT_TO_REGISTERED_MODELS', True)
        settings.HAYSTACK_LIMIT_TO_REGISTERED_MODELS = False

        self.assertEqual(self.sb.search(''), {'hits': 0, 'results': []})
        self.assertEqual(self.sb.search('*:*')['hits'], 3)
        self.assertEqual(
            [result.pk for result in self.sb.search('*:*')['results']],
            ['1', '2', '3'])

        # Restore.
        settings.HAYSTACK_LIMIT_TO_REGISTERED_MODELS = old_limit_to_registered_models

    def test_more_like_this(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search('*:*').hits, 3)

        # A functional MLT example with enough data to work is below. Rely on
        # this to ensure the API is correct enough.
        self.assertEqual(
            self.sb.more_like_this(self.sample_objs[0])['hits'], 0)
        self.assertEqual([
            result.pk for result in self.sb.more_like_this(self.sample_objs[0])
            ['results']
        ], [])

    def test_build_schema(self):
        (content_field_name,
         fields) = self.sb.build_schema(self.site.all_searchfields())
        self.assertEqual(content_field_name, 'text')
        self.assertEqual(len(fields), 4)
        self.assertEqual(fields, [{
            'indexed': 'true',
            'type': 'text',
            'stored': 'true',
            'field_name': 'text',
            'multi_valued': 'false'
        }, {
            'indexed': 'true',
            'type': 'date',
            'stored': 'true',
            'field_name': 'pub_date',
            'multi_valued': 'false'
        }, {
            'indexed': 'true',
            'type': 'text',
            'stored': 'true',
            'field_name': 'name',
            'multi_valued': 'false'
        }, {
            'indexed': 'true',
            'field_name': 'name_exact',
            'stored': 'true',
            'type': 'string',
            'multi_valued': 'false'
        }])

        self.site.unregister(MockModel)
        self.site.register(MockModel, SolrComplexFacetsMockSearchIndex)
        (content_field_name,
         fields) = self.sb.build_schema(self.site.all_searchfields())
        self.assertEqual(content_field_name, 'text')
        self.assertEqual(len(fields), 15)
        self.assertEqual(fields, [{
            'indexed': 'true',
            'type': 'text',
            'stored': 'true',
            'field_name': 'name',
            'multi_valued': 'false'
        }, {
            'indexed': 'true',
            'type': 'boolean',
            'stored': 'true',
            'field_name': 'is_active_exact',
            'multi_valued': 'false'
        }, {
            'indexed': 'true',
            'type': 'date',
            'stored': 'true',
            'field_name': 'created',
            'multi_valued': 'false'
        }, {
            'indexed': 'true',
            'type': 'slong',
            'stored': 'true',
            'field_name': 'post_count',
            'multi_valued': 'false'
        }, {
            'indexed': 'true',
            'type': 'date',
            'stored': 'true',
            'field_name': 'created_exact',
            'multi_valued': 'false'
        }, {
            'indexed': 'true',
            'type': 'string',
            'stored': 'true',
            'field_name': 'sites_exact',
            'multi_valued': 'true'
        }, {
            'indexed': 'true',
            'type': 'boolean',
            'stored': 'true',
            'field_name': 'is_active',
            'multi_valued': 'false'
        }, {
            'indexed': 'true',
            'type': 'text',
            'stored': 'true',
            'field_name': 'sites',
            'multi_valued': 'true'
        }, {
            'indexed': 'true',
            'type': 'slong',
            'stored': 'true',
            'field_name': 'post_count_i',
            'multi_valued': 'false'
        }, {
            'indexed': 'true',
            'type': 'sfloat',
            'stored': 'true',
            'field_name': 'average_rating',
            'multi_valued': 'false'
        }, {
            'indexed': 'true',
            'type': 'text',
            'stored': 'true',
            'field_name': 'text',
            'multi_valued': 'false'
        }, {
            'indexed': 'true',
            'type': 'date',
            'stored': 'true',
            'field_name': 'pub_date_exact',
            'multi_valued': 'false'
        }, {
            'indexed': 'true',
            'type': 'string',
            'stored': 'true',
            'field_name': 'name_exact',
            'multi_valued': 'false'
        }, {
            'indexed': 'true',
            'type': 'date',
            'stored': 'true',
            'field_name': 'pub_date',
            'multi_valued': 'false'
        }, {
            'indexed': 'true',
            'type': 'sfloat',
            'stored': 'true',
            'field_name': 'average_rating_exact',
            'multi_valued': 'false'
        }])

    def test_verify_type(self):
        import haystack
        haystack.site.unregister(MockModel)
        haystack.site.register(MockModel, SolrMaintainTypeMockSearchIndex)
        self.sb.update(self.smtmmi, self.sample_objs)

        self.assertEqual(self.sb.search('*:*')['hits'], 3)
        self.assertEqual(
            [result.month for result in self.sb.search('*:*')['results']],
            [u'02', u'02', u'02'])
class SolrSearchBackendTestCase(TestCase):
    def setUp(self):
        super(SolrSearchBackendTestCase, self).setUp()

        # Wipe it clean.
        self.raw_solr = pysolr.Solr(settings.HAYSTACK_SOLR_URL)
        clear_solr_index()

        self.site = SearchSite()
        self.sb = SearchBackend(site=self.site)
        self.smmi = SolrMockSearchIndex(MockModel, backend=self.sb)
        self.smtmmi = SolrMaintainTypeMockSearchIndex(MockModel, backend=self.sb)
        self.site.register(MockModel, SolrMockSearchIndex)

        # Stow.
        import haystack

        self.old_site = haystack.site
        haystack.site = self.site

        self.sample_objs = []

        for i in xrange(1, 4):
            mock = MockModel()
            mock.id = i
            mock.author = "daniel%s" % i
            mock.pub_date = datetime.date(2009, 2, 25) - datetime.timedelta(days=i)
            self.sample_objs.append(mock)

    def tearDown(self):
        import haystack

        haystack.site = self.old_site
        super(SolrSearchBackendTestCase, self).tearDown()

    def test_update(self):
        self.sb.update(self.smmi, self.sample_objs)

        # Check what Solr thinks is there.
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)
        self.assertEqual(
            self.raw_solr.search("*:*").docs,
            [
                {
                    "django_id": "1",
                    "django_ct": "core.mockmodel",
                    "name": "daniel1",
                    "name_exact": "daniel1",
                    "text": "Indexed!\n1",
                    "pub_date": "2009-02-24T00:00:00Z",
                    "id": "core.mockmodel.1",
                },
                {
                    "django_id": "2",
                    "django_ct": "core.mockmodel",
                    "name": "daniel2",
                    "name_exact": "daniel2",
                    "text": "Indexed!\n2",
                    "pub_date": "2009-02-23T00:00:00Z",
                    "id": "core.mockmodel.2",
                },
                {
                    "django_id": "3",
                    "django_ct": "core.mockmodel",
                    "name": "daniel3",
                    "name_exact": "daniel3",
                    "text": "Indexed!\n3",
                    "pub_date": "2009-02-22T00:00:00Z",
                    "id": "core.mockmodel.3",
                },
            ],
        )

    def test_remove(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)

        self.sb.remove(self.sample_objs[0])
        self.assertEqual(self.raw_solr.search("*:*").hits, 2)
        self.assertEqual(
            self.raw_solr.search("*:*").docs,
            [
                {
                    "django_id": "2",
                    "django_ct": "core.mockmodel",
                    "name": "daniel2",
                    "name_exact": "daniel2",
                    "text": "Indexed!\n2",
                    "pub_date": "2009-02-23T00:00:00Z",
                    "id": "core.mockmodel.2",
                },
                {
                    "django_id": "3",
                    "django_ct": "core.mockmodel",
                    "name": "daniel3",
                    "name_exact": "daniel3",
                    "text": "Indexed!\n3",
                    "pub_date": "2009-02-22T00:00:00Z",
                    "id": "core.mockmodel.3",
                },
            ],
        )

    def test_clear(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)

        self.sb.clear()
        self.assertEqual(self.raw_solr.search("*:*").hits, 0)

        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)

        self.sb.clear([AnotherMockModel])
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)

        self.sb.clear([MockModel])
        self.assertEqual(self.raw_solr.search("*:*").hits, 0)

        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)

        self.sb.clear([AnotherMockModel, MockModel])
        self.assertEqual(self.raw_solr.search("*:*").hits, 0)

    def test_search(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)

        self.assertEqual(self.sb.search(""), {"hits": 0, "results": []})
        self.assertEqual(self.sb.search("*:*")["hits"], 3)
        self.assertEqual([result.pk for result in self.sb.search("*:*")["results"]], ["1", "2", "3"])

        self.assertEqual(self.sb.search("", highlight=True), {"hits": 0, "results": []})
        self.assertEqual(self.sb.search("Index", highlight=True)["hits"], 3)
        self.assertEqual(
            [result.highlighted["text"][0] for result in self.sb.search("Index", highlight=True)["results"]],
            ["<em>Indexed</em>!\n1", "<em>Indexed</em>!\n2", "<em>Indexed</em>!\n3"],
        )

        self.assertEqual(self.sb.search("Indx")["hits"], 0)
        self.assertEqual(self.sb.search("Indx")["spelling_suggestion"], "index")
        self.assertEqual(self.sb.search("Indx", spelling_query="indexy")["spelling_suggestion"], "index")

        self.assertEqual(self.sb.search("", facets=["name"]), {"hits": 0, "results": []})
        results = self.sb.search("Index", facets=["name"])
        self.assertEqual(results["hits"], 3)
        self.assertEqual(results["facets"]["fields"]["name"], [("daniel1", 1), ("daniel2", 1), ("daniel3", 1)])

        self.assertEqual(
            self.sb.search(
                "",
                date_facets={
                    "pub_date": {
                        "start_date": datetime.date(2008, 2, 26),
                        "end_date": datetime.date(2008, 3, 26),
                        "gap_by": "month",
                        "gap_amount": 1,
                    }
                },
            ),
            {"hits": 0, "results": []},
        )
        results = self.sb.search(
            "Index",
            date_facets={
                "pub_date": {
                    "start_date": datetime.date(2008, 2, 26),
                    "end_date": datetime.date(2008, 3, 26),
                    "gap_by": "month",
                    "gap_amount": 1,
                }
            },
        )
        self.assertEqual(results["hits"], 3)
        # DRL_TODO: Correct output but no counts. Another case of needing better test data?
        # self.assertEqual(results['facets']['dates']['pub_date'], {'end': '2008-02-26T00:00:00Z', 'gap': '/MONTH'})

        self.assertEqual(self.sb.search("", query_facets=[("name", "[* TO e]")]), {"hits": 0, "results": []})
        results = self.sb.search("Index", query_facets=[("name", "[* TO e]")])
        self.assertEqual(results["hits"], 3)
        self.assertEqual(results["facets"]["queries"], {"name:[* TO e]": 3})

        self.assertEqual(self.sb.search("", narrow_queries=set(["name:daniel1"])), {"hits": 0, "results": []})
        results = self.sb.search("Index", narrow_queries=set(["name:daniel1"]))
        self.assertEqual(results["hits"], 1)

        # Ensure that swapping the ``result_class`` works.
        self.assertTrue(
            isinstance(self.sb.search(u"index document", result_class=MockSearchResult)["results"][0], MockSearchResult)
        )

        # Check the use of ``limit_to_registered_models``.
        self.assertEqual(self.sb.search("", limit_to_registered_models=False), {"hits": 0, "results": []})
        self.assertEqual(self.sb.search("*:*", limit_to_registered_models=False)["hits"], 3)
        self.assertEqual(
            [result.pk for result in self.sb.search("*:*", limit_to_registered_models=False)["results"]],
            ["1", "2", "3"],
        )

        # Stow.
        old_limit_to_registered_models = getattr(settings, "HAYSTACK_LIMIT_TO_REGISTERED_MODELS", True)
        settings.HAYSTACK_LIMIT_TO_REGISTERED_MODELS = False

        self.assertEqual(self.sb.search(""), {"hits": 0, "results": []})
        self.assertEqual(self.sb.search("*:*")["hits"], 3)
        self.assertEqual([result.pk for result in self.sb.search("*:*")["results"]], ["1", "2", "3"])

        # Restore.
        settings.HAYSTACK_LIMIT_TO_REGISTERED_MODELS = old_limit_to_registered_models

    def test_use_correct_site(self):
        import haystack

        test_site = SearchSite()
        test_site.register(MockModel, SolrMockSearchIndex)
        self.sb.update(self.smmi, self.sample_objs)

        # Make sure that ``_process_results`` uses the right ``site``.
        self.assertEqual(self.sb.search("*:*")["hits"], 3)
        self.assertEqual([result.pk for result in self.sb.search("*:*")["results"]], ["1", "2", "3"])

        haystack.site.unregister(MockModel)
        self.assertEqual(len(haystack.site.get_indexed_models()), 0)
        self.sb.site = test_site
        self.assertTrue(len(self.sb.site.get_indexed_models()) > 0)

        # Should still be there, despite the main ``site`` not having that model
        # registered any longer.
        self.assertEqual(self.sb.search("*:*")["hits"], 3)
        self.assertEqual([result.pk for result in self.sb.search("*:*")["results"]], ["1", "2", "3"])

        # Unregister it on the backend & make sure it takes effect.
        self.sb.site.unregister(MockModel)
        self.assertEqual(len(self.sb.site.get_indexed_models()), 0)
        self.assertEqual(self.sb.search("*:*")["hits"], 0)

        # Nuke it & fallback on the main ``site``.
        self.sb.site = haystack.site
        self.assertEqual(self.sb.search("*:*")["hits"], 0)
        haystack.site.register(MockModel, SolrMockSearchIndex)
        self.assertEqual(self.sb.search("*:*")["hits"], 3)

    def test_more_like_this(self):
        self.sb.update(self.smmi, self.sample_objs)
        self.assertEqual(self.raw_solr.search("*:*").hits, 3)

        # A functional MLT example with enough data to work is below. Rely on
        # this to ensure the API is correct enough.
        self.assertEqual(self.sb.more_like_this(self.sample_objs[0])["hits"], 0)
        self.assertEqual([result.pk for result in self.sb.more_like_this(self.sample_objs[0])["results"]], [])

    def test_build_schema(self):
        (content_field_name, fields) = self.sb.build_schema(self.site.all_searchfields())
        self.assertEqual(content_field_name, "text")
        self.assertEqual(len(fields), 4)
        self.assertEqual(
            fields,
            [
                {"indexed": "true", "type": "text", "stored": "true", "field_name": "text", "multi_valued": "false"},
                {
                    "indexed": "true",
                    "type": "date",
                    "stored": "true",
                    "field_name": "pub_date",
                    "multi_valued": "false",
                },
                {"indexed": "true", "type": "text", "stored": "true", "field_name": "name", "multi_valued": "false"},
                {
                    "indexed": "true",
                    "field_name": "name_exact",
                    "stored": "true",
                    "type": "string",
                    "multi_valued": "false",
                },
            ],
        )

        self.site.unregister(MockModel)
        self.site.register(MockModel, SolrComplexFacetsMockSearchIndex)
        (content_field_name, fields) = self.sb.build_schema(self.site.all_searchfields())
        self.assertEqual(content_field_name, "text")
        self.assertEqual(len(fields), 15)
        self.assertEqual(
            fields,
            [
                {"indexed": "true", "type": "text", "stored": "true", "field_name": "name", "multi_valued": "false"},
                {
                    "indexed": "true",
                    "type": "boolean",
                    "stored": "true",
                    "field_name": "is_active_exact",
                    "multi_valued": "false",
                },
                {"indexed": "true", "type": "date", "stored": "true", "field_name": "created", "multi_valued": "false"},
                {
                    "indexed": "true",
                    "type": "slong",
                    "stored": "true",
                    "field_name": "post_count",
                    "multi_valued": "false",
                },
                {
                    "indexed": "true",
                    "type": "date",
                    "stored": "true",
                    "field_name": "created_exact",
                    "multi_valued": "false",
                },
                {
                    "indexed": "true",
                    "type": "string",
                    "stored": "true",
                    "field_name": "sites_exact",
                    "multi_valued": "true",
                },
                {
                    "indexed": "true",
                    "type": "boolean",
                    "stored": "true",
                    "field_name": "is_active",
                    "multi_valued": "false",
                },
                {"indexed": "true", "type": "text", "stored": "true", "field_name": "sites", "multi_valued": "true"},
                {
                    "indexed": "true",
                    "type": "slong",
                    "stored": "true",
                    "field_name": "post_count_i",
                    "multi_valued": "false",
                },
                {
                    "indexed": "true",
                    "type": "sfloat",
                    "stored": "true",
                    "field_name": "average_rating",
                    "multi_valued": "false",
                },
                {"indexed": "true", "type": "text", "stored": "true", "field_name": "text", "multi_valued": "false"},
                {
                    "indexed": "true",
                    "type": "date",
                    "stored": "true",
                    "field_name": "pub_date_exact",
                    "multi_valued": "false",
                },
                {
                    "indexed": "true",
                    "type": "string",
                    "stored": "true",
                    "field_name": "name_exact",
                    "multi_valued": "false",
                },
                {
                    "indexed": "true",
                    "type": "date",
                    "stored": "true",
                    "field_name": "pub_date",
                    "multi_valued": "false",
                },
                {
                    "indexed": "true",
                    "type": "sfloat",
                    "stored": "true",
                    "field_name": "average_rating_exact",
                    "multi_valued": "false",
                },
            ],
        )

    def test_verify_type(self):
        import haystack

        haystack.site.unregister(MockModel)
        haystack.site.register(MockModel, SolrMaintainTypeMockSearchIndex)
        self.sb.update(self.smtmmi, self.sample_objs)

        self.assertEqual(self.sb.search("*:*")["hits"], 3)
        self.assertEqual([result.month for result in self.sb.search("*:*")["results"]], [u"02", u"02", u"02"])