diff options
24 files changed, 846 insertions, 52 deletions
@@ -173,6 +173,9 @@ fabric.properties # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* +# VSCode +.vscode/ + ### Maven ### # Maven target @@ -185,4 +188,4 @@ release.properties dependency-reduced-pom.xml buildNumber.properties .mvn/timing.properties -.mvn/wrapper/maven-wrapper.jar
\ No newline at end of file +.mvn/wrapper/maven-wrapper.jar @@ -40,8 +40,8 @@ <commons-text.version>1.6</commons-text.version> <jetbrains-annotations.version>16.0.3</jetbrains-annotations.version> <protoc-jar-maven-plugin.version>3.6.0.2</protoc-jar-maven-plugin.version> - <micrometer.version>1.1.4</micrometer.version> <testcontainers.version>1.11.2</testcontainers.version> + <spring.boot.version>2.1.5.RELEASE</spring.boot.version> </properties> <modules> @@ -165,6 +165,7 @@ <groupId>org.immutables</groupId> <artifactId>value</artifactId> <version>${immutables.version}</version> + <scope>provided</scope> </dependency> <dependency> <groupId>org.immutables</groupId> @@ -197,6 +198,13 @@ <version>${slf4j.version}</version> </dependency> <dependency> + <artifactId>spring-boot-dependencies</artifactId> + <groupId>org.springframework.boot</groupId> + <version>${spring.boot.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + <dependency> <groupId>org.jetbrains</groupId> <artifactId>annotations</artifactId> <version>${jetbrains-annotations.version}</version> @@ -220,16 +228,6 @@ <version>1.7.26</version> <scope>runtime</scope> </dependency> - <dependency> - <groupId>io.micrometer</groupId> - <artifactId>micrometer-registry-prometheus</artifactId> - <version>${micrometer.version}</version> - </dependency> - <dependency> - <groupId>org.springframework.security</groupId> - <artifactId>spring-security-crypto</artifactId> - <version>5.0.12.RELEASE</version> - </dependency> <dependency> <groupId>org.mockito</groupId> diff --git a/rest-services/aai-client/pom.xml b/rest-services/aai-client/pom.xml index 7c63f4b0..6a695b0f 100644 --- a/rest-services/aai-client/pom.xml +++ b/rest-services/aai-client/pom.xml @@ -28,7 +28,10 @@ <artifactId>ssl</artifactId> <version>${project.version}</version> </dependency> - + <dependency> + <groupId>org.immutables</groupId> + <artifactId>value</artifactId> + </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-text</artifactId> diff --git a/rest-services/cbs-client/pom.xml b/rest-services/cbs-client/pom.xml index 7d044dce..538950fa 100644 --- a/rest-services/cbs-client/pom.xml +++ b/rest-services/cbs-client/pom.xml @@ -28,6 +28,10 @@ <artifactId>model</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.immutables</groupId> + <artifactId>value</artifactId> + </dependency> <dependency> <groupId>org.mockito</groupId> diff --git a/rest-services/dmaap-client/pom.xml b/rest-services/dmaap-client/pom.xml index 86a4ab07..a8ee7391 100644 --- a/rest-services/dmaap-client/pom.xml +++ b/rest-services/dmaap-client/pom.xml @@ -46,6 +46,10 @@ <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </dependency> + <dependency> + <groupId>org.immutables</groupId> + <artifactId>value</artifactId> + </dependency> <dependency> <groupId>org.junit.jupiter</groupId> diff --git a/rest-services/http-client/pom.xml b/rest-services/http-client/pom.xml index 1d321058..ba6b2fd0 100644 --- a/rest-services/http-client/pom.xml +++ b/rest-services/http-client/pom.xml @@ -58,6 +58,10 @@ <artifactId>vavr</artifactId> </dependency> <dependency> + <groupId>org.immutables</groupId> + <artifactId>value</artifactId> + </dependency> + <dependency> <groupId>org.jetbrains</groupId> <artifactId>annotations</artifactId> </dependency> diff --git a/security/ssl/src/test/java/org/onap/dcaegen2/services/sdk/security/ssl/PasswordTest.java b/security/ssl/src/test/java/org/onap/dcaegen2/services/sdk/security/ssl/PasswordTest.java index 41143f61..03d4ac25 100644 --- a/security/ssl/src/test/java/org/onap/dcaegen2/services/sdk/security/ssl/PasswordTest.java +++ b/security/ssl/src/test/java/org/onap/dcaegen2/services/sdk/security/ssl/PasswordTest.java @@ -24,7 +24,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import io.vavr.collection.Array; -import java.security.GeneralSecurityException; import java.util.Arrays; import org.junit.jupiter.api.Test; import org.onap.dcaegen2.services.sdk.security.ssl.exceptions.PasswordEvictedException; diff --git a/standardization/moher-api/healthstate/pom.xml b/standardization/moher-api/healthstate/pom.xml index d6cf46be..a4036288 100644 --- a/standardization/moher-api/healthstate/pom.xml +++ b/standardization/moher-api/healthstate/pom.xml @@ -33,4 +33,23 @@ <artifactId>dcaegen2-sdk-moher-healthstate</artifactId> + <dependencies> + <dependency> + <groupId>io.vavr</groupId> + <artifactId>vavr + </artifactId> + </dependency> + <dependency> + <groupId>org.immutables</groupId> + <artifactId>value</artifactId> + </dependency> + <dependency> + <groupId>org.immutables</groupId> + <artifactId>gson</artifactId> + </dependency> + <dependency> + <groupId>io.projectreactor</groupId> + <artifactId>reactor-core</artifactId> + </dependency> + </dependencies> </project>
\ No newline at end of file diff --git a/standardization/moher-api/healthstate/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/health/api/AliveMessage.java b/standardization/moher-api/healthstate/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/health/api/AliveMessage.java new file mode 100644 index 00000000..c9a8c226 --- /dev/null +++ b/standardization/moher-api/healthstate/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/health/api/AliveMessage.java @@ -0,0 +1,29 @@ +/* + * ============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.health.api; + +public final class AliveMessage { + + public static final String ALIVE_MESSAGE_JSON = "{\"alive\":true}"; + + private AliveMessage() { + } +} diff --git a/standardization/moher-api/healthstate/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/health/api/Health.java b/standardization/moher-api/healthstate/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/health/api/Health.java new file mode 100644 index 00000000..65b11ad1 --- /dev/null +++ b/standardization/moher-api/healthstate/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/health/api/Health.java @@ -0,0 +1,51 @@ +/* + * ============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.health.api; + +import org.immutables.gson.Gson; +import org.immutables.value.Value; + +@Value.Immutable +@Gson.TypeAdapters +public interface Health { + + @Value.Default + default boolean healthy() { + return true; + } + + @Value.Default + default String description() { + return "Service is working correctly"; + } + + static Health createHealthy() { + return ImmutableHealth.builder().build(); + } + + static Health createHealthy(String description) { + return ImmutableHealth.builder().description(description).build(); + } + + static Health createUnhealthy(String description) { + return ImmutableHealth.builder().healthy(false).description(description).build(); + } +} diff --git a/standardization/moher-api/healthstate/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/health/api/HealthProvider.java b/standardization/moher-api/healthstate/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/health/api/HealthProvider.java new file mode 100644 index 00000000..b6d770a4 --- /dev/null +++ b/standardization/moher-api/healthstate/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/health/api/HealthProvider.java @@ -0,0 +1,38 @@ +/* + * ============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.health.api; + +import io.vavr.Function0; +import java.util.function.Supplier; +import reactor.core.publisher.Mono; + +@FunctionalInterface +public interface HealthProvider { + Mono<Health> currentHealth(); + + static HealthProvider fromFunction(Function0<Health> function) { + return () -> Mono.fromCallable(function::apply); + } + + static HealthProvider fromSupplier(Supplier<Health> function) { + return () -> Mono.fromCallable(function::get); + } +} diff --git a/standardization/moher-api/metrics/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/metrics/impl/MetricsImpl.java b/standardization/moher-api/metrics/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/metrics/impl/MetricsImpl.java index e592d976..8ccce84d 100644 --- a/standardization/moher-api/metrics/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/metrics/impl/MetricsImpl.java +++ b/standardization/moher-api/metrics/src/main/java/org/onap/dcaegen2/services/sdk/standardization/moher/metrics/impl/MetricsImpl.java @@ -42,13 +42,13 @@ public class MetricsImpl implements Metrics { @Override public Mono<String> collect() { - return Mono.just(registry.scrape()); + return Mono.fromCallable(registry::scrape); } @Override public Flux<String> collect(Duration interval) { return Flux.interval(interval) - .map((l) -> registry.scrape()); + .map(l -> registry.scrape()); } @SuppressWarnings("squid:S2095") 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 |