From 354136dc94d1963384573d2f2728f1fb408f3d9a Mon Sep 17 00:00:00 2001 From: Henning Baldersheim Date: Mon, 11 Mar 2024 15:51:38 +0100 Subject: Rename FastBackend => Indexedbackend, and move some tests into the package they test. --- .../fastsearch/DocsumDefinitionTestCase.java | 82 +++++++++ .../prelude/fastsearch/IndexedBackendTestCase.java | 199 ++++++++++++++++++++ .../prelude/fastsearch/PartialFillTestCase.java | 140 ++++++++++++++ .../fastsearch/test/DocsumDefinitionTestCase.java | 90 --------- .../fastsearch/test/FastSearcherTestCase.java | 204 --------------------- .../fastsearch/test/PartialFillTestCase.java | 150 --------------- 6 files changed, 421 insertions(+), 444 deletions(-) create mode 100644 container-search/src/test/java/com/yahoo/prelude/fastsearch/DocsumDefinitionTestCase.java create mode 100644 container-search/src/test/java/com/yahoo/prelude/fastsearch/IndexedBackendTestCase.java create mode 100644 container-search/src/test/java/com/yahoo/prelude/fastsearch/PartialFillTestCase.java delete mode 100644 container-search/src/test/java/com/yahoo/prelude/fastsearch/test/DocsumDefinitionTestCase.java delete mode 100644 container-search/src/test/java/com/yahoo/prelude/fastsearch/test/FastSearcherTestCase.java delete mode 100644 container-search/src/test/java/com/yahoo/prelude/fastsearch/test/PartialFillTestCase.java (limited to 'container-search/src/test') diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/DocsumDefinitionTestCase.java b/container-search/src/test/java/com/yahoo/prelude/fastsearch/DocsumDefinitionTestCase.java new file mode 100644 index 00000000000..ba9988b865c --- /dev/null +++ b/container-search/src/test/java/com/yahoo/prelude/fastsearch/DocsumDefinitionTestCase.java @@ -0,0 +1,82 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.prelude.fastsearch; + +import com.yahoo.document.GlobalId; +import com.yahoo.search.schema.DocumentSummary; +import com.yahoo.search.schema.Schema; +import com.yahoo.slime.BinaryFormat; +import com.yahoo.slime.Cursor; +import com.yahoo.slime.Slime; +import org.junit.jupiter.api.Test; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Tests docsum class functionality + * + * @author bratseth + */ +public class DocsumDefinitionTestCase { + + @Test + void testDecoding() { + DocsumDefinitionSet set = createDocsumDefinitionSet(); + FastHit hit = new FastHit(); + + set.lazyDecode(null, makeDocsum(), hit); + assertEquals("Arts/Celebrities/Madonna", hit.getField("TOPIC")); + assertEquals("1", hit.getField("EXTINFOSOURCE").toString()); + assertEquals("10", hit.getField("LANG1").toString()); + assertEquals("352", hit.getField("WORDS").toString()); + assertEquals("index:null/0/" + asHexString(hit.getGlobalId()), hit.getId().toString()); + } + + private static String asHexString(GlobalId gid) { + StringBuilder sb = new StringBuilder(); + byte[] rawGid = gid.getRawId(); + for (byte b : rawGid) { + String hex = Integer.toHexString(0xFF & b); + if (hex.length() == 1) + sb.append('0'); + sb.append(hex); + } + return sb.toString(); + } + + public static byte[] makeDocsum() { + Slime slime = new Slime(); + Cursor docsum = slime.setObject(); + docsum.setString("TOPIC", "Arts/Celebrities/Madonna"); + docsum.setString("TITLE", "StudyOfMadonna.com - Interviews, Articles, Reviews, Quotes, Essays and more.."); + docsum.setString("DYNTEASER", "dynamic teaser"); + docsum.setLong("EXTINFOSOURCE", 1); + docsum.setLong("LANG1", 10); + docsum.setLong("WORDS", 352); + docsum.setLong("BYTES", 9190); + byte[] tmp = BinaryFormat.encode(slime); + ByteBuffer buf = ByteBuffer.allocate(tmp.length + 4); + buf.order(ByteOrder.LITTLE_ENDIAN); + buf.putInt(DocsumDefinitionSet.SLIME_MAGIC_ID); + buf.order(ByteOrder.BIG_ENDIAN); + buf.put(tmp); + return buf.array(); + } + + public static DocsumDefinitionSet createDocsumDefinitionSet() { + var schema = new Schema.Builder("test"); + var summary = new DocumentSummary.Builder("default"); + summary.add(new DocumentSummary.Field("TOPIC", "string")); + summary.add(new DocumentSummary.Field("TITLE", "string")); + summary.add(new DocumentSummary.Field("DYNTEASER", "string")); + summary.add(new DocumentSummary.Field("EXTINFOSOURCE", "integer")); + summary.add(new DocumentSummary.Field("LANG1", "integer")); + summary.add(new DocumentSummary.Field("WORDS", "integer")); + summary.add(new DocumentSummary.Field("BYTES", "byte")); + schema.add(summary.build()); + return new DocsumDefinitionSet(schema.build()); + } + +} diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/IndexedBackendTestCase.java b/container-search/src/test/java/com/yahoo/prelude/fastsearch/IndexedBackendTestCase.java new file mode 100644 index 00000000000..917206bf00c --- /dev/null +++ b/container-search/src/test/java/com/yahoo/prelude/fastsearch/IndexedBackendTestCase.java @@ -0,0 +1,199 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.prelude.fastsearch; + +import com.yahoo.container.QrSearchersConfig; +import com.yahoo.container.handler.VipStatus; +import com.yahoo.container.protect.Error; +import com.yahoo.search.Query; +import com.yahoo.search.Result; +import com.yahoo.search.dispatch.MockDispatcher; +import com.yahoo.search.dispatch.rpc.RpcResourcePool; +import com.yahoo.search.dispatch.searchcluster.Node; +import com.yahoo.search.grouping.GroupingRequest; +import com.yahoo.search.grouping.request.AllOperation; +import com.yahoo.search.grouping.request.EachOperation; +import com.yahoo.search.grouping.request.GroupingOperation; +import com.yahoo.search.result.ErrorMessage; +import com.yahoo.search.schema.DocumentSummary; +import com.yahoo.search.schema.RankProfile; +import com.yahoo.search.schema.Schema; +import com.yahoo.search.schema.SchemaInfo; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.*; + + +/** + * Tests the Fast searcher + * + * @author bratseth + */ +public class IndexedBackendTestCase { + private static final String SCHEMA = "test"; + private static final String CLUSTER = "test"; + + @Test + void testNullQuery() { + Logger.getLogger(IndexedBackend.class.getName()).setLevel(Level.ALL); + IndexedBackend fastSearcher = new IndexedBackend("container.0", + MockDispatcher.create(List.of()), + new SummaryParameters(null), + new ClusterParams("testhittype"), + documentdbInfoConfig(SCHEMA), + schemaInfo(SCHEMA)); + + String query = "?junkparam=ignored"; + Result result = doSearch(fastSearcher, new Query(query), 0, 10); + ErrorMessage message = result.hits().getError(); + + assertNotNull(message, "Got error"); + assertEquals("Null query", message.getMessage()); + assertEquals(query, message.getDetailedMessage()); + assertEquals(Error.NULL_QUERY.code, message.getCode()); + } + + private Result doSearch(VespaBackend searcher, Query query, int offset, int hits) { + query.setOffset(offset); + query.setHits(hits); + return searcher.search(SCHEMA, query); + } + + @Test + void testSinglePassGroupingIsForcedWithSingleNodeGroups() { + IndexedBackend fastSearcher = new IndexedBackend("container.0", + MockDispatcher.create(List.of(new Node(CLUSTER, 0, "host0", 0))), + new SummaryParameters(null), + new ClusterParams("testhittype"), + documentdbInfoConfig(SCHEMA), + schemaInfo(SCHEMA)); + Query q = new Query("?query=foo"); + GroupingRequest request1 = GroupingRequest.newInstance(q); + request1.setRootOperation(new AllOperation()); + + GroupingRequest request2 = GroupingRequest.newInstance(q); + AllOperation all = new AllOperation(); + all.addChild(new EachOperation()); + all.addChild(new EachOperation()); + request2.setRootOperation(all); + + assertForceSinglePassIs(false, q); + fastSearcher.search(SCHEMA, q); + assertForceSinglePassIs(true, q); + } + + @Test + void testRankProfileValidation() { + IndexedBackend fastSearcher = new IndexedBackend("container.0", + MockDispatcher.create(List.of(new Node(CLUSTER, 0, "host0", 0))), + new SummaryParameters(null), + new ClusterParams("testhittype"), + documentdbInfoConfig(SCHEMA), + schemaInfo(SCHEMA)); + assertFalse(searchError("?query=q", fastSearcher).contains("does not contain requested rank profile")); + assertFalse(searchError("?query=q&ranking.profile=default", fastSearcher).contains("does not contain requested rank profile")); + assertTrue(searchError("?query=q&ranking.profile=nosuch", fastSearcher).contains("does not contain requested rank profile")); + } + + @Test + void testSummaryNeedsQuery() { + var documentDb = new DocumentdbInfoConfig(new DocumentdbInfoConfig.Builder().documentdb(new DocumentdbInfoConfig.Documentdb.Builder().name(SCHEMA))); + var schema = new Schema.Builder(SCHEMA) + .add(new DocumentSummary.Builder("default").build()) + .add(new RankProfile.Builder("default").setHasRankFeatures(false) + .setHasSummaryFeatures(false) + .build()); + IndexedBackend backend = new IndexedBackend("container.0", + MockDispatcher.create(Collections.singletonList(new Node(CLUSTER, 0, "host0", 0))), + new SummaryParameters(null), + new ClusterParams("testhittype"), + documentDb, + new SchemaInfo(List.of(schema.build()), List.of())); + Query q = new Query("?query=foo"); + Result result = doSearch(backend, q, 0, 10); + assertFalse(backend.summaryNeedsQuery(q)); + + q = new Query("?query=select+*+from+source+where+title+contains+%22foobar%22+and++geoLocation%28myfieldname%2C+63.5%2C+10.5%2C+%22999+km%22%29%3B"); + q.getModel().setType(Query.Type.YQL); + result = doSearch(backend, q, 0, 10); + assertTrue(backend.summaryNeedsQuery(q)); + } + + @Test + void testSinglePassGroupingIsNotForcedWithSingleNodeGroups() { + MockDispatcher dispatcher = MockDispatcher.create(List.of(new Node(CLUSTER, 0, "host0", 0), new Node(CLUSTER, 2, "host1", 0))); + + IndexedBackend fastSearcher = new IndexedBackend("container.0", + dispatcher, + new SummaryParameters(null), + new ClusterParams("testhittype"), + documentdbInfoConfig(SCHEMA), + schemaInfo(SCHEMA)); + Query q = new Query("?query=foo"); + GroupingRequest request1 = GroupingRequest.newInstance(q); + request1.setRootOperation(new AllOperation()); + + GroupingRequest request2 = GroupingRequest.newInstance(q); + AllOperation all = new AllOperation(); + all.addChild(new EachOperation()); + all.addChild(new EachOperation()); + request2.setRootOperation(all); + + assertForceSinglePassIs(false, q); + fastSearcher.search(SCHEMA, q); + assertForceSinglePassIs(false, q); + } + + private void assertForceSinglePassIs(boolean expected, Query query) { + for (GroupingRequest request : query.getSelect().getGrouping()) + assertForceSinglePassIs(expected, request.getRootOperation()); + } + + private void assertForceSinglePassIs(boolean expected, GroupingOperation operation) { + assertEquals(expected, operation.getForceSinglePass(), "Force single pass is " + expected + " in " + operation); + for (GroupingOperation child : operation.getChildren()) + assertForceSinglePassIs(expected, child); + } + + @Test + void testDispatchReconfig() { + String clusterName = "a"; + var b = new QrSearchersConfig.Builder(); + var searchClusterB = new QrSearchersConfig.Searchcluster.Builder(); + searchClusterB.name(clusterName); + b.searchcluster(searchClusterB); + VipStatus vipStatus = new VipStatus(b.build()); + List nodes_1 = List.of(new Node(CLUSTER, 0, "host0", 0)); + RpcResourcePool rpcPool_1 = new RpcResourcePool(MockDispatcher.toDispatchConfig(), MockDispatcher.toNodesConfig(nodes_1)); + MockDispatcher dispatch_1 = MockDispatcher.create(nodes_1, rpcPool_1, vipStatus); + dispatch_1.clusterMonitor.shutdown(); + vipStatus.addToRotation(clusterName); + assertTrue(vipStatus.isInRotation()); + dispatch_1.deconstruct(); + assertTrue(vipStatus.isInRotation()); //Verify that deconstruct does not touch vipstatus + } + + private String searchError(String query, VespaBackend searcher) { + return search(query, searcher).hits().getError().getDetailedMessage(); + } + + private Result search(String query, VespaBackend searcher) { + return searcher.search(SCHEMA, new Query(query)); + } + + private DocumentdbInfoConfig documentdbInfoConfig(String schemaName) { + var db = new DocumentdbInfoConfig.Documentdb.Builder().name(schemaName); + return new DocumentdbInfoConfig.Builder().documentdb(db).build(); + } + + private SchemaInfo schemaInfo(String schemaName) { + var schema = new Schema.Builder(schemaName); + schema.add(new RankProfile.Builder("default").build()); + return new SchemaInfo(List.of(schema.build()), List.of()); + } + +} diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/PartialFillTestCase.java b/container-search/src/test/java/com/yahoo/prelude/fastsearch/PartialFillTestCase.java new file mode 100644 index 00000000000..7760e204d4b --- /dev/null +++ b/container-search/src/test/java/com/yahoo/prelude/fastsearch/PartialFillTestCase.java @@ -0,0 +1,140 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.prelude.fastsearch; + +import com.yahoo.search.Query; +import com.yahoo.search.Result; +import com.yahoo.search.result.ErrorHit; +import com.yahoo.search.result.ErrorMessage; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author havardpe + */ +public class PartialFillTestCase { + + public static class FS4 extends VespaBackend { + public List history = new ArrayList<>(); + protected Result doSearch2(String schema, Query query) { + return new Result(query); + } + protected void doPartialFill(Result result, String summaryClass) { + history.add(result); + } + } + + public static class BadFS4 extends VespaBackend { + protected Result doSearch2(String schema, Query query) { + return new Result(query); + } + protected void doPartialFill(Result result, String summaryClass) { + if (result.hits().getErrorHit() == null) { + result.hits().addError(ErrorMessage.createUnspecifiedError("error")); + } + } + } + + @Test + void testPartitioning() { + FS4 fs4 = new FS4(); + Query a = new Query("/?query=foo"); + Query b = new Query("/?query=bar"); + Query c = new Query("/?query=foo"); // equal to a + Result r = new Result(new Query("/?query=ignorethis")); + for (int i = 0; i < 7; i++) { + FastHit h = new FastHit(); + h.setQuery(a); + h.setFillable(); + r.hits().add(h); + } + for (int i = 0; i < 5; i++) { + FastHit h = new FastHit(); + h.setQuery(b); + h.setFillable(); + r.hits().add(h); + } + for (int i = 0; i < 3; i++) { + FastHit h = new FastHit(); + h.setQuery(c); + h.setFillable(); + r.hits().add(h); + } + for (int i = 0; i < 2; i++) { + FastHit h = new FastHit(); + // no query assigned + h.setFillable(); + r.hits().add(h); + } + for (int i = 0; i < 5; i++) { + FastHit h = new FastHit(); + // not fillable + h.setQuery(a); + r.hits().add(h); + } + for (int i = 0; i < 5; i++) { + FastHit h = new FastHit(); + // already filled + h.setQuery(a); + h.setFilled("default"); + r.hits().add(h); + } + doFill(fs4, r, "default"); + assertNull(r.hits().getErrorHit()); + assertEquals(4, fs4.history.size()); + assertEquals(a, fs4.history.get(0).getQuery()); + assertEquals(7, fs4.history.get(0).getHitCount()); + assertEquals(b, fs4.history.get(1).getQuery()); + assertEquals(5, fs4.history.get(1).getHitCount()); + assertEquals(c, fs4.history.get(2).getQuery()); + assertEquals(3, fs4.history.get(2).getHitCount()); + assertEquals(r.getQuery(), fs4.history.get(3).getQuery()); + assertEquals(2, fs4.history.get(3).getHitCount()); + } + + @Test + void testMergeErrors() { + BadFS4 fs4 = new BadFS4(); + Query a = new Query("/?query=foo"); + Query b = new Query("/?query=bar"); + Result r = new Result(new Query("/?query=ignorethis")); + { + FastHit h = new FastHit(); + h.setQuery(a); + h.setFillable(); + r.hits().add(h); + } + { + FastHit h = new FastHit(); + h.setQuery(b); + h.setFillable(); + r.hits().add(h); + } + doFill(fs4, r, "default"); + ErrorHit eh = r.hits().getErrorHit(); + assertNotNull(eh); + ErrorMessage exp_sub = ErrorMessage.createUnspecifiedError("error"); + int n = 0; + for (Iterator i = eh.errorIterator(); i.hasNext(); ) { + com.yahoo.search.result.ErrorMessage error = i.next(); + switch (n) { + case 0: + case 1: + assertEquals(exp_sub, error); + break; + default: + fail(); + } + n++; + } + } + + private void doFill(VespaBackend searcher, Result result, String summaryClass) { + searcher.fill(result, summaryClass); + } + +} diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/DocsumDefinitionTestCase.java b/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/DocsumDefinitionTestCase.java deleted file mode 100644 index ade094115fe..00000000000 --- a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/DocsumDefinitionTestCase.java +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.fastsearch.test; - -import com.yahoo.prelude.fastsearch.ByteField; -import com.yahoo.prelude.fastsearch.DataField; -import com.yahoo.prelude.fastsearch.DocsumDefinition; -import com.yahoo.prelude.fastsearch.DocsumDefinitionSet; -import com.yahoo.prelude.fastsearch.FastHit; -import com.yahoo.prelude.fastsearch.IntegerField; -import com.yahoo.prelude.fastsearch.StringField; -import com.yahoo.document.DocumentId; -import com.yahoo.document.GlobalId; -import com.yahoo.search.schema.DocumentSummary; -import com.yahoo.search.schema.Schema; -import com.yahoo.slime.BinaryFormat; -import com.yahoo.slime.Cursor; -import com.yahoo.slime.Slime; -import org.junit.jupiter.api.Test; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -/** - * Tests docsum class functionality - * - * @author bratseth - */ -public class DocsumDefinitionTestCase { - - @Test - void testDecoding() { - DocsumDefinitionSet set = createDocsumDefinitionSet(); - FastHit hit = new FastHit(); - - set.lazyDecode(null, makeDocsum(), hit); - assertEquals("Arts/Celebrities/Madonna", hit.getField("TOPIC")); - assertEquals("1", hit.getField("EXTINFOSOURCE").toString()); - assertEquals("10", hit.getField("LANG1").toString()); - assertEquals("352", hit.getField("WORDS").toString()); - assertEquals("index:null/0/" + asHexString(hit.getGlobalId()), hit.getId().toString()); - } - - private static String asHexString(GlobalId gid) { - StringBuilder sb = new StringBuilder(); - byte[] rawGid = gid.getRawId(); - for (byte b : rawGid) { - String hex = Integer.toHexString(0xFF & b); - if (hex.length() == 1) - sb.append('0'); - sb.append(hex); - } - return sb.toString(); - } - - public static byte[] makeDocsum() { - Slime slime = new Slime(); - Cursor docsum = slime.setObject(); - docsum.setString("TOPIC", "Arts/Celebrities/Madonna"); - docsum.setString("TITLE", "StudyOfMadonna.com - Interviews, Articles, Reviews, Quotes, Essays and more.."); - docsum.setString("DYNTEASER", "dynamic teaser"); - docsum.setLong("EXTINFOSOURCE", 1); - docsum.setLong("LANG1", 10); - docsum.setLong("WORDS", 352); - docsum.setLong("BYTES", 9190); - byte[] tmp = BinaryFormat.encode(slime); - ByteBuffer buf = ByteBuffer.allocate(tmp.length + 4); - buf.order(ByteOrder.LITTLE_ENDIAN); - buf.putInt(DocsumDefinitionSet.SLIME_MAGIC_ID); - buf.order(ByteOrder.BIG_ENDIAN); - buf.put(tmp); - return buf.array(); - } - - public static DocsumDefinitionSet createDocsumDefinitionSet() { - var schema = new Schema.Builder("test"); - var summary = new DocumentSummary.Builder("default"); - summary.add(new DocumentSummary.Field("TOPIC", "string")); - summary.add(new DocumentSummary.Field("TITLE", "string")); - summary.add(new DocumentSummary.Field("DYNTEASER", "string")); - summary.add(new DocumentSummary.Field("EXTINFOSOURCE", "integer")); - summary.add(new DocumentSummary.Field("LANG1", "integer")); - summary.add(new DocumentSummary.Field("WORDS", "integer")); - summary.add(new DocumentSummary.Field("BYTES", "byte")); - schema.add(summary.build()); - return new DocsumDefinitionSet(schema.build()); - } - -} diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/FastSearcherTestCase.java b/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/FastSearcherTestCase.java deleted file mode 100644 index 3928743c954..00000000000 --- a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/FastSearcherTestCase.java +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.fastsearch.test; - -import com.yahoo.container.QrSearchersConfig; -import com.yahoo.container.handler.VipStatus; -import com.yahoo.container.protect.Error; -import com.yahoo.prelude.fastsearch.ClusterParams; -import com.yahoo.prelude.fastsearch.DocumentdbInfoConfig; -import com.yahoo.prelude.fastsearch.FastBackend; -import com.yahoo.prelude.fastsearch.SummaryParameters; -import com.yahoo.prelude.fastsearch.VespaBackend; -import com.yahoo.search.Query; -import com.yahoo.search.Result; -import com.yahoo.search.dispatch.MockDispatcher; -import com.yahoo.search.dispatch.rpc.RpcResourcePool; -import com.yahoo.search.dispatch.searchcluster.Node; -import com.yahoo.search.grouping.GroupingRequest; -import com.yahoo.search.grouping.request.AllOperation; -import com.yahoo.search.grouping.request.EachOperation; -import com.yahoo.search.grouping.request.GroupingOperation; -import com.yahoo.search.result.ErrorMessage; -import com.yahoo.search.schema.DocumentSummary; -import com.yahoo.search.schema.RankProfile; -import com.yahoo.search.schema.Schema; -import com.yahoo.search.schema.SchemaInfo; -import org.junit.jupiter.api.Test; - -import java.util.Collections; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static org.junit.jupiter.api.Assertions.*; - - -/** - * Tests the Fast searcher - * - * @author bratseth - */ -public class FastSearcherTestCase { - private static final String SCHEMA = "test"; - private static final String CLUSTER = "test"; - - @Test - void testNullQuery() { - Logger.getLogger(FastBackend.class.getName()).setLevel(Level.ALL); - FastBackend fastSearcher = new FastBackend("container.0", - MockDispatcher.create(List.of()), - new SummaryParameters(null), - new ClusterParams("testhittype"), - documentdbInfoConfig(SCHEMA), - schemaInfo(SCHEMA)); - - String query = "?junkparam=ignored"; - Result result = doSearch(fastSearcher, new Query(query), 0, 10); - ErrorMessage message = result.hits().getError(); - - assertNotNull(message, "Got error"); - assertEquals("Null query", message.getMessage()); - assertEquals(query, message.getDetailedMessage()); - assertEquals(Error.NULL_QUERY.code, message.getCode()); - } - - private Result doSearch(VespaBackend searcher, Query query, int offset, int hits) { - query.setOffset(offset); - query.setHits(hits); - return searcher.search(SCHEMA, query); - } - - @Test - void testSinglePassGroupingIsForcedWithSingleNodeGroups() { - FastBackend fastSearcher = new FastBackend("container.0", - MockDispatcher.create(List.of(new Node(CLUSTER, 0, "host0", 0))), - new SummaryParameters(null), - new ClusterParams("testhittype"), - documentdbInfoConfig(SCHEMA), - schemaInfo(SCHEMA)); - Query q = new Query("?query=foo"); - GroupingRequest request1 = GroupingRequest.newInstance(q); - request1.setRootOperation(new AllOperation()); - - GroupingRequest request2 = GroupingRequest.newInstance(q); - AllOperation all = new AllOperation(); - all.addChild(new EachOperation()); - all.addChild(new EachOperation()); - request2.setRootOperation(all); - - assertForceSinglePassIs(false, q); - fastSearcher.search(SCHEMA, q); - assertForceSinglePassIs(true, q); - } - - @Test - void testRankProfileValidation() { - FastBackend fastSearcher = new FastBackend("container.0", - MockDispatcher.create(List.of(new Node(CLUSTER, 0, "host0", 0))), - new SummaryParameters(null), - new ClusterParams("testhittype"), - documentdbInfoConfig(SCHEMA), - schemaInfo(SCHEMA)); - assertFalse(searchError("?query=q", fastSearcher).contains("does not contain requested rank profile")); - assertFalse(searchError("?query=q&ranking.profile=default", fastSearcher).contains("does not contain requested rank profile")); - assertTrue(searchError("?query=q&ranking.profile=nosuch", fastSearcher).contains("does not contain requested rank profile")); - } - - @Test - void testSummaryNeedsQuery() { - var documentDb = new DocumentdbInfoConfig(new DocumentdbInfoConfig.Builder().documentdb(new DocumentdbInfoConfig.Documentdb.Builder().name(SCHEMA))); - var schema = new Schema.Builder(SCHEMA) - .add(new DocumentSummary.Builder("default").build()) - .add(new RankProfile.Builder("default").setHasRankFeatures(false) - .setHasSummaryFeatures(false) - .build()); - FastBackend backend = new FastBackend("container.0", - MockDispatcher.create(Collections.singletonList(new Node(CLUSTER, 0, "host0", 0))), - new SummaryParameters(null), - new ClusterParams("testhittype"), - documentDb, - new SchemaInfo(List.of(schema.build()), List.of())); - Query q = new Query("?query=foo"); - Result result = doSearch(backend, q, 0, 10); - assertFalse(backend.summaryNeedsQuery(q)); - - q = new Query("?query=select+*+from+source+where+title+contains+%22foobar%22+and++geoLocation%28myfieldname%2C+63.5%2C+10.5%2C+%22999+km%22%29%3B"); - q.getModel().setType(Query.Type.YQL); - result = doSearch(backend, q, 0, 10); - assertTrue(backend.summaryNeedsQuery(q)); - } - - @Test - void testSinglePassGroupingIsNotForcedWithSingleNodeGroups() { - MockDispatcher dispatcher = MockDispatcher.create(List.of(new Node(CLUSTER, 0, "host0", 0), new Node(CLUSTER, 2, "host1", 0))); - - FastBackend fastSearcher = new FastBackend("container.0", - dispatcher, - new SummaryParameters(null), - new ClusterParams("testhittype"), - documentdbInfoConfig(SCHEMA), - schemaInfo(SCHEMA)); - Query q = new Query("?query=foo"); - GroupingRequest request1 = GroupingRequest.newInstance(q); - request1.setRootOperation(new AllOperation()); - - GroupingRequest request2 = GroupingRequest.newInstance(q); - AllOperation all = new AllOperation(); - all.addChild(new EachOperation()); - all.addChild(new EachOperation()); - request2.setRootOperation(all); - - assertForceSinglePassIs(false, q); - fastSearcher.search(SCHEMA, q); - assertForceSinglePassIs(false, q); - } - - private void assertForceSinglePassIs(boolean expected, Query query) { - for (GroupingRequest request : query.getSelect().getGrouping()) - assertForceSinglePassIs(expected, request.getRootOperation()); - } - - private void assertForceSinglePassIs(boolean expected, GroupingOperation operation) { - assertEquals(expected, operation.getForceSinglePass(), "Force single pass is " + expected + " in " + operation); - for (GroupingOperation child : operation.getChildren()) - assertForceSinglePassIs(expected, child); - } - - @Test - void testDispatchReconfig() { - String clusterName = "a"; - var b = new QrSearchersConfig.Builder(); - var searchClusterB = new QrSearchersConfig.Searchcluster.Builder(); - searchClusterB.name(clusterName); - b.searchcluster(searchClusterB); - VipStatus vipStatus = new VipStatus(b.build()); - List nodes_1 = List.of(new Node(CLUSTER, 0, "host0", 0)); - RpcResourcePool rpcPool_1 = new RpcResourcePool(MockDispatcher.toDispatchConfig(), MockDispatcher.toNodesConfig(nodes_1)); - MockDispatcher dispatch_1 = MockDispatcher.create(nodes_1, rpcPool_1, vipStatus); - dispatch_1.clusterMonitor.shutdown(); - vipStatus.addToRotation(clusterName); - assertTrue(vipStatus.isInRotation()); - dispatch_1.deconstruct(); - assertTrue(vipStatus.isInRotation()); //Verify that deconstruct does not touch vipstatus - } - - private String searchError(String query, VespaBackend searcher) { - return search(query, searcher).hits().getError().getDetailedMessage(); - } - - private Result search(String query, VespaBackend searcher) { - return searcher.search(SCHEMA, new Query(query)); - } - - private DocumentdbInfoConfig documentdbInfoConfig(String schemaName) { - var db = new DocumentdbInfoConfig.Documentdb.Builder().name(schemaName); - return new DocumentdbInfoConfig.Builder().documentdb(db).build(); - } - - private SchemaInfo schemaInfo(String schemaName) { - var schema = new Schema.Builder(schemaName); - schema.add(new RankProfile.Builder("default").build()); - return new SchemaInfo(List.of(schema.build()), List.of()); - } - -} diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/PartialFillTestCase.java b/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/PartialFillTestCase.java deleted file mode 100644 index cf5a0ca7bd9..00000000000 --- a/container-search/src/test/java/com/yahoo/prelude/fastsearch/test/PartialFillTestCase.java +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.prelude.fastsearch.test; - -import com.yahoo.component.chain.Chain; -import com.yahoo.prelude.fastsearch.FastHit; -import com.yahoo.prelude.fastsearch.VespaBackend; -import com.yahoo.search.Query; -import com.yahoo.search.Result; -import com.yahoo.search.Searcher; -import com.yahoo.search.result.ErrorHit; -import com.yahoo.search.result.ErrorMessage; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - -/** - * @author havardpe - */ -public class PartialFillTestCase { - - public static class FS4 extends VespaBackend { - public List history = new ArrayList<>(); - protected Result doSearch2(String schema, Query query) { - return new Result(query); - } - protected void doPartialFill(Result result, String summaryClass) { - history.add(result); - } - } - - public static class BadFS4 extends VespaBackend { - protected Result doSearch2(String schema, Query query) { - return new Result(query); - } - protected void doPartialFill(Result result, String summaryClass) { - if (result.hits().getErrorHit() == null) { - result.hits().addError(ErrorMessage.createUnspecifiedError("error")); - } - } - } - - @Test - void testPartitioning() { - FS4 fs4 = new FS4(); - Query a = new Query("/?query=foo"); - Query b = new Query("/?query=bar"); - Query c = new Query("/?query=foo"); // equal to a - Result r = new Result(new Query("/?query=ignorethis")); - for (int i = 0; i < 7; i++) { - FastHit h = new FastHit(); - h.setQuery(a); - h.setFillable(); - r.hits().add(h); - } - for (int i = 0; i < 5; i++) { - FastHit h = new FastHit(); - h.setQuery(b); - h.setFillable(); - r.hits().add(h); - } - for (int i = 0; i < 3; i++) { - FastHit h = new FastHit(); - h.setQuery(c); - h.setFillable(); - r.hits().add(h); - } - for (int i = 0; i < 2; i++) { - FastHit h = new FastHit(); - // no query assigned - h.setFillable(); - r.hits().add(h); - } - for (int i = 0; i < 5; i++) { - FastHit h = new FastHit(); - // not fillable - h.setQuery(a); - r.hits().add(h); - } - for (int i = 0; i < 5; i++) { - FastHit h = new FastHit(); - // already filled - h.setQuery(a); - h.setFilled("default"); - r.hits().add(h); - } - doFill(fs4, r, "default"); - assertNull(r.hits().getErrorHit()); - assertEquals(4, fs4.history.size()); - assertEquals(a, fs4.history.get(0).getQuery()); - assertEquals(7, fs4.history.get(0).getHitCount()); - assertEquals(b, fs4.history.get(1).getQuery()); - assertEquals(5, fs4.history.get(1).getHitCount()); - assertEquals(c, fs4.history.get(2).getQuery()); - assertEquals(3, fs4.history.get(2).getHitCount()); - assertEquals(r.getQuery(), fs4.history.get(3).getQuery()); - assertEquals(2, fs4.history.get(3).getHitCount()); - } - - @Test - void testMergeErrors() { - BadFS4 fs4 = new BadFS4(); - Query a = new Query("/?query=foo"); - Query b = new Query("/?query=bar"); - Result r = new Result(new Query("/?query=ignorethis")); - { - FastHit h = new FastHit(); - h.setQuery(a); - h.setFillable(); - r.hits().add(h); - } - { - FastHit h = new FastHit(); - h.setQuery(b); - h.setFillable(); - r.hits().add(h); - } - doFill(fs4, r, "default"); - ErrorHit eh = r.hits().getErrorHit(); - assertNotNull(eh); - ErrorMessage exp_sub = ErrorMessage.createUnspecifiedError("error"); - int n = 0; - for (Iterator i = eh.errorIterator(); i.hasNext(); ) { - com.yahoo.search.result.ErrorMessage error = i.next(); - switch (n) { - case 0: - case 1: - assertEquals(exp_sub, error); - break; - default: - fail(); - } - n++; - } - } - - private void doFill(VespaBackend searcher, Result result, String summaryClass) { - searcher.fill(result, summaryClass); - } - - private Chain chainedAsSearchChain(Searcher topOfChain) { - List searchers = new ArrayList<>(); - searchers.add(topOfChain); - return new Chain<>(searchers); - } - -} -- cgit v1.2.3