aboutsummaryrefslogtreecommitdiffstats
path: root/container-core/src/test/java/com/yahoo/container/handler/metrics/MetricsV2HandlerTest.java
blob: ad5b1a496709f9b26528babb18be62a06348a9da (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
145
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.handler.metrics;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
import com.yahoo.container.jdisc.RequestHandlerTestDriver;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static com.yahoo.container.handler.metrics.MetricsV2Handler.V2_PATH;
import static com.yahoo.container.handler.metrics.MetricsV2Handler.VALUES_PATH;
import static com.yahoo.container.handler.metrics.MetricsV2Handler.consumerQuery;
import static org.junit.jupiter.api.Assertions.*;

/**
 * @author gjoranv
 */
public class MetricsV2HandlerTest {

    private static final ObjectMapper jsonMapper = new ObjectMapper();

    private static final String URI_BASE = "http://localhost";

    private static final String V2_URI = URI_BASE + V2_PATH;
    private static final String VALUES_URI = URI_BASE + VALUES_PATH;

    // Mock applicationmetrics api
    private static final String MOCK_METRICS_PATH = "/node0";

    private static final String TEST_FILE = "application-metrics.json";
    private static final String RESPONSE = getFileContents(TEST_FILE);
    private static final String CPU_METRIC = "cpu.util";
    private static final String REPLACED_CPU_METRIC = "replaced_cpu_util";
    private static final String CUSTOM_CONSUMER = "custom-consumer";

    private static RequestHandlerTestDriver testDriver;

    @RegisterExtension
    public WireMockExtension wireMockRule = WireMockExtension.newInstance().options(options().dynamicPort()).build();

    @BeforeEach
    public void setup() {
        setupWireMock();
        var handler = new MetricsV2Handler(Executors.newSingleThreadExecutor(),
                                           new MetricsProxyApiConfig.Builder()
                                                   .metricsPort(wireMockRule.getPort())
                                                   .metricsApiPath(MOCK_METRICS_PATH)
                                                   .prometheusApiPath("Not/In/Use")
                                                   .build());
        testDriver = new RequestHandlerTestDriver(handler);
    }

    private void setupWireMock() {
        wireMockRule.stubFor(get(urlPathEqualTo(MOCK_METRICS_PATH))
                                     .willReturn(aResponse().withBody(RESPONSE)));

        // Add a slightly different response for a custom consumer.
        String myConsumerResponse = RESPONSE.replaceAll(CPU_METRIC, REPLACED_CPU_METRIC);
        wireMockRule.stubFor(get(urlPathEqualTo(MOCK_METRICS_PATH))
                                     .withQueryParam("consumer", equalTo(CUSTOM_CONSUMER))
                                     .willReturn(aResponse().withBody(myConsumerResponse)));
    }

    @Test
    void v2_response_contains_values_uri() throws Exception {
        String response = testDriver.sendRequest(V2_URI).readAll();
        JsonNode root = jsonMapper.readTree(response);
        assertTrue(root.has("resources"));

        ArrayNode resources = (ArrayNode) root.get("resources");
        assertEquals(1, resources.size());

        JsonNode valuesUri = resources.get(0);
        assertEquals(VALUES_URI, valuesUri.get("url").textValue());
    }

    @Disabled
    @Test
    void visually_inspect_values_response() {
        JsonNode responseJson = getResponseAsJson(null);
        System.out.println(responseJson);
    }

    @Test
    void invalid_path_yields_error_response() throws Exception {
        String response = testDriver.sendRequest(V2_URI + "/invalid").readAll();
        JsonNode root = jsonMapper.readTree(response);
        assertTrue(root.has("error"));
        assertTrue(root.get("error").textValue().startsWith("No content"));
    }

    @Test
    void values_response_is_equal_to_test_file() {
        String response = testDriver.sendRequest(VALUES_URI).readAll();
        assertEquals(RESPONSE, response);
    }

    @Test
    void consumer_is_propagated_to_metrics_proxy_api() {
        JsonNode responseJson = getResponseAsJson(CUSTOM_CONSUMER);

        JsonNode firstNodeMetricsValues =
                responseJson.get("nodes").get(0)
                        .get("node")
                        .get("metrics").get(0)
                        .get("values");

        assertTrue(firstNodeMetricsValues.has(REPLACED_CPU_METRIC));
    }

    private JsonNode getResponseAsJson(String consumer) {
        String response = testDriver.sendRequest(VALUES_URI + consumerQuery(consumer)).readAll();
        try {
            return jsonMapper.readTree(response);
        } catch (IOException e) {
            fail("Failed to create json object: " + e.getMessage());
            throw new RuntimeException(e);
        }
    }

    static String getFileContents(String filename) {
        InputStream in = MetricsV2HandlerTest.class.getClassLoader().getResourceAsStream(filename);
        if (in == null) {
            throw new RuntimeException("File not found: " + filename);
        }
        return new BufferedReader(new InputStreamReader(in)).lines().collect(Collectors.joining("\n"));
    }

}