From d56ddeba34cca5cf7bc5f9f2897d47d7783d22d6 Mon Sep 17 00:00:00 2001 From: Sebastian Daschner Date: Tue, 11 Feb 2020 16:39:29 +0300 Subject: [PATCH] added MST application class for health checking; provided test examples; --- .../testing/MicroShedApplication.java | 102 ++++++++++++++++++ .../org/microshed/testing/health/Health.java | 25 +++++ .../src/main/java/org/example/app/Health.java | 18 ++++ .../org/example/app/LibertyAppSmokeIT.java | 43 ++++++++ .../java/org/example/app/LibertySmokeIT.java | 32 ++++++ .../java/org/example/app/TestApplication.java | 45 ++++++++ 6 files changed, 265 insertions(+) create mode 100644 core/src/main/java/org/microshed/testing/MicroShedApplication.java create mode 100644 core/src/main/java/org/microshed/testing/health/Health.java create mode 100644 sample-apps/liberty-app/src/main/java/org/example/app/Health.java create mode 100644 sample-apps/liberty-app/src/test/java/org/example/app/LibertyAppSmokeIT.java create mode 100644 sample-apps/liberty-app/src/test/java/org/example/app/LibertySmokeIT.java create mode 100644 sample-apps/liberty-app/src/test/java/org/example/app/TestApplication.java diff --git a/core/src/main/java/org/microshed/testing/MicroShedApplication.java b/core/src/main/java/org/microshed/testing/MicroShedApplication.java new file mode 100644 index 00000000..741fc3c0 --- /dev/null +++ b/core/src/main/java/org/microshed/testing/MicroShedApplication.java @@ -0,0 +1,102 @@ +package org.microshed.testing; + +import org.microshed.testing.health.Health; +import org.microshed.testing.jaxrs.JsonBProvider; + +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 java.net.URI; +import java.util.Objects; + +/** + * Provides access to an application that implements MicroProfile Health. + * This class can be sub-classed and extended for type-safe, business-specific methods within the project's test scope. + *

+ *

+ * Usage: + *

+ *     MicroShedApplication app = MicroShedApplication.withBaseUri(baseUri).build();
+ *     Health health = app.health();
+ * 
+ *

+ * Or a sub-classed version: + *

+ *     class MyApplication extends MicroShedApplication {
+ *
+ *         MyApplication() {
+ *             super(URI.create("http://my-app:8080/"));
+ *         }
+ *
+ *         // add business-related methods
+ *
+ *         public List getMyCustomers { ... }
+ *     }
+ *
+ *     // in the test code, access health checks, metrics, or business-related methods
+ *
+ *     MyApplication app = new MyApplication();
+ *     Health health = app.health();
+ *     ...
+ *     app.getMyCustomers();
+ *     ...
+ * 
+ */ +public class MicroShedApplication { + + private static final String HEALTH_PATH = "/health"; + + private final String healthPath; + + protected final Client client; + protected final WebTarget rootTarget; + + protected MicroShedApplication(URI baseUri) { + this(baseUri, HEALTH_PATH); + } + + private MicroShedApplication(URI baseUri, String healthPath) { + this.healthPath = healthPath; + + client = ClientBuilder.newBuilder() + .register(JsonBProvider.class) + .build(); + this.rootTarget = client.target(baseUri); + } + + public Health health() { + return rootTarget.path(healthPath) + .request(MediaType.APPLICATION_JSON_TYPE) + .get(Health.class); + } + + public static Builder withBaseUri(String baseUri) { + Objects.requireNonNull(baseUri, "Base URI must not be null"); + Builder builder = new Builder(); + builder.baseUri = URI.create(baseUri); + return builder; + } + + public static Builder withBaseUri(URI baseUri) { + Objects.requireNonNull(baseUri, "Base URI must not be null"); + Builder builder = new Builder(); + builder.baseUri = baseUri; + return builder; + } + + public static class Builder { + + private URI baseUri; + private String healthPath = HEALTH_PATH; + + public Builder healthPath(String healthPath) { + this.healthPath = healthPath; + return this; + } + + public MicroShedApplication build() { + return new MicroShedApplication(baseUri, healthPath); + } + } +} diff --git a/core/src/main/java/org/microshed/testing/health/Health.java b/core/src/main/java/org/microshed/testing/health/Health.java new file mode 100644 index 00000000..225ac7b7 --- /dev/null +++ b/core/src/main/java/org/microshed/testing/health/Health.java @@ -0,0 +1,25 @@ +package org.microshed.testing.health; + +import java.util.ArrayList; +import java.util.List; + +public class Health { + + public Status status; + public List checks = new ArrayList<>(); + + public Check getCheck(String name) { + return checks.stream() + .filter(c -> c.name.equalsIgnoreCase(name)) + .findAny().orElse(null); + } + + public static class Check { + public String name; + public Status status; + } + + public enum Status { + UP, DOWN; + } +} diff --git a/sample-apps/liberty-app/src/main/java/org/example/app/Health.java b/sample-apps/liberty-app/src/main/java/org/example/app/Health.java new file mode 100644 index 00000000..3d2a16f8 --- /dev/null +++ b/sample-apps/liberty-app/src/main/java/org/example/app/Health.java @@ -0,0 +1,18 @@ +package org.example.app; + +import org.eclipse.microprofile.health.HealthCheck; +import org.eclipse.microprofile.health.HealthCheckResponse; +import org.eclipse.microprofile.health.Readiness; + +import javax.enterprise.context.ApplicationScoped; + +@Readiness +@ApplicationScoped +public class Health implements HealthCheck { + + @Override + public HealthCheckResponse call() { + return HealthCheckResponse.named("test-app").up().build(); + } + +} diff --git a/sample-apps/liberty-app/src/test/java/org/example/app/LibertyAppSmokeIT.java b/sample-apps/liberty-app/src/test/java/org/example/app/LibertyAppSmokeIT.java new file mode 100644 index 00000000..6d7d8661 --- /dev/null +++ b/sample-apps/liberty-app/src/test/java/org/example/app/LibertyAppSmokeIT.java @@ -0,0 +1,43 @@ +package org.example.app; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.microshed.testing.health.Health; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * Requires an local environment which is already running. + * Thus enables to decouple the life cycles of the tests and results in a smaller turnaround time. + *

+ * Note that this is a different approach to {@link LibertySmokeIT}. + */ +public class LibertyAppSmokeIT { + + private TestApplication application; + + @BeforeEach + void setUp() { + application = new TestApplication(); + } + + @Test + void testIsSystemUp() { + assertThat(application.health().status, is(org.microshed.testing.health.Health.Status.UP)); + assertThat(application.health().getCheck("test-app").status, is(Health.Status.UP)); + } + + @Test + void testGetAllPeople() { + assertThat(application.getAllPeople().size(), is(2)); + } + + @Test + void testGetPerson() { + Person person = application.getAllPeople().iterator().next(); + + assertThat(application.getPerson(person.id), is(person)); + } + +} diff --git a/sample-apps/liberty-app/src/test/java/org/example/app/LibertySmokeIT.java b/sample-apps/liberty-app/src/test/java/org/example/app/LibertySmokeIT.java new file mode 100644 index 00000000..9dd078c6 --- /dev/null +++ b/sample-apps/liberty-app/src/test/java/org/example/app/LibertySmokeIT.java @@ -0,0 +1,32 @@ +package org.example.app; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.microshed.testing.MicroShedApplication; +import org.microshed.testing.health.Health; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * Requires an local environment which is already running at {@code localhost:9080}. + * Thus enables to decouple the life cycles of the tests and results in a smaller turnaround time. + *

+ * Note that this is a different approach to {@link LibertyAppSmokeIT}. + */ +public class LibertySmokeIT { + + private MicroShedApplication application; + + @BeforeEach + void setUp() { + application = MicroShedApplication.withBaseUri("http://localhost:9080").build(); + } + + @Test + void testIsSystemUp() { + assertThat(application.health().status, is(Health.Status.UP)); + assertThat(application.health().getCheck("test-app").status, is(Health.Status.UP)); + } + +} diff --git a/sample-apps/liberty-app/src/test/java/org/example/app/TestApplication.java b/sample-apps/liberty-app/src/test/java/org/example/app/TestApplication.java new file mode 100644 index 00000000..3ef2885c --- /dev/null +++ b/sample-apps/liberty-app/src/test/java/org/example/app/TestApplication.java @@ -0,0 +1,45 @@ +package org.example.app; + +import org.microshed.testing.MicroShedApplication; +import org.microshed.testing.jaxrs.RestClientBuilder; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.net.URI; +import java.util.Collection; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +public class TestApplication extends MicroShedApplication { + + private PersonService personClient; + + public TestApplication() { + super(URI.create("http://localhost:9080")); + + // we might use either the type-safe RestClient or the rootTarget and client contained in MicroShedApplication + + personClient = new RestClientBuilder() + .withAppContextRoot("http://localhost:9080/myservice") + .build(PersonService.class); + } + + public Collection getAllPeople() { + // different approach to built-in client + return personClient.getAllPeople(); + } + + public Person getPerson(long id) { + // different approach to person client + Response response = rootTarget.path("/myservice") + .path(String.valueOf(id)) + .request(MediaType.APPLICATION_JSON_TYPE) + .get(); + + assertThat(response.getStatus(), is(200)); + + return response.readEntity(Person.class); + } + +}