summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2018-06-22 15:10:58 +0200
committerMartin Polden <mpolden@mpolden.no>2018-06-26 14:01:48 +0200
commit3289bd77b0580668c3e80e7e790b78bc81fee455 (patch)
tree842afe722a7d3669de0d8d0f1a48c899cea8dbd4
parent34d80f9d3ffb3ebf984e67d2414f5ab16d2dfa5e (diff)
Rewrite StatusPage proxy
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/statuspage/StatusPageResource.java24
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/statuspage/package-info.java5
-rw-r--r--controller-server/pom.xml11
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageClient.java117
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageProxyHandler.java67
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/restapi/impl/StatusPageResource.java55
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/restapi/impl/package-info.java8
-rw-r--r--controller-server/src/main/resources/configdefinitions/statuspage.def4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/MockSecretStore.java48
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageClientTest.java44
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageProxyApiTest.java93
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/restapi/impl/StatusPageResourceTest.java65
12 files changed, 384 insertions, 157 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/statuspage/StatusPageResource.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/statuspage/StatusPageResource.java
deleted file mode 100644
index 65c5e0f9365..00000000000
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/statuspage/StatusPageResource.java
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.hosted.controller.api.statuspage;
-
-import com.fasterxml.jackson.databind.JsonNode;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
-
-/**
- * @author andreer
- */
-@Path("/v1/")
-@Produces(MediaType.APPLICATION_JSON)
-public interface StatusPageResource {
-
- @GET
- @Path("{page}")
- @Produces(MediaType.APPLICATION_JSON)
- JsonNode statusPage(@PathParam("page") String page, @QueryParam("since") String since);
-}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/statuspage/package-info.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/statuspage/package-info.java
deleted file mode 100644
index 3f9117bf931..00000000000
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/statuspage/package-info.java
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-@ExportPackage
-package com.yahoo.vespa.hosted.controller.api.statuspage;
-
-import com.yahoo.osgi.annotation.ExportPackage;
diff --git a/controller-server/pom.xml b/controller-server/pom.xml
index ade85a845fd..76a8bcd70e5 100644
--- a/controller-server/pom.xml
+++ b/controller-server/pom.xml
@@ -121,6 +121,11 @@
</dependency>
<dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ </dependency>
+
+ <dependency>
<groupId>com.yahoo.vespa</groupId>
<artifactId>config-model-api</artifactId>
<version>${project.version}</version>
@@ -235,6 +240,12 @@
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>com.github.tomakehurst</groupId>
+ <artifactId>wiremock-standalone</artifactId>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
<build>
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageClient.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageClient.java
new file mode 100644
index 00000000000..93213172048
--- /dev/null
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageClient.java
@@ -0,0 +1,117 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller.restapi.statuspage;
+
+import com.yahoo.slime.Slime;
+import com.yahoo.vespa.config.SlimeUtils;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.time.Duration;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * A basic client for the StatusPage API.
+ *
+ * @author mpolden
+ */
+public class StatusPageClient {
+
+ private static final Duration requestTimeout = Duration.ofSeconds(30);
+
+ private final URI url;
+ private final String key;
+
+ private StatusPageClient(URI url, String key) {
+ this.url = Objects.requireNonNull(url, "url cannot be null");
+ this.key = Objects.requireNonNull(key, "key cannot be null");
+ }
+
+ /** GET given page and return response body as slime */
+ public Slime get(String page, Optional<String> since) {
+ HttpGet get = new HttpGet(pageUrl(page, since));
+ try (CloseableHttpClient client = client()) {
+ try (CloseableHttpResponse response = client.execute(get)) {
+ if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+ throw new IllegalArgumentException("Received status " + response.getStatusLine().getStatusCode() +
+ " from StatusPage");
+ }
+ byte[] body = EntityUtils.toByteArray(response.getEntity());
+ return SlimeUtils.jsonToSlime(body);
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ URI pageUrl(String page, Optional<String> since) {
+ if (!allowAccess(page)) {
+ throw new IllegalArgumentException("Invalid resource: '" + page + "'");
+ }
+ URIBuilder builder = new URIBuilder(url)
+ .setPath("/api/v2/" + page + ".json")
+ .setParameter("api_key", key);
+ since.ifPresent(s -> builder.setParameter("since", s));
+ try {
+ return builder.build();
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static StatusPageClient create(URI url, String secret) {
+ String[] parts = secret.split(":");
+ if (parts.length != 2) {
+ throw new IllegalArgumentException("Invalid secret");
+ }
+ String pageId = parts[0];
+ String apiKey = parts[1];
+ if (isDefault(url)) {
+ // Rewrite URL to include page ID
+ try {
+ url = new URIBuilder(url).setHost(pageId + "." + url.getHost()).build();
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return new StatusPageClient(url, apiKey);
+ }
+
+ private static CloseableHttpClient client() {
+ HttpClientBuilder builder = HttpClients.custom();
+ RequestConfig requestConfig = RequestConfig.custom()
+ .setConnectionRequestTimeout((int) requestTimeout.toMillis())
+ .setConnectTimeout((int) requestTimeout.toMillis())
+ .setSocketTimeout((int) requestTimeout.toMillis())
+ .build();
+ return builder.setDefaultRequestConfig(requestConfig)
+ .setUserAgent("vespa-statuspage-client")
+ .build();
+ }
+
+ /** Returns whether given page is allowed to be accessed */
+ private static boolean allowAccess(String page) {
+ switch (page) {
+ case "incidents":
+ case "scheduled-maintenances":
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean isDefault(URI url) {
+ return "statuspage.io".equals(url.getHost());
+ }
+
+}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageProxyHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageProxyHandler.java
new file mode 100644
index 00000000000..ad69681fe7e
--- /dev/null
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageProxyHandler.java
@@ -0,0 +1,67 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller.restapi.statuspage;
+
+import com.google.inject.Inject;
+import com.yahoo.container.jdisc.HttpRequest;
+import com.yahoo.container.jdisc.HttpResponse;
+import com.yahoo.container.jdisc.LoggingRequestHandler;
+import com.yahoo.container.jdisc.secretstore.SecretStore;
+import com.yahoo.slime.Slime;
+import com.yahoo.vespa.hosted.controller.restapi.ErrorResponse;
+import com.yahoo.vespa.hosted.controller.restapi.Path;
+import com.yahoo.vespa.hosted.controller.restapi.SlimeJsonResponse;
+import com.yahoo.vespa.hosted.controller.statuspage.config.StatuspageConfig;
+import com.yahoo.yolean.Exceptions;
+
+import java.net.URI;
+import java.util.Optional;
+import java.util.logging.Level;
+
+/**
+ * Proxies requests from the controller to StatusPage.
+ *
+ * @author andreer
+ * @author mpolden
+ */
+@SuppressWarnings("unused") // Handler
+public class StatusPageProxyHandler extends LoggingRequestHandler {
+
+ private static final String secretKey = "vespa_hosted.controller.statuspage_api_key";
+
+ private final SecretStore secretStore;
+ private final URI apiUrl;
+
+ @Inject
+ public StatusPageProxyHandler(Context parentCtx, SecretStore secretStore, StatuspageConfig config) {
+ super(parentCtx);
+ this.secretStore = secretStore;
+ this.apiUrl = URI.create(config.apiUrl());
+ }
+
+ @Override
+ public HttpResponse handle(HttpRequest request) {
+ try {
+ switch (request.getMethod()) {
+ case GET: return handleGET(request);
+ default: return ErrorResponse.methodNotAllowed("Method '" + request.getMethod() + "' is not supported");
+ }
+ } catch (IllegalArgumentException e) {
+ return ErrorResponse.badRequest(Exceptions.toMessageString(e));
+ } catch (RuntimeException e) {
+ log.log(Level.WARNING, "Unexpected error handling '" + request.getUri() + "'", e);
+ return ErrorResponse.internalServerError(Exceptions.toMessageString(e));
+ }
+ }
+
+ private HttpResponse handleGET(HttpRequest request) {
+ Path path = new Path(request.getUri().getPath());
+ if (!path.matches("/statuspage/v1/{page}")) {
+ return ErrorResponse.notFoundError("Nothing at " + path);
+ }
+ StatusPageClient client = StatusPageClient.create(apiUrl, secretStore.getSecret(secretKey));
+ Optional<String> since = Optional.ofNullable(request.getProperty("since"));
+ Slime statusPageResponse = client.get(path.get("page"), since);
+ return new SlimeJsonResponse(statusPageResponse);
+ }
+
+}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/restapi/impl/StatusPageResource.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/restapi/impl/StatusPageResource.java
deleted file mode 100644
index 4c479267f2c..00000000000
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/restapi/impl/StatusPageResource.java
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.hosted.restapi.impl;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.google.inject.Inject;
-import com.yahoo.container.jaxrs.annotation.Component;
-import com.yahoo.container.jdisc.secretstore.SecretStore;
-
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.ClientBuilder;
-import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.UriBuilder;
-
-/**
- * Proxies requests from controller to https://xxx.statuspage.io/api/v2/yyy.json?api_key=zzz[&amp;since=YYYY-MM-DDThh:mm[:ss]±hh:mm]
- *
- * @author andreer
- */
-@Path("/v1/")
-@Produces(MediaType.APPLICATION_JSON)
-public class StatusPageResource implements com.yahoo.vespa.hosted.controller.api.statuspage.StatusPageResource {
-
- private final Client client;
- private final SecretStore secretStore;
-
- @Inject
- public StatusPageResource(@Component SecretStore secretStore) {
- this(secretStore, ClientBuilder.newClient());
- }
-
- protected StatusPageResource(SecretStore secretStore, Client client) {
- this.secretStore = secretStore;
- this.client = client;
- }
-
- protected UriBuilder statusPageURL(String page, String since) {
- String[] secrets = secretStore.getSecret("vespa_hosted.controller.statuspage_api_key").split(":");
- UriBuilder uriBuilder = UriBuilder.fromUri("https://" + secrets[0] + ".statuspage.io/api/v2/" + page + ".json?api_key=" + secrets[1]);
- if (since != null) {
- uriBuilder.queryParam("since", since);
- }
-
- return uriBuilder;
- }
-
- @Override
- public JsonNode statusPage(String page, String since) {
- WebTarget target = client.target(statusPageURL(page, since));
- return target.request().get(JsonNode.class);
- }
-
-}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/restapi/impl/package-info.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/restapi/impl/package-info.java
deleted file mode 100644
index dca8a22a313..00000000000
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/restapi/impl/package-info.java
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-/**
- * @author Tony Vaagenes
- */
-@ExportPackage
-package com.yahoo.vespa.hosted.restapi.impl;
-
-import com.yahoo.osgi.annotation.ExportPackage;
diff --git a/controller-server/src/main/resources/configdefinitions/statuspage.def b/controller-server/src/main/resources/configdefinitions/statuspage.def
new file mode 100644
index 00000000000..db8b034f99b
--- /dev/null
+++ b/controller-server/src/main/resources/configdefinitions/statuspage.def
@@ -0,0 +1,4 @@
+# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+namespace=vespa.hosted.controller.statuspage.config
+
+apiUrl string default=https://statuspage.io
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/MockSecretStore.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/MockSecretStore.java
new file mode 100644
index 00000000000..2f934e69798
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/MockSecretStore.java
@@ -0,0 +1,48 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller;
+
+import com.yahoo.component.AbstractComponent;
+import com.yahoo.container.jdisc.secretstore.SecretStore;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * @author mpolden
+ */
+public class MockSecretStore extends AbstractComponent implements SecretStore {
+
+ private final Map<String, TreeMap<Integer, String>> secrets = new HashMap<>();
+
+ public MockSecretStore setSecret(String name, String value, int version) {
+ TreeMap<Integer, String> values = secrets.getOrDefault(name, new TreeMap<>());
+ values.put(version, value);
+ secrets.put(name, values);
+ return this;
+ }
+
+ public MockSecretStore setSecret(String name, String value) {
+ return setSecret(name, value, 1);
+ }
+
+ public MockSecretStore clear() {
+ secrets.clear();
+ return this;
+ }
+
+ @Override
+ public String getSecret(String key) {
+ TreeMap<Integer, String> values = secrets.get(key);
+ if (values == null || values.isEmpty()) {
+ return null;
+ }
+ return values.lastEntry().getValue();
+ }
+
+ @Override
+ public String getSecret(String key, int version) {
+ return secrets.getOrDefault(key, new TreeMap<>()).get(version);
+ }
+
+}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageClientTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageClientTest.java
new file mode 100644
index 00000000000..378e4298552
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageClientTest.java
@@ -0,0 +1,44 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller.restapi.statuspage;
+
+import org.junit.Test;
+
+import java.net.URI;
+import java.util.Optional;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author mpolden
+ */
+public class StatusPageClientTest {
+
+ @Test
+ public void test_url_building() {
+ {
+ URI apiUrl = URI.create("https://statuspage.io");
+ String secret = "testpage:testkey";
+ assertEquals("https://testpage.statuspage.io/api/v2/incidents.json?api_key=testkey",
+ StatusPageClient.create(apiUrl, secret).pageUrl("incidents", Optional.empty()).toString());
+ assertEquals("https://testpage.statuspage.io/api/v2/scheduled-maintenances.json?api_key=testkey&since=2015-01-01T00%3A00%2B00%3A00",
+ StatusPageClient.create(apiUrl, secret).pageUrl("scheduled-maintenances",
+ Optional.of("2015-01-01T00:00+00:00")).toString());
+ }
+
+ {
+ URI apiUrl = URI.create("http://foo.bar");
+ assertEquals("http://foo.bar/api/v2/incidents.json?api_key=testkey",
+ StatusPageClient.create(apiUrl, "testpage:testkey").pageUrl("incidents", Optional.empty()).toString());
+ }
+
+ {
+ try {
+ URI apiUrl = URI.create("http://foo.bar");
+ assertEquals("http://foo.bar/api/v2/incidents.json?api_key=testkey",
+ StatusPageClient.create(apiUrl, "").pageUrl("incidents", Optional.empty()).toString());
+ fail("Expected exception");
+ } catch (IllegalArgumentException ignored) {}
+ }
+ }
+
+}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageProxyApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageProxyApiTest.java
new file mode 100644
index 00000000000..181e4386df6
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/statuspage/StatusPageProxyApiTest.java
@@ -0,0 +1,93 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller.restapi.statuspage;
+
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
+import com.yahoo.application.Networking;
+import com.yahoo.application.container.JDisc;
+import com.yahoo.application.container.handler.Request;
+import com.yahoo.application.container.handler.Response;
+import com.yahoo.vespa.hosted.controller.MockSecretStore;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.okJson;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author mpolden
+ */
+public class StatusPageProxyApiTest {
+
+ private JDisc container;
+
+ @Before
+ public void startContainer() {
+ container = JDisc.fromServicesXml(servicesXml(), Networking.disable);
+ secretStore().setSecret("vespa_hosted.controller.statuspage_api_key", "page-id:secret");
+ }
+
+ @After
+ public void stopContainer() {
+ container.close();
+ secretStore().clear();
+ }
+
+ @Rule
+ public final WireMockRule wireMock = new WireMockRule(options().dynamicPort(), true);
+
+ @Test
+ public void test_proxy() throws Exception {
+ // Invalid requests
+ assertResponse("/statuspage/v1/", "{\"error-code\":\"NOT_FOUND\",\"message\":\"Nothing at path '/statuspage/v1'\"}", 404);
+ assertResponse("/statuspage/v1/invalid", "{\"error-code\":\"BAD_REQUEST\",\"message\":\"Invalid resource: 'invalid'\"}", 400);
+ assertResponse(Request.Method.POST, "/statuspage/v1/invalid", "{\"error-code\":\"METHOD_NOT_ALLOWED\",\"message\":\"Method 'POST' is not supported\"}", 405);
+
+ // Mock responses from StatusPage
+ wireMock.stubFor(get(urlEqualTo("/api/v2/incidents.json?api_key=secret"))
+ .willReturn(okJson("{\"incidents\":[]}")));
+ wireMock.stubFor(get(urlEqualTo("/api/v2/scheduled-maintenances.json?api_key=secret"))
+ .willReturn(okJson("{\"scheduled_maintenances\":[]}")));
+
+ assertResponse("/statuspage/v1/incidents", "{\"incidents\":[]}", 200);
+ assertResponse("/statuspage/v1/scheduled-maintenances", "{\"scheduled_maintenances\":[]}", 200);
+ }
+
+ private void assertResponse(String path, String expectedResponse, int expectedStatusCode) throws IOException {
+ assertResponse(Request.Method.GET, path, expectedResponse, expectedStatusCode);
+ }
+
+ private void assertResponse(Request.Method method, String path, String expectedResponse, int expectedStatusCode) throws IOException {
+ Response response = container.handleRequest(new Request("http://localhost:8080" + path, new byte[0], method));
+ assertEquals(expectedResponse, response.getBodyAsString());
+ assertEquals("Status code", expectedStatusCode, response.getStatus());
+ assertEquals("application/json; charset=UTF-8", response.getHeaders().getFirst("Content-Type"));
+ }
+
+ private MockSecretStore secretStore() {
+ return (MockSecretStore) container.components().getComponent(MockSecretStore.class.getName());
+ }
+
+ private String servicesXml() {
+ String statusPageApiUrl = "http://127.0.0.1:" + wireMock.port();
+ return "<jdisc version='1.0'>\n" +
+ " <config name='vespa.hosted.controller.statuspage.config.statuspage'>\n" +
+ " <apiUrl>" + statusPageApiUrl + "</apiUrl>\n" +
+ " </config>\n" +
+ " <component id='com.yahoo.vespa.hosted.controller.MockSecretStore'/>\n" +
+ " <handler id='com.yahoo.vespa.hosted.controller.restapi.statuspage.StatusPageProxyHandler'>\n" +
+ " <binding>http://*/statuspage/v1/*</binding>\n" +
+ " </handler>\n" +
+ " <http>\n" +
+ " <server id='default' port='8080'/>\n" +
+ " </http>\n" +
+ "</jdisc>";
+ }
+
+}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/restapi/impl/StatusPageResourceTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/restapi/impl/StatusPageResourceTest.java
deleted file mode 100644
index 429e1ea2b8d..00000000000
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/restapi/impl/StatusPageResourceTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.hosted.restapi.impl;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.yahoo.container.jdisc.secretstore.SecretStore;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.Invocation;
-import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.UriBuilder;
-import java.io.IOException;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-/**
- * @author frodelu
- */
-public class StatusPageResourceTest {
-
- private StatusPageResource statusPage;
-
- @Before
- public void setup() throws IOException {
-
- Client mockClient = Mockito.mock(Client.class);
- WebTarget mockTarget = Mockito.mock(WebTarget.class);
- Invocation.Builder mockRequest = Mockito.mock(Invocation.Builder.class);
- SecretStore secretStore = Mockito.mock(SecretStore.class);
-
- Mockito.when(mockClient.target(Mockito.any(UriBuilder.class))).thenReturn(mockTarget);
- Mockito.when(mockTarget.request()).thenReturn(mockRequest);
- Mockito.when(mockRequest.get(JsonNode.class)).thenReturn(
- new ObjectMapper().readTree("{\"page\":{\"name\":\"Vespa\"}}"));
- Mockito.when(secretStore.getSecret(Mockito.any(String.class))).thenReturn("testpage:testkey");
-
- statusPage = new StatusPageResource(secretStore, mockClient);
- }
-
-
- @Test
- public void default_url() {
- UriBuilder uri = statusPage.statusPageURL("incidents", null);
- assertNotNull("URI not initialized", uri);
- assertEquals("https://testpage.statuspage.io/api/v2/incidents.json?api_key=testkey", uri.toTemplate());
- }
-
- @Test
- public void url_with_since_param() {
- UriBuilder uri = statusPage.statusPageURL("incidents", "2015-01-01T00:00+00:00");
- assertNotNull("URI not initialized", uri);
- assertEquals("https://testpage.statuspage.io/api/v2/incidents.json?api_key=testkey&since=2015-01-01T00%3A00%2B00%3A00", uri.toTemplate());
- }
-
- @Test
- public void valid_status_page() {
- JsonNode result = statusPage.statusPage("incidents", null);
- assertNotNull("No result from StatusPage.io", result);
- assertEquals("Vespa", result.get("page").get("name").asText());
- }
-}