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'])
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"])
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)
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)
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'])
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)
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"])