2011-08-29 13:10:56 +00:00
"""
Tests for django - watson .
Fun fact : The MySQL full text search engine does not support indexing of words
that are 3 letters or fewer . Thus , the standard metasyntactic variables in
these tests have been amended to ' fooo ' and ' baar ' . Ho hum .
"""
2011-08-20 17:50:35 +00:00
2013-05-02 14:50:16 +00:00
from __future__ import unicode_literals
2013-06-21 09:10:54 +00:00
import os , json
2013-12-03 17:02:23 +00:00
try :
from unittest import skipUnless
except :
from django . utils . unittest import skipUnless
2011-08-29 10:18:53 +00:00
2011-08-21 14:15:15 +00:00
from django . db import models
from django . test import TestCase
2011-08-21 17:31:38 +00:00
from django . core . management import call_command
2013-01-25 08:56:07 +00:00
try :
from django . conf . urls import *
except ImportError : # Django<1.4
from django . conf . urls . defaults import *
2011-08-30 09:53:33 +00:00
from django . conf import settings
2011-08-29 13:37:19 +00:00
from django . contrib import admin
2011-08-29 13:57:55 +00:00
from django . contrib . auth . models import User
2011-09-08 15:53:07 +00:00
from django . http import HttpResponseNotFound , HttpResponseServerError
2011-08-30 10:22:39 +00:00
from django import template
2013-05-01 16:08:09 +00:00
from django . utils . encoding import force_text
2011-08-21 14:15:15 +00:00
2011-08-23 16:12:35 +00:00
import watson
2011-08-29 10:51:40 +00:00
from watson . registration import RegistrationError , get_backend , SearchEngine
2011-08-21 20:12:28 +00:00
from watson . models import SearchEntry
2011-08-21 14:15:15 +00:00
2011-08-21 14:52:24 +00:00
class TestModelBase ( models . Model ) :
title = models . CharField (
max_length = 200 ,
)
content = models . TextField (
blank = True ,
)
description = models . TextField (
blank = True ,
)
2011-08-21 20:25:10 +00:00
is_published = models . BooleanField (
default = True ,
)
2011-08-21 14:52:24 +00:00
def __unicode__ ( self ) :
return self . title
2011-08-21 14:15:15 +00:00
class Meta :
2011-08-21 14:52:24 +00:00
abstract = True
2011-08-21 14:15:15 +00:00
app_label = " auth " # Hack: Cannot use an app_label that is under South control, due to http://south.aeracode.org/ticket/520
2011-08-21 14:52:24 +00:00
2011-09-15 11:22:37 +00:00
class WatsonTestModel1 ( TestModelBase ) :
2011-08-21 14:52:24 +00:00
pass
2011-08-21 17:00:49 +00:00
str_pk_gen = 0 ;
def get_str_pk ( ) :
global str_pk_gen
str_pk_gen + = 1 ;
return str ( str_pk_gen )
2011-08-21 14:52:24 +00:00
2011-09-15 11:22:37 +00:00
class WatsonTestModel2 ( TestModelBase ) :
2011-08-21 14:52:24 +00:00
2011-08-21 17:00:49 +00:00
id = models . CharField (
primary_key = True ,
max_length = 100 ,
default = get_str_pk
)
2011-08-21 14:15:15 +00:00
2011-08-23 16:12:35 +00:00
class RegistrationTest ( TestCase ) :
2011-08-21 14:15:15 +00:00
def testRegistration ( self ) :
# Register the model and test.
2011-09-15 11:22:37 +00:00
watson . register ( WatsonTestModel1 )
self . assertTrue ( watson . is_registered ( WatsonTestModel1 ) )
self . assertRaises ( RegistrationError , lambda : watson . register ( WatsonTestModel1 ) )
self . assertTrue ( WatsonTestModel1 in watson . get_registered_models ( ) )
self . assertTrue ( isinstance ( watson . get_adapter ( WatsonTestModel1 ) , watson . SearchAdapter ) )
2011-08-21 14:15:15 +00:00
# Unregister the model and text.
2011-09-15 11:22:37 +00:00
watson . unregister ( WatsonTestModel1 )
self . assertFalse ( watson . is_registered ( WatsonTestModel1 ) )
self . assertRaises ( RegistrationError , lambda : watson . unregister ( WatsonTestModel1 ) )
self . assertTrue ( WatsonTestModel1 not in watson . get_registered_models ( ) )
self . assertRaises ( RegistrationError , lambda : isinstance ( watson . get_adapter ( WatsonTestModel1 ) ) )
2011-08-24 10:06:41 +00:00
2011-08-29 10:51:40 +00:00
complex_registration_search_engine = SearchEngine ( " restricted " )
2011-09-11 20:09:01 +00:00
class InstallUninstallTestBase ( TestCase ) :
def testUninstallAndInstall ( self ) :
# Not too much to test here, as some backends don't require installation.
# Just make sure the commands don't error.
call_command ( " uninstallwatson " , verbosity = 0 )
call_command ( " installwatson " , verbosity = 0 )
@skipUnless ( get_backend ( ) . requires_installation , " search backend does not require installation " )
def testRealInstallAndUninstall ( self ) :
backend = get_backend ( )
call_command ( " uninstallwatson " , verbosity = 0 )
self . assertFalse ( backend . is_installed ( ) )
call_command ( " installwatson " , verbosity = 0 )
self . assertTrue ( backend . is_installed ( ) )
2011-08-24 10:06:41 +00:00
class SearchTestBase ( TestCase ) :
2011-09-15 11:22:37 +00:00
model1 = WatsonTestModel1
2011-08-29 15:47:40 +00:00
2011-09-15 11:22:37 +00:00
model2 = WatsonTestModel2
2011-08-24 10:06:41 +00:00
2011-08-21 14:52:24 +00:00
def setUp ( self ) :
2011-09-08 15:53:07 +00:00
# If migrations are off, then this is needed to get the indices installed. It has to
# be called in the setUp() method, but multiple invocations should be safe.
call_command ( " installwatson " , verbosity = 0 )
2011-08-25 11:09:01 +00:00
# Remove all the current registered models.
self . registered_models = watson . get_registered_models ( )
for model in self . registered_models :
watson . unregister ( model )
# Register the test models.
2011-08-29 15:47:40 +00:00
watson . register ( self . model1 )
watson . register ( self . model2 , exclude = ( " id " , ) )
2011-09-15 11:22:37 +00:00
complex_registration_search_engine . register ( WatsonTestModel1 , exclude = ( " content " , " description " , ) , store = ( " is_published " , ) )
complex_registration_search_engine . register ( WatsonTestModel2 , fields = ( " title " , ) )
2011-08-21 15:55:37 +00:00
# Create some test models.
2011-09-15 11:22:37 +00:00
self . test11 = WatsonTestModel1 . objects . create (
2011-08-27 17:38:44 +00:00
title = " title model1 instance11 " ,
content = " content model1 instance11 " ,
description = " description model1 instance11 " ,
2011-08-21 15:55:37 +00:00
)
2011-09-15 11:22:37 +00:00
self . test12 = WatsonTestModel1 . objects . create (
2011-08-27 17:38:44 +00:00
title = " title model1 instance12 " ,
content = " content model1 instance12 " ,
description = " description model1 instance12 " ,
2011-08-21 15:55:37 +00:00
)
2011-09-15 11:22:37 +00:00
self . test21 = WatsonTestModel2 . objects . create (
2011-08-27 17:38:44 +00:00
title = " title model2 instance21 " ,
content = " content model2 instance21 " ,
description = " description model2 instance21 " ,
2011-08-21 15:55:37 +00:00
)
2011-09-15 11:22:37 +00:00
self . test22 = WatsonTestModel2 . objects . create (
2011-08-27 17:38:44 +00:00
title = " title model2 instance22 " ,
content = " content model2 instance22 " ,
description = " description model2 instance22 " ,
2011-08-21 15:55:37 +00:00
)
2011-08-24 10:06:41 +00:00
def tearDown ( self ) :
2011-08-25 11:09:01 +00:00
# Re-register the old registered models.
for model in self . registered_models :
watson . register ( model )
# Unregister the test models.
2011-08-29 15:47:40 +00:00
watson . unregister ( self . model1 )
watson . unregister ( self . model2 )
2011-09-15 11:22:37 +00:00
complex_registration_search_engine . unregister ( WatsonTestModel1 )
complex_registration_search_engine . unregister ( WatsonTestModel2 )
2011-08-24 10:06:41 +00:00
# Delete the test models.
2011-09-15 11:22:37 +00:00
WatsonTestModel1 . objects . all ( ) . delete ( )
WatsonTestModel2 . objects . all ( ) . delete ( )
2011-08-24 10:06:41 +00:00
del self . test11
del self . test12
del self . test21
del self . test22
# Delete the search index.
SearchEntry . objects . all ( ) . delete ( )
class InternalsTest ( SearchTestBase ) :
2011-08-23 16:12:35 +00:00
def testSearchEntriesCreated ( self ) :
2011-08-29 10:51:40 +00:00
self . assertEqual ( SearchEntry . objects . filter ( engine_slug = " default " ) . count ( ) , 4 )
2014-01-12 15:10:45 +00:00
def testBuildWatsonForModelCommand ( self ) :
# Hack a change into the model using a bulk update, which doesn't send signals.
WatsonTestModel1 . objects . filter ( id = self . test11 . id ) . update ( title = " fooo1_selective " )
WatsonTestModel2 . objects . filter ( id = self . test21 . id ) . update ( title = " fooo2_selective " )
# Test that no update has happened.
self . assertEqual ( watson . search ( " fooo1_selective " ) . count ( ) , 0 )
self . assertEqual ( watson . search ( " fooo2_selective " ) . count ( ) , 0 )
# Run the rebuild command.
call_command ( " buildwatson " , " WatsonTestModel1 " , verbosity = 0 )
2014-01-13 22:32:34 +00:00
# Test that the update is now applied to selected model.
2014-01-12 15:10:45 +00:00
self . assertEqual ( watson . search ( " fooo1_selective " ) . count ( ) , 1 )
self . assertEqual ( watson . search ( " fooo2_selective " ) . count ( ) , 0 )
2014-01-13 22:32:34 +00:00
call_command ( " buildwatson " , " WatsonTestModel1 " , " WatsonTestModel2 " , verbosity = 0 )
# Test that the update is now applied to multiple selected models.
self . assertEqual ( watson . search ( " fooo1_selective " ) . count ( ) , 1 )
self . assertEqual ( watson . search ( " fooo2_selective " ) . count ( ) , 1 )
2014-01-12 15:10:45 +00:00
2011-08-27 17:38:44 +00:00
def testBuildWatsonCommand ( self ) :
2012-03-07 22:43:11 +00:00
# Hack a change into the model using a bulk update, which doesn't send signals.
2014-01-12 15:10:45 +00:00
WatsonTestModel1 . objects . filter ( id = self . test11 . id ) . update ( title = " fooo1 " )
WatsonTestModel2 . objects . filter ( id = self . test21 . id ) . update ( title = " fooo2 " )
2011-08-24 10:06:41 +00:00
# Test that no update has happened.
2014-01-12 15:10:45 +00:00
self . assertEqual ( watson . search ( " fooo1 " ) . count ( ) , 0 )
self . assertEqual ( watson . search ( " fooo2 " ) . count ( ) , 0 )
2011-08-24 10:06:41 +00:00
# Run the rebuild command.
2011-08-24 11:42:03 +00:00
call_command ( " buildwatson " , verbosity = 0 )
2014-01-13 22:32:34 +00:00
# Test that the update is now applied.
2014-01-12 15:10:45 +00:00
self . assertEqual ( watson . search ( " fooo1 " ) . count ( ) , 1 )
self . assertEqual ( watson . search ( " fooo2 " ) . count ( ) , 1 )
2011-08-21 16:50:09 +00:00
def testUpdateSearchIndex ( self ) :
# Update a model and make sure that the search results match.
2012-03-07 22:43:11 +00:00
self . test11 . title = " fooo "
self . test11 . save ( )
2011-08-21 16:50:09 +00:00
# Test a search that should get one model.
2011-08-29 13:08:16 +00:00
exact_search = watson . search ( " fooo " )
2011-08-21 16:50:09 +00:00
self . assertEqual ( len ( exact_search ) , 1 )
2011-08-29 13:08:16 +00:00
self . assertEqual ( exact_search [ 0 ] . title , " fooo " )
2011-08-23 16:20:28 +00:00
# Delete a model and make sure that the search results match.
2012-03-07 22:43:11 +00:00
self . test11 . delete ( )
2011-08-29 13:08:16 +00:00
self . assertEqual ( watson . search ( " fooo " ) . count ( ) , 0 )
2011-09-05 11:09:25 +00:00
2012-03-07 22:43:11 +00:00
def testSearchIndexUpdateDeferredByContext ( self ) :
with watson . update_index ( ) :
self . test11 . title = " fooo "
self . test11 . save ( )
self . assertEqual ( watson . search ( " fooo " ) . count ( ) , 0 )
self . assertEqual ( watson . search ( " fooo " ) . count ( ) , 1 )
2011-09-05 11:09:25 +00:00
def testSearchIndexUpdateAbandonedOnError ( self ) :
try :
with watson . update_index ( ) :
self . test11 . title = " fooo "
self . test11 . save ( )
raise Exception ( " Foo " )
except :
pass
# Test a search that should get not model.
self . assertEqual ( watson . search ( " fooo " ) . count ( ) , 0 )
2011-08-24 10:06:41 +00:00
2014-07-24 18:34:25 +00:00
def testSkipSearchIndexUpdate ( self ) :
with watson . skip_index_update ( ) :
self . test11 . title = " fooo "
self . test11 . save ( )
# Test a search that should get not model.
self . assertEqual ( watson . search ( " fooo " ) . count ( ) , 0 )
2011-08-24 10:06:41 +00:00
def testFixesDuplicateSearchEntries ( self ) :
2011-08-29 10:51:40 +00:00
search_entries = SearchEntry . objects . filter ( engine_slug = " default " )
2011-08-24 10:06:41 +00:00
# Duplicate a couple of search entries.
2011-08-29 10:51:40 +00:00
for search_entry in search_entries . all ( ) [ : 2 ] :
2011-08-24 10:06:41 +00:00
search_entry . id = None
search_entry . save ( )
# Make sure that we have six (including duplicates).
2011-08-29 10:51:40 +00:00
self . assertEqual ( search_entries . all ( ) . count ( ) , 6 )
2011-08-24 10:06:41 +00:00
# Run the rebuild command.
2011-08-24 11:42:03 +00:00
call_command ( " buildwatson " , verbosity = 0 )
2011-08-24 10:06:41 +00:00
# Make sure that we have four again (including duplicates).
2011-08-29 10:51:40 +00:00
self . assertEqual ( search_entries . all ( ) . count ( ) , 4 )
2011-08-24 10:22:51 +00:00
2011-10-02 16:16:24 +00:00
def testEmptyFilterGivesAllResults ( self ) :
2011-09-15 11:22:37 +00:00
for model in ( WatsonTestModel1 , WatsonTestModel2 ) :
2011-10-02 16:16:24 +00:00
self . assertEqual ( watson . filter ( model , " " ) . count ( ) , 2 )
self . assertEqual ( watson . filter ( model , " " ) . count ( ) , 2 )
2011-08-24 10:06:41 +00:00
2011-08-27 17:45:43 +00:00
def testFilter ( self ) :
2011-09-15 11:22:37 +00:00
for model in ( WatsonTestModel1 , WatsonTestModel2 ) :
2011-08-27 17:45:43 +00:00
# Test can find all.
self . assertEqual ( watson . filter ( model , " TITLE " ) . count ( ) , 2 )
# Test can find a specific one.
2011-09-15 11:22:37 +00:00
obj = watson . filter ( WatsonTestModel1 , " INSTANCE12 " ) . get ( )
self . assertTrue ( isinstance ( obj , WatsonTestModel1 ) )
2011-08-27 17:45:43 +00:00
self . assertEqual ( obj . title , " title model1 instance12 " )
# Test can do filter on a queryset.
2011-09-15 11:22:37 +00:00
obj = watson . filter ( WatsonTestModel1 . objects . filter ( title__icontains = " TITLE " ) , " INSTANCE12 " ) . get ( )
self . assertTrue ( isinstance ( obj , WatsonTestModel1 ) )
2011-08-27 17:45:43 +00:00
self . assertEqual ( obj . title , " title model1 instance12 " )
2012-02-28 16:30:38 +00:00
@skipUnless ( get_backend ( ) . supports_prefix_matching , " Search backend does not support prefix matching. " )
def testPrefixFilter ( self ) :
2012-02-28 14:37:39 +00:00
self . assertEqual ( watson . filter ( WatsonTestModel1 , " INSTAN " ) . count ( ) , 2 )
2011-08-27 17:45:43 +00:00
2011-08-27 17:38:44 +00:00
2011-08-24 10:06:41 +00:00
class SearchTest ( SearchTestBase ) :
2011-09-06 16:17:14 +00:00
def emptySearchTextGivesNoResults ( self ) :
self . assertEqual ( watson . search ( " " ) . count ( ) , 0 )
self . assertEqual ( watson . search ( " " ) . count ( ) , 0 )
2011-08-24 10:06:41 +00:00
def testMultiTableSearch ( self ) :
# Test a search that should get all models.
2011-08-27 17:38:44 +00:00
self . assertEqual ( watson . search ( " TITLE " ) . count ( ) , 4 )
self . assertEqual ( watson . search ( " CONTENT " ) . count ( ) , 4 )
self . assertEqual ( watson . search ( " DESCRIPTION " ) . count ( ) , 4 )
2011-08-28 12:42:47 +00:00
self . assertEqual ( watson . search ( " TITLE CONTENT DESCRIPTION " ) . count ( ) , 4 )
2011-08-24 10:06:41 +00:00
# Test a search that should get two models.
2011-08-27 17:38:44 +00:00
self . assertEqual ( watson . search ( " MODEL1 " ) . count ( ) , 2 )
self . assertEqual ( watson . search ( " MODEL2 " ) . count ( ) , 2 )
self . assertEqual ( watson . search ( " TITLE MODEL1 " ) . count ( ) , 2 )
self . assertEqual ( watson . search ( " TITLE MODEL2 " ) . count ( ) , 2 )
2011-08-24 10:06:41 +00:00
# Test a search that should get one model.
2011-08-27 17:38:44 +00:00
self . assertEqual ( watson . search ( " INSTANCE11 " ) . count ( ) , 1 )
self . assertEqual ( watson . search ( " INSTANCE21 " ) . count ( ) , 1 )
self . assertEqual ( watson . search ( " TITLE INSTANCE11 " ) . count ( ) , 1 )
self . assertEqual ( watson . search ( " TITLE INSTANCE21 " ) . count ( ) , 1 )
# Test a search that should get zero models.
2011-08-29 13:08:16 +00:00
self . assertEqual ( watson . search ( " FOOO " ) . count ( ) , 0 )
self . assertEqual ( watson . search ( " FOOO INSTANCE11 " ) . count ( ) , 0 )
2011-08-27 17:38:44 +00:00
self . assertEqual ( watson . search ( " MODEL2 INSTANCE11 " ) . count ( ) , 0 )
2014-02-17 11:23:24 +00:00
def testSearchWithApostrophe ( self ) :
WatsonTestModel1 . objects . create (
title = " title model1 instance12 " ,
content = " content model1 instance13 d ' Argent " ,
description = " description model1 instance13 " ,
)
self . assertEqual ( watson . search ( " d ' Argent " ) . count ( ) , 1 )
2012-02-28 16:30:38 +00:00
@skipUnless ( get_backend ( ) . supports_prefix_matching , " Search backend does not support prefix matching. " )
def testMultiTablePrefixSearch ( self ) :
2012-02-28 15:14:28 +00:00
self . assertEqual ( watson . search ( " DESCR " ) . count ( ) , 4 )
2011-08-21 16:58:41 +00:00
def testLimitedModelList ( self ) :
# Test a search that should get all models.
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " TITLE " , models = ( WatsonTestModel1 , WatsonTestModel2 ) ) . count ( ) , 4 )
2011-08-27 17:38:44 +00:00
# Test a search that should get two models.
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " MODEL1 " , models = ( WatsonTestModel1 , WatsonTestModel2 ) ) . count ( ) , 2 )
self . assertEqual ( watson . search ( " MODEL1 " , models = ( WatsonTestModel1 , ) ) . count ( ) , 2 )
self . assertEqual ( watson . search ( " MODEL2 " , models = ( WatsonTestModel1 , WatsonTestModel2 ) ) . count ( ) , 2 )
self . assertEqual ( watson . search ( " MODEL2 " , models = ( WatsonTestModel2 , ) ) . count ( ) , 2 )
2011-08-24 10:57:16 +00:00
# Test a search that should get one model.
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " INSTANCE11 " , models = ( WatsonTestModel1 , WatsonTestModel2 ) ) . count ( ) , 1 )
self . assertEqual ( watson . search ( " INSTANCE11 " , models = ( WatsonTestModel1 , ) ) . count ( ) , 1 )
self . assertEqual ( watson . search ( " INSTANCE21 " , models = ( WatsonTestModel1 , WatsonTestModel2 , ) ) . count ( ) , 1 )
self . assertEqual ( watson . search ( " INSTANCE21 " , models = ( WatsonTestModel2 , ) ) . count ( ) , 1 )
2011-08-27 17:38:44 +00:00
# Test a search that should get zero models.
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " MODEL1 " , models = ( WatsonTestModel2 , ) ) . count ( ) , 0 )
self . assertEqual ( watson . search ( " MODEL2 " , models = ( WatsonTestModel1 , ) ) . count ( ) , 0 )
self . assertEqual ( watson . search ( " INSTANCE21 " , models = ( WatsonTestModel1 , ) ) . count ( ) , 0 )
self . assertEqual ( watson . search ( " INSTANCE11 " , models = ( WatsonTestModel2 , ) ) . count ( ) , 0 )
2011-08-21 16:58:41 +00:00
def testExcludedModelList ( self ) :
# Test a search that should get all models.
2011-08-27 17:38:44 +00:00
self . assertEqual ( watson . search ( " TITLE " , exclude = ( ) ) . count ( ) , 4 )
# Test a search that should get two models.
self . assertEqual ( watson . search ( " MODEL1 " , exclude = ( ) ) . count ( ) , 2 )
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " MODEL1 " , exclude = ( WatsonTestModel2 , ) ) . count ( ) , 2 )
2011-08-27 17:38:44 +00:00
self . assertEqual ( watson . search ( " MODEL2 " , exclude = ( ) ) . count ( ) , 2 )
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " MODEL2 " , exclude = ( WatsonTestModel1 , ) ) . count ( ) , 2 )
2011-08-21 16:58:41 +00:00
# Test a search that should get one model.
2011-08-27 17:38:44 +00:00
self . assertEqual ( watson . search ( " INSTANCE11 " , exclude = ( ) ) . count ( ) , 1 )
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " INSTANCE11 " , exclude = ( WatsonTestModel2 , ) ) . count ( ) , 1 )
2011-08-27 17:38:44 +00:00
self . assertEqual ( watson . search ( " INSTANCE21 " , exclude = ( ) ) . count ( ) , 1 )
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " INSTANCE21 " , exclude = ( WatsonTestModel1 , ) ) . count ( ) , 1 )
2011-08-27 17:38:44 +00:00
# Test a search that should get zero models.
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " MODEL1 " , exclude = ( WatsonTestModel1 , ) ) . count ( ) , 0 )
self . assertEqual ( watson . search ( " MODEL2 " , exclude = ( WatsonTestModel2 , ) ) . count ( ) , 0 )
self . assertEqual ( watson . search ( " INSTANCE21 " , exclude = ( WatsonTestModel2 , ) ) . count ( ) , 0 )
self . assertEqual ( watson . search ( " INSTANCE11 " , exclude = ( WatsonTestModel1 , ) ) . count ( ) , 0 )
2011-08-27 17:38:44 +00:00
def testLimitedModelQuerySet ( self ) :
2011-08-25 11:09:01 +00:00
# Test a search that should get all models.
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " TITLE " , models = ( WatsonTestModel1 . objects . filter ( title__icontains = " TITLE " ) , WatsonTestModel2 . objects . filter ( title__icontains = " TITLE " ) , ) ) . count ( ) , 4 )
2011-08-27 17:38:44 +00:00
# Test a search that should get two models.
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " MODEL1 " , models = ( WatsonTestModel1 . objects . filter (
2011-08-27 17:38:44 +00:00
title__icontains = " MODEL1 " ,
description__icontains = " MODEL1 " ,
) , ) ) . count ( ) , 2 )
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " MODEL2 " , models = ( WatsonTestModel2 . objects . filter (
2011-08-27 17:38:44 +00:00
title__icontains = " MODEL2 " ,
description__icontains = " MODEL2 " ,
) , ) ) . count ( ) , 2 )
2011-08-25 11:09:01 +00:00
# Test a search that should get one model.
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " INSTANCE11 " , models = ( WatsonTestModel1 . objects . filter (
2011-08-27 17:38:44 +00:00
title__icontains = " MODEL1 " ,
) , ) ) . count ( ) , 1 )
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " INSTANCE21 " , models = ( WatsonTestModel2 . objects . filter (
2011-08-27 17:38:44 +00:00
title__icontains = " MODEL2 " ,
) , ) ) . count ( ) , 1 )
# Test a search that should get no models.
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " INSTANCE11 " , models = ( WatsonTestModel1 . objects . filter (
2011-08-27 17:38:44 +00:00
title__icontains = " MODEL2 " ,
) , ) ) . count ( ) , 0 )
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " INSTANCE21 " , models = ( WatsonTestModel2 . objects . filter (
2011-08-27 17:38:44 +00:00
title__icontains = " MODEL1 " ,
) , ) ) . count ( ) , 0 )
def testExcludedModelQuerySet ( self ) :
# Test a search that should get all models.
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " TITLE " , exclude = ( WatsonTestModel1 . objects . filter ( title__icontains = " FOOO " ) , WatsonTestModel2 . objects . filter ( title__icontains = " FOOO " ) , ) ) . count ( ) , 4 )
2011-08-27 17:38:44 +00:00
# Test a search that should get two models.
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " MODEL1 " , exclude = ( WatsonTestModel1 . objects . filter (
2011-08-27 17:38:44 +00:00
title__icontains = " INSTANCE21 " ,
description__icontains = " INSTANCE22 " ,
) , ) ) . count ( ) , 2 )
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " MODEL2 " , exclude = ( WatsonTestModel2 . objects . filter (
2011-08-27 17:38:44 +00:00
title__icontains = " INSTANCE11 " ,
description__icontains = " INSTANCE12 " ,
) , ) ) . count ( ) , 2 )
2011-08-25 11:09:01 +00:00
# Test a search that should get one model.
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " INSTANCE11 " , exclude = ( WatsonTestModel1 . objects . filter (
2011-08-27 17:38:44 +00:00
title__icontains = " MODEL2 " ,
) , ) ) . count ( ) , 1 )
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " INSTANCE21 " , exclude = ( WatsonTestModel2 . objects . filter (
2011-08-27 17:38:44 +00:00
title__icontains = " MODEL1 " ,
) , ) ) . count ( ) , 1 )
2011-08-25 11:09:01 +00:00
# Test a search that should get no models.
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " INSTANCE11 " , exclude = ( WatsonTestModel1 . objects . filter (
2011-08-27 17:38:44 +00:00
title__icontains = " MODEL1 " ,
) , ) ) . count ( ) , 0 )
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " INSTANCE21 " , exclude = ( WatsonTestModel2 . objects . filter (
2011-08-27 17:38:44 +00:00
title__icontains = " MODEL2 " ,
) , ) ) . count ( ) , 0 )
2011-08-28 12:42:47 +00:00
def testKitchenSink ( self ) :
""" For sanity, let ' s just test everything together in one giant search of doom! """
2012-02-28 14:15:25 +00:00
self . assertEqual ( watson . search (
2011-08-28 12:42:47 +00:00
" INSTANCE11 " ,
models = (
2011-09-15 11:22:37 +00:00
WatsonTestModel1 . objects . filter ( title__icontains = " INSTANCE11 " ) ,
WatsonTestModel2 . objects . filter ( title__icontains = " TITLE " ) ,
2011-08-28 12:42:47 +00:00
) ,
exclude = (
2011-09-15 11:22:37 +00:00
WatsonTestModel1 . objects . filter ( title__icontains = " MODEL2 " ) ,
WatsonTestModel2 . objects . filter ( title__icontains = " MODEL1 " ) ,
2011-08-28 12:42:47 +00:00
)
) . get ( ) . title , " title model1 instance11 " )
2011-08-21 18:05:34 +00:00
class LiveFilterSearchTest ( SearchTest ) :
2011-08-21 20:12:28 +00:00
2011-09-15 11:22:37 +00:00
model1 = WatsonTestModel1 . objects . filter ( is_published = True )
2011-08-29 15:47:40 +00:00
2011-09-15 11:22:37 +00:00
model2 = WatsonTestModel2 . objects . filter ( is_published = True )
2011-08-21 20:25:10 +00:00
def testUnpublishedModelsNotFound ( self ) :
# Make sure that there are four to find!
2011-08-23 16:12:35 +00:00
self . assertEqual ( watson . search ( " tItle Content Description " ) . count ( ) , 4 )
2011-08-21 20:25:10 +00:00
# Unpublish two objects.
2012-03-07 22:43:11 +00:00
self . test11 . is_published = False
self . test11 . save ( )
self . test21 . is_published = False
self . test21 . save ( )
2011-08-21 20:25:10 +00:00
# This should return 4, but two of them are unpublished.
2011-08-27 17:45:43 +00:00
self . assertEqual ( watson . search ( " tItle Content Description " ) . count ( ) , 2 )
def testCanOverridePublication ( self ) :
# Unpublish two objects.
2012-03-07 22:43:11 +00:00
self . test11 . is_published = False
self . test11 . save ( )
2011-08-27 17:45:43 +00:00
# This should still return 4, since we're overriding the publication.
2011-09-15 11:22:37 +00:00
self . assertEqual ( watson . search ( " tItle Content Description " , models = ( WatsonTestModel2 , WatsonTestModel1 . _base_manager . all ( ) , ) ) . count ( ) , 4 )
2011-08-29 10:10:09 +00:00
class RankingTest ( SearchTestBase ) :
2011-08-29 10:18:53 +00:00
def setUp ( self ) :
super ( RankingTest , self ) . setUp ( )
2011-08-29 13:08:16 +00:00
self . test11 . title + = " fooo baar fooo "
2011-08-29 10:18:53 +00:00
self . test11 . save ( )
2011-08-29 18:18:27 +00:00
self . test12 . content + = " fooo baar "
2011-08-29 10:18:53 +00:00
self . test12 . save ( )
2011-08-29 10:10:09 +00:00
def testRankingParamPresentOnSearch ( self ) :
self . assertGreater ( watson . search ( " TITLE " ) [ 0 ] . watson_rank , 0 )
def testRankingParamPresentOnFilter ( self ) :
2011-09-15 11:22:37 +00:00
self . assertGreater ( watson . filter ( WatsonTestModel1 , " TITLE " ) [ 0 ] . watson_rank , 0 )
2011-08-29 10:10:09 +00:00
def testRankingParamAbsentOnSearch ( self ) :
self . assertRaises ( AttributeError , lambda : watson . search ( " TITLE " , ranking = False ) [ 0 ] . watson_rank )
def testRankingParamAbsentOnFilter ( self ) :
2011-09-15 11:22:37 +00:00
self . assertRaises ( AttributeError , lambda : watson . filter ( WatsonTestModel1 , " TITLE " , ranking = False ) [ 0 ] . watson_rank )
2011-08-29 10:18:53 +00:00
@skipUnless ( get_backend ( ) . supports_ranking , " search backend does not support ranking " )
def testRankingWithSearch ( self ) :
self . assertEqual (
2011-08-29 13:08:16 +00:00
[ entry . title for entry in watson . search ( " FOOO " ) ] ,
2013-05-02 14:50:16 +00:00
[ " title model1 instance11 fooo baar fooo " , " title model1 instance12 " ]
2011-08-29 10:18:53 +00:00
)
@skipUnless ( get_backend ( ) . supports_ranking , " search backend does not support ranking " )
def testRankingWithFilter ( self ) :
self . assertEqual (
2011-09-15 11:22:37 +00:00
[ entry . title for entry in watson . filter ( WatsonTestModel1 , " FOOO " ) ] ,
2013-05-02 14:50:16 +00:00
[ " title model1 instance11 fooo baar fooo " , " title model1 instance12 " ]
2011-08-29 10:36:34 +00:00
)
2011-08-29 10:51:40 +00:00
class ComplexRegistrationTest ( SearchTestBase ) :
def testMetaStored ( self ) :
self . assertEqual ( complex_registration_search_engine . search ( " instance11 " ) [ 0 ] . meta [ " is_published " ] , True )
def testMetaNotStored ( self ) :
self . assertRaises ( KeyError , lambda : complex_registration_search_engine . search ( " instance21 " ) [ 0 ] . meta [ " is_published " ] )
def testFieldsExcludedOnSearch ( self ) :
self . assertEqual ( complex_registration_search_engine . search ( " TITLE " ) . count ( ) , 4 )
self . assertEqual ( complex_registration_search_engine . search ( " CONTENT " ) . count ( ) , 0 )
self . assertEqual ( complex_registration_search_engine . search ( " DESCRIPTION " ) . count ( ) , 0 )
def testFieldsExcludedOnFilter ( self ) :
2011-09-15 11:22:37 +00:00
self . assertEqual ( complex_registration_search_engine . filter ( WatsonTestModel1 , " TITLE " ) . count ( ) , 2 )
self . assertEqual ( complex_registration_search_engine . filter ( WatsonTestModel1 , " CONTENT " ) . count ( ) , 0 )
self . assertEqual ( complex_registration_search_engine . filter ( WatsonTestModel1 , " DESCRIPTION " ) . count ( ) , 0 )
self . assertEqual ( complex_registration_search_engine . filter ( WatsonTestModel2 , " TITLE " ) . count ( ) , 2 )
self . assertEqual ( complex_registration_search_engine . filter ( WatsonTestModel2 , " CONTENT " ) . count ( ) , 0 )
self . assertEqual ( complex_registration_search_engine . filter ( WatsonTestModel2 , " DESCRIPTION " ) . count ( ) , 0 )
2011-08-29 10:51:40 +00:00
2011-09-15 11:22:37 +00:00
class WatsonTestModel1Admin ( watson . SearchAdmin ) :
2011-08-29 13:37:19 +00:00
2011-08-29 13:57:55 +00:00
search_fields = ( " title " , " description " , " content " , )
2011-08-29 13:37:19 +00:00
list_display = ( " title " , )
2011-09-15 11:22:37 +00:00
admin . site . register ( WatsonTestModel1 , WatsonTestModel1Admin )
2011-08-29 13:37:19 +00:00
2011-09-06 16:42:06 +00:00
urlpatterns = patterns ( " " ,
2011-08-29 10:36:34 +00:00
2011-09-06 16:42:06 +00:00
url ( " ^simple/ " , include ( " watson.urls " ) ) ,
2011-08-29 10:36:34 +00:00
2011-09-06 16:42:06 +00:00
url ( " ^custom/ " , include ( " watson.urls " ) , kwargs = {
2011-08-29 13:08:16 +00:00
" query_param " : " fooo " ,
2011-08-29 10:36:34 +00:00
" empty_query_redirect " : " /simple/ " ,
2011-08-30 09:53:33 +00:00
" extra_context " : {
" foo " : " bar " ,
" foo2 " : lambda : " bar2 " ,
2011-08-30 10:22:39 +00:00
} ,
" paginate_by " : 10 ,
2011-08-29 10:36:34 +00:00
} ) ,
2011-08-29 13:37:19 +00:00
url ( " ^admin/ " , include ( admin . site . urls ) ) ,
2011-08-29 10:36:34 +00:00
)
2011-08-29 13:57:55 +00:00
2011-09-08 15:53:07 +00:00
def handler404 ( request ) :
return HttpResponseNotFound ( " Not found " )
def handler500 ( request ) :
return HttpResponseServerError ( " Server error " )
2011-08-29 13:57:55 +00:00
class AdminIntegrationTest ( SearchTestBase ) :
urls = " watson.tests "
def setUp ( self ) :
2012-04-24 10:08:35 +00:00
self . old_TEMPLATE_DIRS = settings . TEMPLATE_DIRS
settings . TEMPLATE_DIRS = (
os . path . join ( os . path . dirname ( admin . __file__ ) , " templates " ) ,
)
2011-08-29 13:57:55 +00:00
super ( AdminIntegrationTest , self ) . setUp ( )
self . user = User (
username = " foo " ,
is_staff = True ,
is_superuser = True ,
)
self . user . set_password ( " bar " )
self . user . save ( )
2011-08-30 09:53:33 +00:00
@skipUnless ( " django.contrib.admin " in settings . INSTALLED_APPS , " Django admin site not installed " )
2011-08-29 13:57:55 +00:00
def testAdminIntegration ( self ) :
2012-04-24 10:11:40 +00:00
# Log the user in.
if hasattr ( self , " settings " ) :
with self . settings ( INSTALLED_APPS = tuple ( set ( tuple ( settings . INSTALLED_APPS ) + ( " django.contrib.sessions " , ) ) ) ) : # HACK: Without this the client won't log in, for some reason.
self . client . login (
username = " foo " ,
password = " bar " ,
)
else :
self . client . login (
username = " foo " ,
password = " bar " ,
)
2011-09-08 15:56:31 +00:00
# Test a search with no query.
2011-09-15 11:22:37 +00:00
response = self . client . get ( " /admin/auth/watsontestmodel1/ " )
2011-09-08 15:56:31 +00:00
self . assertContains ( response , " instance11 " )
self . assertContains ( response , " instance12 " )
self . assertContains ( response , " searchbar " ) # Ensure that the search bar renders.
2011-08-29 13:57:55 +00:00
# Test a search for all the instances.
2011-09-15 11:22:37 +00:00
response = self . client . get ( " /admin/auth/watsontestmodel1/?q=title content description " )
2011-08-29 13:57:55 +00:00
self . assertContains ( response , " instance11 " )
self . assertContains ( response , " instance12 " )
# Test a search for half the instances.
2011-09-15 11:22:37 +00:00
response = self . client . get ( " /admin/auth/watsontestmodel1/?q=instance11 " )
2011-08-29 13:57:55 +00:00
self . assertContains ( response , " instance11 " )
self . assertNotContains ( response , " instance12 " )
def tearDown ( self ) :
super ( AdminIntegrationTest , self ) . tearDown ( )
self . user . delete ( )
del self . user
2012-04-24 10:08:35 +00:00
settings . TEMPLATE_DIRS = self . old_TEMPLATE_DIRS
2011-08-29 10:36:34 +00:00
class SiteSearchTest ( SearchTestBase ) :
urls = " watson.tests "
2012-04-30 09:41:27 +00:00
def setUp ( self ) :
self . old_TEMPLATE_DIRS = settings . TEMPLATE_DIRS
settings . TEMPLATE_DIRS = (
os . path . join ( os . path . dirname ( admin . __file__ ) , " templates " ) ,
)
super ( SiteSearchTest , self ) . setUp ( )
2011-08-29 10:36:34 +00:00
def testSiteSearch ( self ) :
# Test a search than should find everything.
response = self . client . get ( " /simple/?q=title " )
self . assertContains ( response , " instance11 " )
self . assertContains ( response , " instance12 " )
self . assertContains ( response , " instance21 " )
self . assertContains ( response , " instance22 " )
2011-08-29 17:20:58 +00:00
self . assertTemplateUsed ( response , " watson/search_results.html " )
2011-08-29 10:36:34 +00:00
# Test a search that should find one thing.
response = self . client . get ( " /simple/?q=instance11 " )
self . assertContains ( response , " instance11 " )
self . assertNotContains ( response , " instance12 " )
self . assertNotContains ( response , " instance21 " )
self . assertNotContains ( response , " instance22 " )
# Test a search that should find nothing.
2011-08-29 13:08:16 +00:00
response = self . client . get ( " /simple/?q=fooo " )
2011-08-29 10:36:34 +00:00
self . assertNotContains ( response , " instance11 " )
self . assertNotContains ( response , " instance12 " )
self . assertNotContains ( response , " instance21 " )
self . assertNotContains ( response , " instance22 " )
2011-09-06 16:42:06 +00:00
def testSiteSearchJSON ( self ) :
# Test a search that should find everything.
response = self . client . get ( " /simple/json/?q=title " )
self . assertEqual ( response [ " Content-Type " ] , " application/json; charset=utf-8 " )
2013-05-01 16:08:09 +00:00
results = set ( result [ " title " ] for result in json . loads ( force_text ( response . content ) ) [ " results " ] )
2011-09-06 16:42:06 +00:00
self . assertEqual ( len ( results ) , 4 )
self . assertTrue ( " title model1 instance11 " in results )
self . assertTrue ( " title model1 instance12 " in results )
self . assertTrue ( " title model2 instance21 " in results )
self . assertTrue ( " title model2 instance22 " in results )
2011-08-29 10:36:34 +00:00
def testSiteSearchCustom ( self ) :
# Test a search than should find everything.
2011-08-29 13:08:16 +00:00
response = self . client . get ( " /custom/?fooo=title " )
2011-08-29 10:36:34 +00:00
self . assertContains ( response , " instance11 " )
self . assertContains ( response , " instance12 " )
self . assertContains ( response , " instance21 " )
self . assertContains ( response , " instance22 " )
2011-08-29 17:20:58 +00:00
self . assertTemplateUsed ( response , " watson/search_results.html " )
2011-08-30 09:53:33 +00:00
# Test that the extra context is included.
self . assertEqual ( response . context [ " foo " ] , " bar " )
self . assertEqual ( response . context [ " foo2 " ] , " bar2 " )
2011-08-30 10:22:39 +00:00
# Test that pagination is included.
self . assertEqual ( response . context [ " paginator " ] . num_pages , 1 )
self . assertEqual ( response . context [ " page_obj " ] . number , 1 )
self . assertEqual ( response . context [ " search_results " ] , response . context [ " page_obj " ] . object_list )
# Test a request for an empty page.
try :
response = self . client . get ( " /custom/?fooo=title&page=10 " )
except template . TemplateDoesNotExist as ex :
# No 404 template defined.
2011-09-05 11:06:57 +00:00
self . assertEqual ( ex . args [ 0 ] , " 404.html " )
2011-08-30 10:22:39 +00:00
else :
self . assertEqual ( response . status_code , 404 )
# Test a requet for the last page.
response = self . client . get ( " /custom/?fooo=title&page=last " )
self . assertEqual ( response . context [ " paginator " ] . num_pages , 1 )
self . assertEqual ( response . context [ " page_obj " ] . number , 1 )
self . assertEqual ( response . context [ " search_results " ] , response . context [ " page_obj " ] . object_list )
2011-08-29 10:36:34 +00:00
# Test a search that should find nothing.
2011-08-29 13:08:16 +00:00
response = self . client . get ( " /custom/?q=fooo " )
2011-09-06 16:42:06 +00:00
self . assertRedirects ( response , " /simple/ " )
def testSiteSearchCustomJSON ( self ) :
# Test a search that should find everything.
response = self . client . get ( " /custom/json/?fooo=title&page=last " )
self . assertEqual ( response [ " Content-Type " ] , " application/json; charset=utf-8 " )
2013-05-01 16:08:09 +00:00
results = set ( result [ " title " ] for result in json . loads ( force_text ( response . content ) ) [ " results " ] )
2011-09-06 16:42:06 +00:00
self . assertEqual ( len ( results ) , 4 )
self . assertTrue ( " title model1 instance11 " in results )
self . assertTrue ( " title model1 instance12 " in results )
self . assertTrue ( " title model2 instance21 " in results )
self . assertTrue ( " title model2 instance22 " in results )
# Test a search with an invalid page.
response = self . client . get ( " /custom/json/?fooo=title&page=200 " )
2012-05-08 11:36:38 +00:00
self . assertEqual ( response . status_code , 404 )
2012-04-30 09:41:27 +00:00
def tearDown ( self ) :
super ( SiteSearchTest , self ) . tearDown ( )
2013-05-01 16:08:09 +00:00
settings . TEMPLATE_DIRS = self . old_TEMPLATE_DIRS