diff options
Diffstat (limited to 'routing-generator/src/test/java/com/yahoo/vespa/hosted/routing/nginx/NginxMetricsReporterTest.java')
-rw-r--r-- | routing-generator/src/test/java/com/yahoo/vespa/hosted/routing/nginx/NginxMetricsReporterTest.java | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/routing-generator/src/test/java/com/yahoo/vespa/hosted/routing/nginx/NginxMetricsReporterTest.java b/routing-generator/src/test/java/com/yahoo/vespa/hosted/routing/nginx/NginxMetricsReporterTest.java new file mode 100644 index 00000000000..72014047db7 --- /dev/null +++ b/routing-generator/src/test/java/com/yahoo/vespa/hosted/routing/nginx/NginxMetricsReporterTest.java @@ -0,0 +1,162 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.routing.nginx; + +import com.google.common.jimfs.Jimfs; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.jdisc.test.MockMetric; +import com.yahoo.vespa.hosted.routing.RoutingTable; +import com.yahoo.vespa.hosted.routing.RoutingTable.Endpoint; +import com.yahoo.vespa.hosted.routing.RoutingTable.Target; +import com.yahoo.vespa.hosted.routing.mock.HealthStatusMock; +import com.yahoo.vespa.hosted.routing.status.ServerGroup; +import org.junit.Test; + +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.FileTime; +import java.time.Duration; +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +/** + * @author mortent + * @author mpolden + */ +public class NginxMetricsReporterTest { + + private static final ApplicationId routingApp = ApplicationId.from("hosted-vespa", "routing", "default"); + + private static final Target target0 = createTarget("vespa", "music", "prod", "gateway"); + private static final Target target1 = createTarget("vespa", "music", "prod", "qrs"); + private static final Target target2 = createTarget("vespa", "donbot", "default", "default"); + private static final Target target3 = createTarget("notchecked", "notchecked", "default", "default"); + private static final Target target4 = createTarget("not", "appearing-in-routing", "default", "default"); + private static final Target target5 = createTarget(routingApp.tenant().value(), routingApp.application().value(), routingApp.instance().value(), "routing"); + + private final MockMetric metrics = new MockMetric(); + private final RoutingTable routingTable = createRoutingTable(); + private final HealthStatusMock healthService = new HealthStatusMock(); + private final FileSystem fileSystem = Jimfs.newFileSystem(); + private final NginxMetricsReporter reporter = new NginxMetricsReporter(routingApp, metrics, healthService, + fileSystem, Duration.ofDays(1), + () -> Optional.of(routingTable)); + + @Test + public void upstream_metrics() { + List<ServerGroup.Server> servers = List.of( + new ServerGroup.Server("gateway.prod.music.vespa.us-east-2.prod", "10.78.114.166:4080", true), + new ServerGroup.Server("gateway.prod.music.vespa.us-east-2.prod", "10.78.115.68:4080", true), + new ServerGroup.Server("qrs.prod.music.vespa.us-east-2.prod", "10.78.114.166:4080", true), + new ServerGroup.Server("qrs.prod.music.vespa.us-east-2.prod", "10.78.115.68:4080", true), + new ServerGroup.Server("qrs.prod.music.vespa.us-east-2.prod", "10.78.114.166:4080", false), + new ServerGroup.Server("qrs.prod.music.vespa.us-east-2.prod", "10.78.115.68:4080", false), + new ServerGroup.Server("qrs.prod.music.vespa.us-east-2.prod", "10.78.114.166:4080", false), + new ServerGroup.Server("qrs.prod.music.vespa.us-east-2.prod", "10.78.115.68:4080", false), + new ServerGroup.Server("donbot.vespa.us-east-2.prod", "10.201.8.47:4080", true), + new ServerGroup.Server("donbot.vespa.us-east-2.prod", "10.201.14.46:4080", false), + new ServerGroup.Server("appearing-in-routing.not.us-east-2.prod", "10.201.14.50:4080", false) + ); + healthService.setStatus(new ServerGroup(servers)); + reporter.run(); + + assertEquals(2D, getMetric(NginxMetricsReporter.UPSTREAM_UP_METRIC, dimensionsOf(target0)), Double.MIN_VALUE); + assertEquals(0D, getMetric(NginxMetricsReporter.UPSTREAM_DOWN_METRIC, dimensionsOf(target0)), Double.MIN_VALUE); + assertEquals(0D, getMetric(NginxMetricsReporter.UPSTREAM_UNKNOWN_METRIC, dimensionsOf(target0)), Double.MIN_VALUE); + + assertEquals(2L, getMetric(NginxMetricsReporter.UPSTREAM_UP_METRIC, dimensionsOf(target1)), Double.MIN_VALUE); + assertEquals(4L, getMetric(NginxMetricsReporter.UPSTREAM_DOWN_METRIC, dimensionsOf(target1)), Double.MIN_VALUE); + assertEquals(0L, getMetric(NginxMetricsReporter.UPSTREAM_UNKNOWN_METRIC, dimensionsOf(target1)), Double.MIN_VALUE); + + assertEquals(1D, getMetric(NginxMetricsReporter.UPSTREAM_UP_METRIC, dimensionsOf(target2)), Double.MIN_VALUE); + assertEquals(1D, getMetric(NginxMetricsReporter.UPSTREAM_DOWN_METRIC, dimensionsOf(target2)), Double.MIN_VALUE); + assertEquals(0D, getMetric(NginxMetricsReporter.UPSTREAM_UNKNOWN_METRIC, dimensionsOf(target2)), Double.MIN_VALUE); + + // If the application appears in routing table - but not in health check cache yet + assertEquals(0D, getMetric(NginxMetricsReporter.UPSTREAM_UP_METRIC, dimensionsOf(target3)), Double.MIN_VALUE); + assertEquals(0D, getMetric(NginxMetricsReporter.UPSTREAM_DOWN_METRIC, dimensionsOf(target3)), Double.MIN_VALUE); + assertEquals(1D, getMetric(NginxMetricsReporter.UPSTREAM_UNKNOWN_METRIC, dimensionsOf(target3)), Double.MIN_VALUE); + + // If the application does not appear in routing table - but still appears in cache + assertNull(getMetric(NginxMetricsReporter.UPSTREAM_UP_METRIC, dimensionsOf(target4))); + assertNull(getMetric(NginxMetricsReporter.UPSTREAM_DOWN_METRIC, dimensionsOf(target4))); + assertNull(getMetric(NginxMetricsReporter.UPSTREAM_UNKNOWN_METRIC, dimensionsOf(target4))); + + assertNull(getMetric(NginxMetricsReporter.UPSTREAM_UP_METRIC, dimensionsOf(target5))); + assertNull(getMetric(NginxMetricsReporter.UPSTREAM_DOWN_METRIC, dimensionsOf(target5))); + assertEquals(1D, getMetric(NginxMetricsReporter.UPSTREAM_UNKNOWN_METRIC, dimensionsOf(target5)), Double.MIN_VALUE); + } + + @Test + public void config_age_metric() throws Exception { + reporter.run(); + // No files exist + assertEquals(0D, getMetric(NginxMetricsReporter.CONFIG_AGE_METRIC), Double.MIN_VALUE); + + // Only temporary file exists + Path configRoot = fileSystem.getPath("/opt/vespa/var/vespa-hosted/routing/"); + Path tempFile = configRoot.resolve("nginxl4.conf.tmp"); + createFile(tempFile, Instant.ofEpochSecond(123)); + reporter.run(); + assertEquals(123D, getMetric(NginxMetricsReporter.CONFIG_AGE_METRIC), Double.MIN_VALUE); + + // Only main file exists + Files.delete(tempFile); + createFile(configRoot.resolve("nginxl4.conf"), Instant.ofEpochSecond(456)); + reporter.run(); + assertEquals(0D, getMetric(NginxMetricsReporter.CONFIG_AGE_METRIC), Double.MIN_VALUE); + + // Both files exist + createFile(tempFile, Instant.ofEpochSecond(123)); + reporter.run(); + assertEquals(333D, getMetric(NginxMetricsReporter.CONFIG_AGE_METRIC), Double.MIN_VALUE); + } + + private double getMetric(String name) { + return getMetric(name, Map.of()); + } + + private Double getMetric(String name, Map<String, ?> dimensions) { + Map<Map<String, ?>, Double> metric = metrics.metrics().get(name); + if (metric == null) throw new IllegalArgumentException("Metric '" + name + "' not found"); + return metric.get(dimensions); + } + + private void createFile(Path path, Instant lastModified) throws IOException { + Files.createDirectories(path.getParent()); + Files.createFile(path); + Files.setLastModifiedTime(path, FileTime.from(lastModified)); + } + + private Map<String, ?> dimensionsOf(Target target) { + return Map.of( + "tenantName", target.tenant().value(), + "app", String.format("%s.%s", target.application().value(), target.instance().get().value()), + "applicationId", String.format("%s.%s.%s", target.tenant().value(), target.application().value(), target.instance().get().value()), + "clusterid", target.cluster().value() + ); + } + + private static Target createTarget(String tenantName, String applicationName, String instanceName, String clusterName) { + ZoneId zone = ZoneId.from("prod", "us-east-2"); + ClusterSpec.Id cluster = ClusterSpec.Id.from(clusterName); + return Target.create(ApplicationId.from(tenantName, applicationName, instanceName), cluster, zone, List.of()); + } + + private static RoutingTable createRoutingTable() { + return new RoutingTable(Map.of(new Endpoint("endpoint0"), target0, + new Endpoint("endpoint1"), target1, + new Endpoint("endpoint2"), target2, + new Endpoint("endpoint3"), target3), + 42); + } + +} |