diff options
author | Piotr Wielebski <piotr.wielebski@nokia.com> | 2019-06-12 11:56:13 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@onap.org> | 2019-06-12 11:56:13 +0000 |
commit | a5b37327f23ec512e2ab64394ec4029e773af238 (patch) | |
tree | 3b397ea1c476b66b179f5f7f8d44b590439b6e75 /standardization/moher-api/server-adapters | |
parent | e655bbdb2e7d17660b34c7af236e7afb4ccda25a (diff) | |
parent | 3d6feef167f8e8eb716312599132c41dd89457cb (diff) |
Merge "Monitoring API - write framework adapters"
Diffstat (limited to 'standardization/moher-api/server-adapters')
12 files changed, 678 insertions, 36 deletions
diff --git a/standardization/moher-api/server-adapters/pom.xml b/standardization/moher-api/server-adapters/pom.xml index 4b8f4a55..94d83473 100644 --- a/standardization/moher-api/server-adapters/pom.xml +++ b/standardization/moher-api/server-adapters/pom.xml @@ -35,7 +35,7 @@ <packaging>pom</packaging> <modules> - <module>spring</module> + <module>spring-webflux</module> <module>reactor-netty</module> </modules> </project>
\ No newline at end of file diff --git a/standardization/moher-api/server-adapters/reactor-netty/pom.xml b/standardization/moher-api/server-adapters/reactor-netty/pom.xml index f2f37412..9ae7df4c 100644 --- a/standardization/moher-api/server-adapters/reactor-netty/pom.xml +++ b/standardization/moher-api/server-adapters/reactor-netty/pom.xml @@ -32,4 +32,34 @@ <description>MoHeR Project Reactor's Netty server adapter</description> <artifactId>dcae-sdk-moher-reactor-netty</artifactId> + <dependencies> + <dependency> + <groupId>io.projectreactor.netty</groupId> + <artifactId>reactor-netty</artifactId> + </dependency> + <dependency> + <groupId>org.onap.dcaegen2.services.sdk</groupId> + <artifactId>dcaegen2-sdk-moher-metrics</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.dcaegen2.services.sdk</groupId> + <artifactId>dcaegen2-sdk-moher-healthstate</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + </dependency> + <dependency> + <groupId>org.onap.dcaegen2.services.sdk.rest.services</groupId> + <artifactId>http-client</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + </dependencies> </project>
\ No newline at end of file diff --git a/standardization/moher-api/server-adapters/reactor-netty/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/reactornetty/HealthRoutes.java b/standardization/moher-api/server-adapters/reactor-netty/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/reactornetty/HealthRoutes.java new file mode 100644 index 00000000..1b6411de --- /dev/null +++ b/standardization/moher-api/server-adapters/reactor-netty/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/reactornetty/HealthRoutes.java @@ -0,0 +1,80 @@ +/* + * ============LICENSE_START==================================== + * DCAEGEN2-SERVICES-SDK + * ========================================================= + * Copyright (C) 2019 Nokia. All rights reserved. + * ========================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END===================================== + */ + +package org.onap.dcaegen2.services.sdk.standardization.moher.adapters.reactornetty; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpResponseStatus; +import java.util.function.Consumer; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.AliveMessage; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.GsonAdaptersHealth; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.Health; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.HealthProvider; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; +import reactor.netty.http.server.HttpServerRoutes; + +public class HealthRoutes implements Consumer<HttpServerRoutes> { + + public static final String APPLICATION_JSON = "application/json"; + private final Gson gson; + private final HealthProvider healthProvider; + + public HealthRoutes(Gson gson, + HealthProvider healthProvider) { + this.gson = gson; + this.healthProvider = healthProvider; + } + + public static HealthRoutes create(HealthProvider healthProvider) { + GsonBuilder gson = new GsonBuilder(); + gson.registerTypeAdapterFactory(new GsonAdaptersHealth()); + return new HealthRoutes(gson.create(), healthProvider); + } + + @Override + public void accept(HttpServerRoutes routes) { + routes.get("/health/ready", this::readinessCheck); + routes.get("/health/alive", this::livenessCheck); + } + + private Publisher<Void> readinessCheck(HttpServerRequest httpServerRequest, HttpServerResponse httpServerResponse) { + return healthProvider.currentHealth() + .flatMapMany(health -> + httpServerResponse.status(statusForHealth(health)) + .header(HttpHeaderNames.CONTENT_TYPE, APPLICATION_JSON) + .sendString(Mono.just(health).map(gson::toJson)) + ); + } + + private Publisher<Void> livenessCheck(HttpServerRequest httpServerRequest, HttpServerResponse httpServerResponse) { + return httpServerResponse.status(HttpResponseStatus.OK) + .header(HttpHeaderNames.CONTENT_TYPE, APPLICATION_JSON) + .sendString(Mono.just(AliveMessage.ALIVE_MESSAGE_JSON)); + } + + private HttpResponseStatus statusForHealth(Health health) { + return health.healthy() ? HttpResponseStatus.OK : HttpResponseStatus.SERVICE_UNAVAILABLE; + } +} diff --git a/standardization/moher-api/server-adapters/reactor-netty/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/reactornetty/MetricsRoutes.java b/standardization/moher-api/server-adapters/reactor-netty/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/reactornetty/MetricsRoutes.java new file mode 100644 index 00000000..b6db874d --- /dev/null +++ b/standardization/moher-api/server-adapters/reactor-netty/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/reactornetty/MetricsRoutes.java @@ -0,0 +1,49 @@ +/* + * ============LICENSE_START==================================== + * DCAEGEN2-SERVICES-SDK + * ========================================================= + * Copyright (C) 2019 Nokia. All rights reserved. + * ========================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END===================================== + */ + +package org.onap.dcaegen2.services.sdk.standardization.moher.adapters.reactornetty; + +import java.util.function.Consumer; +import org.onap.dcaegen2.services.sdk.standardization.moher.metrics.api.Metrics; +import org.reactivestreams.Publisher; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; +import reactor.netty.http.server.HttpServerRoutes; + +public class MetricsRoutes implements Consumer<HttpServerRoutes> { + + private final Metrics metrics; + + public MetricsRoutes(Metrics metrics) { + this.metrics = metrics; + } + + @Override + public void accept(HttpServerRoutes routes) { + routes.get("/metrics", this::prometheusMetrics); + } + + private Publisher<Void> prometheusMetrics( + HttpServerRequest httpServerRequest, + HttpServerResponse httpServerResponse) { + return httpServerResponse.sendString(metrics.collect()); + } + +} diff --git a/standardization/moher-api/server-adapters/reactor-netty/src/test/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/reactornetty/HealthRoutesIT.java b/standardization/moher-api/server-adapters/reactor-netty/src/test/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/reactornetty/HealthRoutesIT.java new file mode 100644 index 00000000..367f50e3 --- /dev/null +++ b/standardization/moher-api/server-adapters/reactor-netty/src/test/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/reactornetty/HealthRoutesIT.java @@ -0,0 +1,122 @@ +/* + * ============LICENSE_START==================================== + * DCAEGEN2-SERVICES-SDK + * ========================================================= + * Copyright (C) 2019 Nokia. All rights reserved. + * ========================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END===================================== + */ + +package org.onap.dcaegen2.services.sdk.standardization.moher.adapters.reactornetty; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.onap.dcaegen2.services.sdk.rest.services.adapters.http.HttpMethod; +import org.onap.dcaegen2.services.sdk.rest.services.adapters.http.HttpResponse; +import org.onap.dcaegen2.services.sdk.rest.services.adapters.http.ImmutableHttpRequest; +import org.onap.dcaegen2.services.sdk.rest.services.adapters.http.RxHttpClient; +import org.onap.dcaegen2.services.sdk.rest.services.adapters.http.RxHttpClientFactory; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.AliveMessage; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.GsonAdaptersHealth; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.Health; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.HealthProvider; +import reactor.netty.DisposableServer; +import reactor.netty.http.server.HttpServer; + +class HealthRoutesIT { + + private static final Duration TIMEOUT = Duration.ofSeconds(5); + private final AtomicReference<Health> currentHealth = new AtomicReference<>(); + private final HealthRoutes sut = HealthRoutes.create(HealthProvider.fromSupplier(currentHealth::get)); + private final RxHttpClient rxHttpClient = RxHttpClientFactory.create(); + private final Gson gsonForDeserialization = new GsonBuilder() + .registerTypeAdapterFactory(new GsonAdaptersHealth()) + .create(); + private DisposableServer server; + private String baseUrl; + + @BeforeEach + void setUp() { + server = HttpServer.create().route(sut).bindNow(); + baseUrl = String.format("http://%s:%d", server.host(), server.port()); + } + + @AfterEach + void tearDown() { + server.disposeNow(TIMEOUT); + } + + @Test + void readinessProbeShouldReturnOkWhenHealthy() { + // given + final Health expectedHealth = Health.createHealthy("Ready to go"); + currentHealth.set(expectedHealth); + final String url = baseUrl + "/health/ready"; + + // when + final HttpResponse response = rxHttpClient + .call(ImmutableHttpRequest.builder().method(HttpMethod.GET).url(url).build()) + .block(TIMEOUT); + + // then + assertThat(response.successful()).describedAs("response should be successful").isTrue(); + final Health actualHealth = response.bodyAsJson(StandardCharsets.UTF_8, gsonForDeserialization, Health.class); + assertThat(actualHealth).describedAs("response body").isEqualTo(expectedHealth); + } + + @Test + void readinessProbeShouldReturnUnavailableWhenNotHealthy() { + // given + final Health expectedHealth = Health.createUnhealthy("Waiting for CBS update"); + currentHealth.set(expectedHealth); + final String url = baseUrl + "/health/ready"; + + // when + final HttpResponse response = rxHttpClient + .call(ImmutableHttpRequest.builder().method(HttpMethod.GET).url(url).build()) + .block(TIMEOUT); + + // then + assertThat(response.statusCode()).describedAs("response status code") + .isGreaterThanOrEqualTo(500) + .isLessThan(600); + assertThat(response.successful()).describedAs("response should not be successful").isFalse(); + final Health actualHealth = response.bodyAsJson(StandardCharsets.UTF_8, gsonForDeserialization, Health.class); + assertThat(actualHealth).describedAs("response body").isEqualTo(expectedHealth); + } + + @Test + void livenessProbeShouldAlwaysReturnOk() { + // given + final String url = baseUrl + "/health/alive"; + + // when + final HttpResponse response = rxHttpClient + .call(ImmutableHttpRequest.builder().method(HttpMethod.GET).url(url).build()) + .block(TIMEOUT); + + // then + assertThat(response.successful()).describedAs("response should be successful").isTrue(); + assertThat(response.bodyAsString()).describedAs("response body").isEqualTo(AliveMessage.ALIVE_MESSAGE_JSON); + } + +}
\ No newline at end of file diff --git a/standardization/moher-api/server-adapters/reactor-netty/src/test/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/reactornetty/MetricsRoutesIT.java b/standardization/moher-api/server-adapters/reactor-netty/src/test/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/reactornetty/MetricsRoutesIT.java new file mode 100644 index 00000000..55c24c73 --- /dev/null +++ b/standardization/moher-api/server-adapters/reactor-netty/src/test/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/reactornetty/MetricsRoutesIT.java @@ -0,0 +1,71 @@ +/* + * ============LICENSE_START==================================== + * DCAEGEN2-SERVICES-SDK + * ========================================================= + * Copyright (C) 2019 Nokia. All rights reserved. + * ========================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END===================================== + */ + +package org.onap.dcaegen2.services.sdk.standardization.moher.adapters.reactornetty; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.Duration; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.onap.dcaegen2.services.sdk.rest.services.adapters.http.HttpMethod; +import org.onap.dcaegen2.services.sdk.rest.services.adapters.http.HttpResponse; +import org.onap.dcaegen2.services.sdk.rest.services.adapters.http.ImmutableHttpRequest; +import org.onap.dcaegen2.services.sdk.rest.services.adapters.http.RxHttpClient; +import org.onap.dcaegen2.services.sdk.rest.services.adapters.http.RxHttpClientFactory; +import org.onap.dcaegen2.services.sdk.standardization.moher.metrics.api.Metrics; +import org.onap.dcaegen2.services.sdk.standardization.moher.metrics.api.MetricsFactory; +import reactor.netty.DisposableServer; +import reactor.netty.http.server.HttpServer; + +class MetricsRoutesIT { + + private static final Duration TIMEOUT = Duration.ofSeconds(5); + private final Metrics metrics = MetricsFactory.createMetrics(MetricsFactory.createDefaultRegistry()); + private final MetricsRoutes sut = new MetricsRoutes(metrics); + private final RxHttpClient rxHttpClient = RxHttpClientFactory.create(); + private DisposableServer server; + + @BeforeEach + void setUp() { + server = HttpServer.create().route(sut).bindNow(); + } + + @AfterEach + void tearDown() { + server.disposeNow(TIMEOUT); + } + + @Test + void prometheusMetrics() { + // given + final String url = String.format("http://%s:%d/metrics", server.host(), server.port()); + + // when + final HttpResponse response = rxHttpClient + .call(ImmutableHttpRequest.builder().method(HttpMethod.GET).url(url).build()) + .block(TIMEOUT); + + // then + assertThat(response.successful()).describedAs("response should be successfull").isTrue(); + assertThat(response.bodyAsString()).describedAs("response body").contains("system_cpu", "jvm_classes"); + } +}
\ No newline at end of file diff --git a/standardization/moher-api/server-adapters/spring-webflux/pom.xml b/standardization/moher-api/server-adapters/spring-webflux/pom.xml new file mode 100644 index 00000000..7eff97aa --- /dev/null +++ b/standardization/moher-api/server-adapters/spring-webflux/pom.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ ============LICENSE_START======================================================= + ~ DCAEGEN2-SERVICES-SDK + ~ ================================================================================ + ~ Copyright (C) 2019 Nokia + ~ ================================================================================ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ ============LICENSE_END========================================================= + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <artifactId>dcaegen2-sdk-moher-server-adapters</artifactId> + <groupId>org.onap.dcaegen2.services.sdk</groupId> + <version>1.2.0-SNAPSHOT</version> + </parent> + + <name>Monitoring and Healthcheck :: Server Adapters :: Spring Webflux</name> + <description>MoHeR Spring server adapter</description> + <artifactId>dcae-sdk-moher-spring-webflux</artifactId> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-failsafe-plugin</artifactId> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-webflux</artifactId> + </dependency> + <dependency> + <groupId>org.onap.dcaegen2.services.sdk</groupId> + <artifactId>dcaegen2-sdk-moher-metrics</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.dcaegen2.services.sdk</groupId> + <artifactId>dcaegen2-sdk-moher-healthstate</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-core</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + </dependency> + <dependency> + <artifactId>spring-boot-starter-webflux</artifactId> + <groupId>org.springframework.boot</groupId> + <scope>test</scope> + </dependency> + </dependencies> +</project>
\ No newline at end of file diff --git a/standardization/moher-api/server-adapters/spring-webflux/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/springwebflux/HealthController.java b/standardization/moher-api/server-adapters/spring-webflux/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/springwebflux/HealthController.java new file mode 100644 index 00000000..1f9eb4b0 --- /dev/null +++ b/standardization/moher-api/server-adapters/spring-webflux/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/springwebflux/HealthController.java @@ -0,0 +1,72 @@ +/* + * ============LICENSE_START==================================== + * DCAEGEN2-SERVICES-SDK + * ========================================================= + * Copyright (C) 2019 Nokia. All rights reserved. + * ========================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END===================================== + */ + +package org.onap.dcaegen2.services.sdk.standardization.moher.adapters.springwebflux; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.AliveMessage; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.GsonAdaptersHealth; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.Health; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.HealthProvider; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; + +@RestController +@RequestMapping(value = "/health", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) +public class HealthController { + private final Gson gson; + private final HealthProvider healthProvider; + + public static HealthController create(HealthProvider healthProvider) { + GsonBuilder gson = new GsonBuilder(); + gson.registerTypeAdapterFactory(new GsonAdaptersHealth()); + return new HealthController(gson.create(), healthProvider); + } + + public HealthController(Gson gson, HealthProvider healthProvider) { + this.gson = gson; + this.healthProvider = healthProvider; + } + + @GetMapping("/ready") + public Mono<ResponseEntity<String>> readinessCheck() { + return healthProvider.currentHealth() + .map(health -> responseStatusForHealth(health) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .body(gson.toJson(health))); + } + + @GetMapping("/alive") + public Mono<String> livenessCheck() { + return Mono.just(AliveMessage.ALIVE_MESSAGE_JSON); + } + + private ResponseEntity.BodyBuilder responseStatusForHealth(Health health) { + return health.healthy() + ? ResponseEntity.ok() + : ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE); + } +} diff --git a/standardization/moher-api/server-adapters/spring-webflux/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/springwebflux/MetricsController.java b/standardization/moher-api/server-adapters/spring-webflux/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/springwebflux/MetricsController.java new file mode 100644 index 00000000..4ce4fd12 --- /dev/null +++ b/standardization/moher-api/server-adapters/spring-webflux/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/springwebflux/MetricsController.java @@ -0,0 +1,43 @@ +/* + * ============LICENSE_START==================================== + * DCAEGEN2-SERVICES-SDK + * ========================================================= + * Copyright (C) 2019 Nokia. All rights reserved. + * ========================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END===================================== + */ + +package org.onap.dcaegen2.services.sdk.standardization.moher.adapters.springwebflux; + +import org.onap.dcaegen2.services.sdk.standardization.moher.metrics.api.Metrics; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; + +@RestController +@RequestMapping(value = "/metrics", produces = MediaType.TEXT_PLAIN_VALUE) +public class MetricsController { + private final Metrics metrics; + + public MetricsController(Metrics metrics) { + this.metrics = metrics; + } + + @GetMapping + public Mono<String> prometheusMetrics() { + return metrics.collect(); + } +} diff --git a/standardization/moher-api/server-adapters/spring-webflux/src/test/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/springwebflux/HealthControllerIT.java b/standardization/moher-api/server-adapters/spring-webflux/src/test/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/springwebflux/HealthControllerIT.java new file mode 100644 index 00000000..236cc16f --- /dev/null +++ b/standardization/moher-api/server-adapters/spring-webflux/src/test/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/springwebflux/HealthControllerIT.java @@ -0,0 +1,81 @@ +/* + * ============LICENSE_START==================================== + * DCAEGEN2-SERVICES-SDK + * ========================================================= + * Copyright (C) 2019 Nokia. All rights reserved. + * ========================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END===================================== + */ + +package org.onap.dcaegen2.services.sdk.standardization.moher.adapters.springwebflux; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.atomic.AtomicReference; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import org.junit.jupiter.api.Test; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.AliveMessage; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.GsonAdaptersHealth; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.Health; +import org.onap.dcaegen2.services.sdk.standardization.moher.health.api.HealthProvider; +import org.springframework.http.MediaType; +import org.springframework.test.web.reactive.server.WebTestClient; + +import reactor.core.publisher.Mono; + +class HealthControllerIT { + + private final AtomicReference<Health> currentHealth = new AtomicReference<>(); + private final HealthProvider healthProvider = () -> Mono.fromCallable(currentHealth::get); + private final HealthController sut = HealthController.create(healthProvider); + private final WebTestClient client = WebTestClient.bindToController(sut).build(); + private final Gson gsonForDeserialization = new GsonBuilder().registerTypeAdapterFactory(new GsonAdaptersHealth()) + .create(); + + @Test + void readinessProbeShouldReturnOkWhenHealthy() { + final Health expectedHealth = Health.createHealthy("Ready to go"); + currentHealth.set(expectedHealth); + + client.get().uri("/health/ready").accept(MediaType.APPLICATION_JSON).exchange().expectStatus().isOk() + .expectBody(String.class).value(body -> { + final Health actualHealth = gsonForDeserialization.fromJson(body, Health.class); + assertThat(actualHealth).isEqualTo(expectedHealth); + }); + } + + @Test + void readinessProbeShouldReturnUnavailableWhenNotHealthy() { + final Health expectedHealth = Health.createUnhealthy("Waiting for CBS update"); + currentHealth.set(expectedHealth); + + client.get().uri("/health/ready").accept(MediaType.APPLICATION_JSON).exchange().expectStatus() + .is5xxServerError().expectBody(String.class).value(body -> { + final Health actualHealth = gsonForDeserialization.fromJson(body, Health.class); + assertThat(actualHealth).isEqualTo(expectedHealth); + }); + } + + @Test + void livenessProbeShouldAlwaysReturnOk() { + client.get().uri("/health/alive").accept(MediaType.APPLICATION_JSON).exchange().expectStatus().isOk() + .expectBody(String.class).value(body -> { + assertThat(body).isEqualTo(AliveMessage.ALIVE_MESSAGE_JSON); + }); + } + +} diff --git a/standardization/moher-api/server-adapters/spring-webflux/src/test/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/springwebflux/MetricsControllerIT.java b/standardization/moher-api/server-adapters/spring-webflux/src/test/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/springwebflux/MetricsControllerIT.java new file mode 100644 index 00000000..32d00449 --- /dev/null +++ b/standardization/moher-api/server-adapters/spring-webflux/src/test/java/org/onap/dcaegen2/services/sdk/standardization/moher/adapters/springwebflux/MetricsControllerIT.java @@ -0,0 +1,48 @@ +/* + * ============LICENSE_START==================================== + * DCAEGEN2-SERVICES-SDK + * ========================================================= + * Copyright (C) 2019 Nokia. All rights reserved. + * ========================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END===================================== + */ + +package org.onap.dcaegen2.services.sdk.standardization.moher.adapters.springwebflux; + + +import static org.assertj.core.api.Assertions.assertThat; + +import io.micrometer.prometheus.PrometheusMeterRegistry; +import org.junit.jupiter.api.Test; +import org.onap.dcaegen2.services.sdk.standardization.moher.metrics.api.Metrics; +import org.onap.dcaegen2.services.sdk.standardization.moher.metrics.api.MetricsFactory; +import org.springframework.http.MediaType; +import org.springframework.test.web.reactive.server.WebTestClient; + +class MetricsControllerIT { + + private final PrometheusMeterRegistry defaultRegistry = MetricsFactory.createDefaultRegistry(); + private final Metrics metrics = MetricsFactory.createMetrics(defaultRegistry); + private final MetricsController sut = new MetricsController(metrics); + private final WebTestClient client = WebTestClient.bindToController(sut).build(); + + @Test + void prometheusMetrics() { + client.get().uri("/metrics").accept(MediaType.ALL).exchange() + .expectStatus().isOk() + .expectHeader().contentTypeCompatibleWith(MediaType.TEXT_PLAIN) + .expectBody(String.class) + .value(body -> assertThat(body).contains("system_cpu").contains("jvm_classes")); + } +} diff --git a/standardization/moher-api/server-adapters/spring/pom.xml b/standardization/moher-api/server-adapters/spring/pom.xml deleted file mode 100644 index 52f1dad2..00000000 --- a/standardization/moher-api/server-adapters/spring/pom.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ ============LICENSE_START======================================================= - ~ DCAEGEN2-SERVICES-SDK - ~ ================================================================================ - ~ Copyright (C) 2019 Nokia - ~ ================================================================================ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - ~ ============LICENSE_END========================================================= - --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <artifactId>dcaegen2-sdk-moher-server-adapters</artifactId> - <groupId>org.onap.dcaegen2.services.sdk</groupId> - <version>1.2.0-SNAPSHOT</version> - </parent> - - <name>Monitoring and Healthcheck :: Server Adapters :: Spring</name> - <description>MoHeR Spring server adapter</description> - <artifactId>dcae-sdk-moher-spring</artifactId> - -</project>
\ No newline at end of file |