// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.streamingvisitors; import com.yahoo.data.access.Inspectable; import com.yahoo.data.access.helpers.MatchFeatureData; import com.yahoo.document.select.parser.TokenMgrException; import com.yahoo.messagebus.Trace; import com.yahoo.messagebus.routing.Route; import com.yahoo.prelude.fastsearch.ClusterParams; import com.yahoo.prelude.fastsearch.DocumentdbInfoConfig; import com.yahoo.document.select.parser.ParseException; import com.yahoo.prelude.fastsearch.SummaryParameters; import com.yahoo.prelude.fastsearch.TimeoutException; import com.yahoo.search.Query; import com.yahoo.search.Result; import com.yahoo.search.result.Hit; import com.yahoo.search.schema.Schema; import com.yahoo.search.schema.SchemaInfo; import com.yahoo.search.searchchain.Execution; import com.yahoo.searchlib.aggregation.Grouping; import com.yahoo.vdslib.DocumentSummary; import com.yahoo.vdslib.SearchResult; import com.yahoo.vdslib.VisitorStatistics; import com.yahoo.vespa.streamingvisitors.tracing.MockUtils; import com.yahoo.vespa.streamingvisitors.tracing.MonotonicNanoClock; import com.yahoo.vespa.streamingvisitors.tracing.SamplingStrategy; import com.yahoo.vespa.streamingvisitors.tracing.TraceExporter; import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** * @author Ulf Carlin */ public class StreamingSearcherTestCase { public static final String USERDOC_ID_PREFIX = "id:namespace:mytype:n=1:userspecific"; public static final String GROUPDOC_ID_PREFIX = "id:namespace:mytype:g=group1:userspecific"; private static class MockVisitor implements Visitor { private final Query query; final String searchCluster; final Route route; final String documentType; int totalHitCount; private final List hits = new ArrayList<>(); private final Map summaryMap = new HashMap<>(); private final List groupings = new ArrayList<>(); int traceLevelOverride; MockVisitor(Query query, String searchCluster, Route route, String documentType, int traceLevelOverride) { this.query = query; this.searchCluster = searchCluster; this.route = route; this.documentType = documentType; this.traceLevelOverride = traceLevelOverride; } @Override public void doSearch() throws InterruptedException, ParseException, TimeoutException { String queryString = query.getModel().getQueryString(); if (queryString.compareTo("parseexception") == 0) { throw new ParseException("Parsing failed"); } else if (queryString.compareTo("tokenizeexception") == 0) { throw new TokenMgrException("Tokenization failed", 0); } else if (queryString.compareTo("interruptedexception") == 0) { throw new InterruptedException("Interrupted"); } else if (queryString.compareTo("timeoutexception") == 0) { throw new TimeoutException("Timed out"); } else if (queryString.compareTo("illegalargumentexception") == 0) { throw new IllegalArgumentException("Illegal argument"); } else if (queryString.compareTo("nosummary") == 0) { String docId = USERDOC_ID_PREFIX + 0; totalHitCount = 1; hits.add(new SearchResult.Hit(docId, 1.0)); } else if (queryString.compareTo("nosummarytofill") == 0) { addResults(USERDOC_ID_PREFIX, 1, true); } else if (queryString.compareTo("oneuserhit") == 0) { addResults(USERDOC_ID_PREFIX, 1, false); } else if (queryString.compareTo("twouserhits") == 0) { addResults(USERDOC_ID_PREFIX, 2, false); } else if (queryString.compareTo("twogrouphitsandoneuserhit") == 0) { addResults(GROUPDOC_ID_PREFIX, 2, false); addResults(USERDOC_ID_PREFIX, 1, false); } else if (queryString.compareTo("onegroupinghit") == 0) { groupings.add(new Grouping()); } else if (queryString.compareTo("match_features") == 0) { addResults(USERDOC_ID_PREFIX, 1, false); var matchFeatures = new MatchFeatureData(List.of("my_feature")).addHit(); matchFeatures.set(0, 7.0); hits.get(0).setMatchFeatures(matchFeatures); } } private void addResults(String idPrefix, int hitCount, boolean emptyDocsum) { totalHitCount += hitCount; for (int i=0; i getHits() { return hits; } @Override public Map getSummaryMap() { return summaryMap; } @Override public int getTotalHitCount() { return totalHitCount; } @Override public List getGroupings() { return groupings; } @Override public Trace getTrace() { return new Trace(); } } private static class MockVisitorFactory implements VisitorFactory { public MockVisitor lastCreatedVisitor; @Override public Visitor createVisitor(Query query, String searchCluster, Route route, String documentType, int traceLevelOverride) { lastCreatedVisitor = new MockVisitor(query, searchCluster, route, documentType, traceLevelOverride); return lastCreatedVisitor; } } private static Result executeQuery(StreamingSearcher searcher, Query query) { Execution execution = new Execution(Execution.Context.createContextStub()); return searcher.doSearch2(query, execution); } private static Query[] generateTestQueries(String queryString) { Query[] queries = new Query[4]; // Increase coverage for (int i = 0; i