aboutsummaryrefslogtreecommitdiffstats
path: root/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/MetricsSearcherTestCase.java
blob: 0ebfb9cf6697be19388157f55c49149ab0a0285e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// 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.component.chain.Chain;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
import com.yahoo.search.result.ErrorMessage;
import com.yahoo.search.result.Hit;
import com.yahoo.search.searchchain.Execution;
import com.yahoo.vdslib.VisitorStatistics;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

/**
 * @author Ulf Carlin
 */
public class MetricsSearcherTestCase {

    private final MetricsSearcher metricsSearcher = new MetricsSearcher();
    private final MockBackend backend = new MockBackend();
    private final Chain<Searcher> chain = new Chain<>(metricsSearcher, backend);
    private final Execution.Context context = Execution.Context.createContextStub();
    private final MetricsSearcher.Stats expStatsLt1 = new MetricsSearcher.Stats();
    private final MetricsSearcher.Stats expStatsLt2 = new MetricsSearcher.Stats();

    private static final String LOADTYPE1 = "lt1";
    private static final String LOADTYPE2 = "lt2";

    private void verifySearch(String metricParam, String message, String detailedMessage) {
        Result result = new Execution(chain, context).search(new Query("?query=test&" + metricParam));
        assertEquals(1, result.hits().size());
        if (message == null) {
            assertEquals("news:0", result.hits().get(0).getId().toString());
        } else {
            assertNotNull(result.hits().getError());
            assertTrue(result.hits().getErrorHit().errors().iterator().next().getMessage().contains(message),
                    "Expected '" + message + "' to be contained in '"
                    + result.hits().getErrorHit().errors().iterator().next().getMessage() + "'");
            assertTrue(result.hits().getErrorHit().errors().iterator().next().getDetailedMessage().contains(detailedMessage),
                    "Expected '" + detailedMessage + "' to be contained in '"
                    + result.hits().getErrorHit().errors().iterator().next().getDetailedMessage() + "'");
        }

        if (metricParam == null) {
            return;
        }

        MetricsSearcher.Stats expStats;
        MetricsSearcher.Stats actualStats;
        if (metricParam.contains(LOADTYPE1)) {
            expStats = expStatsLt1;
            actualStats = metricsSearcher.statMap.get(LOADTYPE1);
        } else {
            expStats = expStatsLt2;
            actualStats = metricsSearcher.statMap.get(LOADTYPE2);
        }

        expStats.count++;
        if (message == null) {
            expStats.ok++;
        } else {
            expStats.failed++;
        }
        if (metricParam.contains(LOADTYPE1)) {
            expStats.dataStreamed += 16;
            expStats.documentsStreamed += 2;
        }

        assertEquals(expStats.count, actualStats.count);
        assertEquals(expStats.ok, actualStats.ok);
        assertEquals(expStats.failed, actualStats.failed);
        assertEquals(expStats.dataStreamed, actualStats.dataStreamed);
        assertEquals(expStats.documentsStreamed, actualStats.documentsStreamed);
    }

    @Test
    void testBasics() {
        // Start counting at -1 since count is reset upon the first query by MetricsSearcher.search
        expStatsLt1.count--;
        String[] loadTypes = {LOADTYPE1, LOADTYPE2};
        for (String loadType : loadTypes) {
            verifySearch("streaming.loadtype=" + loadType, null, null);
            verifySearch("metricsearcher.id=" + loadType, null, null);
            verifySearch(null, null, null);
            verifySearch("streaming.loadtype=" + loadType, "Backend communication error", "Detailed error message");
        }

    }

    @Test
    void searcherDoesNotTryToDereferenceNullQueryContext() {
        backend.setImplicitlyCreateContext(false);
        // This will crash with an NPE if the searcher does not cope with null
        // query contexts.
        new Execution(chain, context).search(new Query("?query=test&streaming.loadtype=" + LOADTYPE1));
    }

    private static class MockBackend extends Searcher {

        private int sequenceNumber = 0;
        private final VisitorStatistics visitorStats = new VisitorStatistics();
        private boolean implicitlyCreateContext = true;

        private MockBackend() {
            visitorStats.setBucketsVisited(1);
            visitorStats.setBytesReturned(8);
            visitorStats.setBytesVisited(16);
            visitorStats.setDocumentsReturned(1);
            visitorStats.setDocumentsVisited(2);
        }

        public void setImplicitlyCreateContext(boolean implicitlyCreateContext) {
            this.implicitlyCreateContext = implicitlyCreateContext;
        }

        @Override
        public Result search(Query query, Execution execution) {
            if (implicitlyCreateContext) {
                String loadType = query.properties().getString("streaming.loadtype");
                assignContextProperties(query, loadType);
            }

            Result result = new Result(query);
            if (sequenceNumber == 3 || sequenceNumber == 7) {
                result.hits().addError(ErrorMessage.createBackendCommunicationError("Detailed error message"));
            } else {
                result.hits().add(new Hit("news:0"));
            }
            sequenceNumber++;
            return result;
        }

        private void assignContextProperties(Query query, String loadType) {
            if (loadType != null && loadType.equals(LOADTYPE1)) {
                query.getContext(true).setProperty(StreamingSearcher.STREAMING_STATISTICS, visitorStats);
            } else {
                query.getContext(true).setProperty(StreamingSearcher.STREAMING_STATISTICS, null);
            }
        }
    }

}