diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java index edcfc4ccb..077ac1843 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/CoreShibUiConfiguration.java @@ -9,12 +9,14 @@ import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.document.Document; import org.apache.lucene.index.DirectoryReader; +import org.apache.lucene.index.IndexWriter; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.Directory; +import org.apache.lucene.store.RAMDirectory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -28,7 +30,9 @@ import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; @Configuration public class CoreShibUiConfiguration { @@ -76,8 +80,7 @@ public AttributeUtility attributeUtility() { Analyzer fullTokenAnalyzer; @Autowired - Directory directory; - + DirectoryService directoryService; @Bean public EntityDescriptorFilesScheduledTasks entityDescriptorFilesScheduledTasks(EntityDescriptorRepository entityDescriptorRepository) { @@ -86,8 +89,9 @@ public EntityDescriptorFilesScheduledTasks entityDescriptorFilesScheduledTasks(E @Bean public EntityIdsSearchService entityIdsSearchService() { - return (term, limit) -> { + return (resourceId, term, limit) -> { List entityIds = new ArrayList<>(); + Directory directory = directoryService.getDirectory(resourceId); try { IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(directory)); QueryParser parser = new QueryParser("content", fullTokenAnalyzer); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverConfiguration.java index 1968841c1..cdcd54f02 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/MetadataResolverConfiguration.java @@ -2,6 +2,7 @@ import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects; import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository; +import edu.internet2.tier.shibboleth.admin.ui.service.IndexWriterService; import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.resolver.ResolverException; import org.apache.http.HttpResponse; @@ -38,7 +39,7 @@ public class MetadataResolverConfiguration { OpenSamlObjects openSamlObjects; @Autowired - IndexWriter indexWriter; + IndexWriterService indexWriterService; @Autowired MetadataResolverRepository metadataResolverRepository; @@ -50,13 +51,22 @@ public MetadataResolver metadataResolver() throws ResolverException, ComponentIn List resolvers = new ArrayList<>(); + String incommonMRId = "incommonmd"; // TODO: remove this later when we allow for creation of arbitrary metadata resolvers FileBackedHTTPMetadataResolver incommonMR = new FileBackedHTTPMetadataResolver(HttpClients.createMinimal(), "http://md.incommon.org/InCommon/InCommon-metadata.xml", "/tmp/incommonmd.xml"){ @Override protected void initMetadataResolver() throws ComponentInitializationException { super.initMetadataResolver(); + IndexWriter indexWriter; + try { + indexWriter = indexWriterService.getIndexWriter(incommonMRId); + } catch (IOException e) { + throw new ComponentInitializationException(e); + } + for (String entityId: this.getBackingStore().getIndexedDescriptors().keySet()) { + Document document = new Document(); document.add(new StringField("id", entityId, Field.Store.YES)); document.add(new TextField("content", entityId, Field.Store.YES)); // TODO: change entityId to be content of entity descriptor block @@ -86,7 +96,7 @@ protected void processConditionalRetrievalHeaders(HttpResponse response) { // let's do nothing 'cause we want to allow a refresh } }; - incommonMR.setId("incommonmd"); + incommonMR.setId(incommonMRId); incommonMR.setParserPool(openSamlObjects.getParserPool()); incommonMR.setMetadataFilter(new MetadataFilterChain()); incommonMR.initialize(); diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/SearchConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/SearchConfiguration.java index ac5d1efb7..0ae1cc79f 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/SearchConfiguration.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/SearchConfiguration.java @@ -1,5 +1,7 @@ package edu.internet2.tier.shibboleth.admin.ui.configuration; +import edu.internet2.tier.shibboleth.admin.ui.service.DirectoryService; +import edu.internet2.tier.shibboleth.admin.ui.service.IndexWriterService; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.LowerCaseFilter; import org.apache.lucene.analysis.StopFilter; @@ -11,17 +13,18 @@ import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.store.Directory; import org.apache.lucene.store.RAMDirectory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; @Configuration public class SearchConfiguration { - @Bean - Directory directory() { - return new RAMDirectory(); - } + @Autowired + DirectoryService directoryService; @Bean Analyzer analyzer() { @@ -54,10 +57,37 @@ protected TokenStreamComponents createComponents(String fieldName) { }; } - @Bean - IndexWriter indexWriter() throws IOException { + private IndexWriter createIndexWriter(Directory directory) throws IOException { IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer()); indexWriterConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND); - return new IndexWriter(directory(), indexWriterConfig); + return new IndexWriter(directory, indexWriterConfig); + } + + @Bean + public IndexWriterService indexWriterService() { + Map indexWriterMap = new HashMap<>(); + + return resourceId -> { + IndexWriter indexWriter = indexWriterMap.get(resourceId); + if (indexWriter == null) { + indexWriter = createIndexWriter(directoryService.getDirectory(resourceId)); + indexWriterMap.put(resourceId, indexWriter); + } + return indexWriter; + }; + } + + @Bean + public DirectoryService directoryService() { + Map directoryMap = new HashMap<>(); + + return resourceId -> { + Directory directory = directoryMap.get(resourceId); + if (directory == null) { + directory = new RAMDirectory(); + directoryMap.put(resourceId, directory); + } + return directory; + }; } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityIdsSearchController.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityIdsSearchController.java index 643e626f4..8728b838d 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityIdsSearchController.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/controller/EntityIdsSearchController.java @@ -18,10 +18,13 @@ public EntityIdsSearchController(EntityIdsSearchService entityIdsSearchService) this.entityIdsSearchService = entityIdsSearchService; } + // TODO Change this to include a metadata resolver id so we can pull out the right index to search @GetMapping - ResponseEntity search(@RequestParam String term, @RequestParam(required = false) Integer limit) { + ResponseEntity search(@RequestParam String resourceId, + @RequestParam String term, + @RequestParam(required = false) Integer limit) { //Zero indicates no-limit final int resultLimit = (limit != null ? limit : 10); - return ResponseEntity.ok(this.entityIdsSearchService.findBySearchTermAndOptionalLimit(term, resultLimit)); + return ResponseEntity.ok(this.entityIdsSearchService.findBySearchTermAndOptionalLimit(resourceId, term, resultLimit)); } } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/DirectoryService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/DirectoryService.java new file mode 100644 index 000000000..720a64ca0 --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/DirectoryService.java @@ -0,0 +1,16 @@ +package edu.internet2.tier.shibboleth.admin.ui.service; + +import org.apache.lucene.store.Directory; + +/** + * API component responsible for entity ids search. + */ +@FunctionalInterface +public interface DirectoryService { + /** + * Return a Directory for a given resource id. If one is not found, it will be created. + * @param resourceId the resource to get the Directory for + * @return Directory + */ + Directory getDirectory(String resourceId); +} diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/EntityIdsSearchService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/EntityIdsSearchService.java index 81b8a4b1c..6639d5b1a 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/EntityIdsSearchService.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/EntityIdsSearchService.java @@ -15,9 +15,10 @@ public interface EntityIdsSearchService { /** * Find a list of entity ids + * @param resourceId the id of the resource to search within * @param searchTerm for the query * @param limit optional limit of query results to return. Zero or less value indicates no limit. * @return EntityIdsSearchResultRepresentation */ - EntityIdsSearchResultRepresentation findBySearchTermAndOptionalLimit(String searchTerm, int limit); + EntityIdsSearchResultRepresentation findBySearchTermAndOptionalLimit(String resourceId, String searchTerm, int limit); } diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/IndexWriterService.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/IndexWriterService.java new file mode 100644 index 000000000..1e314ca4b --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/service/IndexWriterService.java @@ -0,0 +1,18 @@ +package edu.internet2.tier.shibboleth.admin.ui.service; + +import org.apache.lucene.index.IndexWriter; + +import java.io.IOException; + +/** + * API component responsible for entity ids search. + */ +@FunctionalInterface +public interface IndexWriterService { + /** + * Return a (possibly cached) index writer for a given resource id. + * @param resourceId the resource to create the IndexWriter for + * @return IndexWriter + */ + IndexWriter getIndexWriter(String resourceId) throws IOException; +} diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestConfiguration.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestConfiguration.groovy index 73cf58307..2cb3c7d9d 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestConfiguration.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/configuration/TestConfiguration.groovy @@ -2,6 +2,7 @@ package edu.internet2.tier.shibboleth.admin.ui.configuration import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository +import edu.internet2.tier.shibboleth.admin.ui.service.IndexWriterService import net.shibboleth.ext.spring.resource.ResourceHelper import net.shibboleth.utilities.java.support.component.ComponentInitializationException import org.apache.lucene.document.Document @@ -14,20 +15,22 @@ import org.opensaml.saml.metadata.resolver.MetadataResolver import org.opensaml.saml.metadata.resolver.impl.ResourceBackedMetadataResolver import org.slf4j.Logger import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.core.io.ClassPathResource @Configuration class TestConfiguration { + @Autowired + IndexWriterService indexWriterService + final OpenSamlObjects openSamlObjects - final IndexWriter indexWriter final MetadataResolverRepository metadataResolverRepository final Logger logger = LoggerFactory.getLogger(TestConfiguration.class); - TestConfiguration(final OpenSamlObjects openSamlObjects, final IndexWriter indexWriter, final MetadataResolverRepository metadataResolverRepository) { + TestConfiguration(final OpenSamlObjects openSamlObjects, final MetadataResolverRepository metadataResolverRepository) { this.openSamlObjects =openSamlObjects - this.indexWriter = indexWriter this.metadataResolverRepository = metadataResolverRepository } @@ -35,6 +38,9 @@ class TestConfiguration { MetadataResolver metadataResolver() { ChainingMetadataResolver metadataResolver = new ChainingMetadataResolver() metadataResolver.setId("chain") + String resolverId = "test" + + IndexWriter indexWriter = indexWriterService.getIndexWriter(resolverId) def shortIncommon = new ResourceBackedMetadataResolver(ResourceHelper.of(new ClassPathResource('/metadata/incommon-short.xml'))){ @Override @@ -58,7 +64,7 @@ class TestConfiguration { } } }.with { - it.id = 'test' + it.id = resolverId TestConfiguration p = owner it.parserPool = p.openSamlObjects.parserPool it.initialize() diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityIdsSearchControllerTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityIdsSearchControllerTests.groovy index a24ed433f..77ea5ddd0 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityIdsSearchControllerTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntityIdsSearchControllerTests.groovy @@ -25,11 +25,14 @@ class EntityIdsSearchControllerTests extends Specification { def mockMvc = MockMvcBuilders.standaloneSetup(controller).build() + static final String RESOURCE_ID = "resourceId" + static final String RESOURCE_ID_VALUE = "test" + static final String TERM = "term" + static final String LIMIT = "limit" + def "GET /api/EntityIds/search with unicon and limit 5"() { given: - def term = "term" def termValue = "unicon" - def limit = "limit" def limitValue = "5" def expectedEntityIdsFromSearchService = new EntityIdsSearchResultRepresentation(["http://unicon.instructure.com/saml2", "https://idp.unicon.net/idp/shibboleth"]) def expectedHttpResponseStatus = status().isOk() @@ -45,12 +48,13 @@ class EntityIdsSearchControllerTests extends Specification { when: def result = mockMvc.perform(get('/api/EntityIds/search') - .param(term, termValue) - .param(limit, limitValue)) + .param(RESOURCE_ID, RESOURCE_ID_VALUE) + .param(TERM, termValue) + .param(LIMIT, limitValue)) then: result.andExpect(expectedHttpResponseStatus) - 1 * entityIdsSearchService.findBySearchTermAndOptionalLimit(termValue, Integer.valueOf(limitValue)) >> expectedEntityIdsFromSearchService + 1 * entityIdsSearchService.findBySearchTermAndOptionalLimit(RESOURCE_ID_VALUE, termValue, Integer.valueOf(limitValue)) >> expectedEntityIdsFromSearchService result.andExpect(expectedHttpResponseStatus) .andExpect(content().contentType(expectedResponseContentType)) .andExpect(content().json(expectedResponseBody, true)) @@ -58,9 +62,7 @@ class EntityIdsSearchControllerTests extends Specification { def "GET /api/EntityIds/search with unicon and limit 1"() { given: - def term = "term" def termValue = "unicon" - def limit = "limit" def limitValue = "1" def expectedEntityIdsFromSearchService = new EntityIdsSearchResultRepresentation(["http://unicon.instructure.com/saml2"]) def expectedHttpResponseStatus = status().isOk() @@ -75,12 +77,13 @@ class EntityIdsSearchControllerTests extends Specification { when: def result = mockMvc.perform(get('/api/EntityIds/search') - .param(term, termValue) - .param(limit, limitValue)) + .param(RESOURCE_ID, RESOURCE_ID_VALUE) + .param(TERM, termValue) + .param(LIMIT, limitValue)) then: result.andExpect(expectedHttpResponseStatus) - 1 * entityIdsSearchService.findBySearchTermAndOptionalLimit(termValue, Integer.valueOf(limitValue)) >> expectedEntityIdsFromSearchService + 1 * entityIdsSearchService.findBySearchTermAndOptionalLimit(RESOURCE_ID_VALUE, termValue, Integer.valueOf(limitValue)) >> expectedEntityIdsFromSearchService result.andExpect(expectedHttpResponseStatus) .andExpect(content().contentType(expectedResponseContentType)) .andExpect(content().json(expectedResponseBody, true)) @@ -88,9 +91,7 @@ class EntityIdsSearchControllerTests extends Specification { def "GET /api/EntityIds/search with shib and no limit"() { given: - def term = "term" def termValue = "shib" - def limit = "limit" def limitValue = NO_LIMIT def expectedEntityIdsFromSearchService = new EntityIdsSearchResultRepresentation(["https://shib.ucanr.org/shibboleth", "https://shibboleth2sp.tf.semcs.net/shibboleth", @@ -123,11 +124,12 @@ class EntityIdsSearchControllerTests extends Specification { when: def result = mockMvc.perform(get('/api/EntityIds/search') - .param(term, termValue)) + .param(RESOURCE_ID, RESOURCE_ID_VALUE) + .param(TERM, termValue)) then: result.andExpect(expectedHttpResponseStatus) - 1 * entityIdsSearchService.findBySearchTermAndOptionalLimit(termValue, Integer.valueOf(limitValue)) >> expectedEntityIdsFromSearchService + 1 * entityIdsSearchService.findBySearchTermAndOptionalLimit(RESOURCE_ID_VALUE, termValue, Integer.valueOf(limitValue)) >> expectedEntityIdsFromSearchService result.andExpect(expectedHttpResponseStatus) .andExpect(content().contentType(expectedResponseContentType)) .andExpect(content().json(expectedResponseBody, true)) @@ -135,9 +137,7 @@ class EntityIdsSearchControllerTests extends Specification { def "GET /api/EntityIds/search with empty term and limit 5"() { given: - def term = "term" def termValue = "" - def limit = "limit" def limitValue = "5" def expectedEntityIdsFromSearchService = new EntityIdsSearchResultRepresentation([]) def expectedHttpResponseStatus = status().isOk() @@ -150,12 +150,13 @@ class EntityIdsSearchControllerTests extends Specification { when: def result = mockMvc.perform(get('/api/EntityIds/search') - .param(term, termValue) - .param(limit, limitValue)) + .param(RESOURCE_ID, RESOURCE_ID_VALUE) + .param(TERM, termValue) + .param(LIMIT, limitValue)) then: result.andExpect(expectedHttpResponseStatus) - 1 * entityIdsSearchService.findBySearchTermAndOptionalLimit(termValue, Integer.valueOf(limitValue)) >> expectedEntityIdsFromSearchService + 1 * entityIdsSearchService.findBySearchTermAndOptionalLimit(RESOURCE_ID_VALUE, termValue, Integer.valueOf(limitValue)) >> expectedEntityIdsFromSearchService result.andExpect(expectedHttpResponseStatus) .andExpect(content().contentType(expectedResponseContentType)) .andExpect(content().json(expectedResponseBody, true)) @@ -163,9 +164,7 @@ class EntityIdsSearchControllerTests extends Specification { def "GET /api/EntityIds/search with empty term and no limit"() { given: - def term = "term" def termValue = "" - def limit = "limit" def limitValue = NO_LIMIT def expectedEntityIdsFromSearchService = new EntityIdsSearchResultRepresentation([]) def expectedHttpResponseStatus = status().isOk() @@ -178,12 +177,13 @@ class EntityIdsSearchControllerTests extends Specification { when: def result = mockMvc.perform(get('/api/EntityIds/search') - .param(term, termValue) - .param(limit, limitValue)) + .param(RESOURCE_ID, RESOURCE_ID_VALUE) + .param(TERM, termValue) + .param(LIMIT, limitValue)) then: result.andExpect(expectedHttpResponseStatus) - 1 * entityIdsSearchService.findBySearchTermAndOptionalLimit(termValue, Integer.valueOf(limitValue)) >> expectedEntityIdsFromSearchService + 1 * entityIdsSearchService.findBySearchTermAndOptionalLimit(RESOURCE_ID_VALUE, termValue, Integer.valueOf(limitValue)) >> expectedEntityIdsFromSearchService result.andExpect(expectedHttpResponseStatus) .andExpect(content().contentType(expectedResponseContentType)) .andExpect(content().json(expectedResponseBody, true)) diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/EntityIdsSearchServiceTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/EntityIdsSearchServiceTests.groovy index 55777e6ec..833e67156 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/EntityIdsSearchServiceTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/service/EntityIdsSearchServiceTests.groovy @@ -22,6 +22,8 @@ class EntityIdsSearchServiceTests extends Specification { @Autowired EntityIdsSearchService entityIdsSearchService + def test = "test" + def "searching for carmen produces one result"() { setup: def searchTerm = "carmen" @@ -30,7 +32,7 @@ class EntityIdsSearchServiceTests extends Specification { def expectedResultItem = "https://carmenwiki.osu.edu/shibboleth" when: - def actualResults = entityIdsSearchService.findBySearchTermAndOptionalLimit(searchTerm, searchLimit) + def actualResults = entityIdsSearchService.findBySearchTermAndOptionalLimit(test, searchTerm, searchLimit) then: expectedResultSize == actualResults.entityIds.size() @@ -45,7 +47,7 @@ class EntityIdsSearchServiceTests extends Specification { def expectedResults = Arrays.asList(["http://unicon.instructure.com/saml2", "https://idp.unicon.net/idp/shibboleth"]) when: - def actualResults = entityIdsSearchService.findBySearchTermAndOptionalLimit(searchTerm, searchLimit) + def actualResults = entityIdsSearchService.findBySearchTermAndOptionalLimit(test, searchTerm, searchLimit) then: expectedResultSize == actualResults.entityIds.size() @@ -59,7 +61,7 @@ class EntityIdsSearchServiceTests extends Specification { def expectedResultSize = 0 when: - def actualResults = entityIdsSearchService.findBySearchTermAndOptionalLimit(searchTerm, searchLimit) + def actualResults = entityIdsSearchService.findBySearchTermAndOptionalLimit(test, searchTerm, searchLimit) then: expectedResultSize == actualResults.entityIds.size() @@ -73,7 +75,7 @@ class EntityIdsSearchServiceTests extends Specification { def expectedResults = Arrays.asList(["http://unicon.instructure.com/saml2"]) when: - def actualResults = entityIdsSearchService.findBySearchTermAndOptionalLimit(searchTerm, searchLimit) + def actualResults = entityIdsSearchService.findBySearchTermAndOptionalLimit(test, searchTerm, searchLimit) then: expectedResultSize == actualResults.entityIds.size() @@ -86,7 +88,7 @@ class EntityIdsSearchServiceTests extends Specification { def searchLimit = 0 when: - entityIdsSearchService.findBySearchTermAndOptionalLimit(searchTerm, searchLimit) + entityIdsSearchService.findBySearchTermAndOptionalLimit(test, searchTerm, searchLimit) then: thrown IllegalArgumentException