Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WFLY-12342] Add server probes for readiness health check #223

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,29 @@
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.jboss.eap.qe.microprofile.tooling.server.configuration.creaper.ManagementClientHelper.executeCliCommand;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import org.apache.http.HttpStatus;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.eap.qe.microprofile.health.tools.HealthUrlProvider;
import org.jboss.eap.qe.microprofile.tooling.server.configuration.ConfigurationException;
import org.jboss.eap.qe.microprofile.tooling.server.configuration.creaper.ManagementClientProvider;
import org.jboss.eap.qe.microprofile.tooling.server.configuration.creaper.ManagementClientRelatedException;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.wildfly.extras.creaper.core.online.OnlineManagementClient;
import org.wildfly.extras.creaper.core.online.operations.admin.Administration;

import io.restassured.RestAssured;
import io.restassured.http.ContentType;
Expand All @@ -37,6 +47,7 @@
public class DefaultReadinessProcedureHealthTest {

public static final String ARCHIVE_NAME = DefaultReadinessProcedureHealthTest.class.getSimpleName() + ".war";
private final String CHANGE_H2_DRIVER_NAME_CLI = "/subsystem=datasources/data-source=ExampleDS:write-attribute(name=driver-name, value=%s)";

@Deployment(testable = false)
public static Archive<?> deployment() {
Expand All @@ -47,24 +58,30 @@ public static Archive<?> deployment() {

/**
* @tpTestDetails Calls the deprecated {@code health} endpoint to get response from all health check procedures
* @tpPassCrit Overall health check status is up and two checks are expected to be returned: one {@code liveness}
* @tpPassCrit Overall health check status is up and five checks are expected to be returned: one {@code liveness}
* check - which is defined by the {@link LivenessHealthCheck} annotated class and has "UP" status and data -
* and
* one {@code readiness} check - which is provided by Wildfly because none was defined in the deployment and the
* {@code mp.health.disable-default-procedures} being set to {@code false} by default. This last check must be
* conventionally named after the deplyment name - i.e namely: {@code "ready-deployment." + deployment name}
* With WFLY-12342 There was also added {@code deployments-status}, {@code boot-errors}, {@code server-state}
* checks
* @tpSince EAP 7.4.0.CD19
*/
@Test
public void testHealthEndpoint() throws ConfigurationException {
RestAssured.get(HealthUrlProvider.healthEndpoint()).then()
.assertThat()
.statusCode(HttpStatus.SC_OK)
.contentType(ContentType.JSON)
.body("status", is("UP"),
"checks", hasSize(2),
"checks", hasSize(5),
"checks.status", hasItems("UP", "UP"),
"checks.name", containsInAnyOrder(String.format("ready-deployment.%s", ARCHIVE_NAME), "live"),
"checks.data", hasSize(2),
"checks.data.key", contains("value"));
"checks.name",
containsInAnyOrder("deployments-status", "boot-errors", "server-state",
String.format("ready-deployment.%s", ARCHIVE_NAME), "live"),
"checks.data", hasSize(5),
"checks.find{it.name == 'live'}.data.key", is("value"));
}

/**
Expand All @@ -89,20 +106,107 @@ public void testLivenessEndpoint() throws ConfigurationException {

/**
* @tpTestDetails Calls the {@code ready} endpoint to get response from all {@code readiness} procedures
* @tpPassCrit Overall health check status is up and one check is expected to be returned, i.e the {@code readiness}
* @tpPassCrit Overall health check status is up and four check are expected to be returned, i.e the {@code readiness}
* check which is provided by Wildfly because none was defined in the deployment and the
* {@code mp.health.disable-default-procedures} being set to {@code false} by default. It must be
* conventionally named after the deplyment name - i.e namely: {@code "ready-deployment." + deployment name}
* @tpSince EAP 7.4.0.CD19
*/
@Test
public void testReadinessEndpoint() throws ConfigurationException {
String readyDeploymentCheckName = String.format("ready-deployment.%s", ARCHIVE_NAME);
RestAssured.get(HealthUrlProvider.readyEndpoint()).then()
.contentType(ContentType.JSON)
.body("status", is("UP"),
"checks", hasSize(1),
"checks", hasSize(4),
"checks.status", hasItems("UP"),
"checks.name", contains(String.format("ready-deployment.%s", ARCHIVE_NAME)),
"checks.data", contains(nullValue()));
"checks.name",
containsInAnyOrder("boot-errors", "server-state", "deployments-status",
readyDeploymentCheckName),
"checks.find{it.name == '" + readyDeploymentCheckName + "'}.data", is(nullValue()),
"checks.find{it.name == 'boot-errors'}.data", is(nullValue()),
"checks.find{it.name == 'deployments-status'}.data", is(notNullValue()),
"checks.find{it.name == 'server-state'}.data.value", is("running"));
}

/**
* @tpTestDetails Calls the {@code ready} endpoint to get response from all {@code readiness} procedures. We have
* introduced change which switch server to {@code reload-required} change.
* @tpPassCrit Overall health check status is down and {@code server-state} readiness check is DOWN
* @tpSince EAP 7.4.0.CD21
*/
@Test
public void testServerStateDown() throws ConfigurationException, IOException, ManagementClientRelatedException {
OnlineManagementClient client = ManagementClientProvider.onlineStandalone();
try {
executeCliCommand(client, String.format(CHANGE_H2_DRIVER_NAME_CLI, "wrong_driver_name"));

RestAssured.get(HealthUrlProvider.readyEndpoint()).then()
.contentType(ContentType.JSON)
.body("status", is("DOWN"),
"checks.find{it.name == 'server-state'}.status", is("DOWN"),
"checks.find{it.name == 'deployments-status'}.status", is("UP"),
"checks.find{it.name == 'boot-errors'}.status", is("UP"),
"checks.find{it.name == 'server-state'}.data.value", is("reload-required"));

} finally {
// put back configuration to correct form
executeCliCommand(client, String.format(CHANGE_H2_DRIVER_NAME_CLI, "h2"));
client.close();
}
}

/**
* @tpTestDetails Calls the {@code ready} endpoint to get response from all {@code readiness} procedures. Wrong
* configuration change is introduced which emits exception in server start
* @tpPassCrit Overall health check status is down and {@code boot-errors} readiness check is DOWN
* @tpSince EAP 7.4.0.CD21
*/
@Test
public void testBootErrorsDown() throws ConfigurationException, IOException, ManagementClientRelatedException,
TimeoutException, InterruptedException {
OnlineManagementClient client = ManagementClientProvider.onlineStandalone();
try {
executeCliCommand(client, String.format(CHANGE_H2_DRIVER_NAME_CLI, "wrong_driver_name"));
new Administration(client).reloadIfRequired();

RestAssured.get(HealthUrlProvider.readyEndpoint()).then()
.contentType(ContentType.JSON)
.body("status", is("DOWN"),
"checks.find{it.name == 'boot-errors'}.status", is("DOWN"),
"checks.find{it.name == 'server-state'}.status", is("UP"),
"checks.find{it.name == 'deployments-status'}.status", is("DOWN"),
"checks.find{it.name == 'boot-errors'}.data", is(notNullValue()));
} finally {
// put back configuration to correct form
executeCliCommand(client, String.format(CHANGE_H2_DRIVER_NAME_CLI, "h2"));
new Administration(client).reloadIfRequired();
client.close();
}
}

/**
* @tpTestDetails Calls the {@code ready} endpoint to get response from all {@code readiness} procedures. There is
* one STOPPED deployment which cause deployments-status to be DOWN.
* @tpPassCrit Overall health check status is down and {@code deployments-status} readiness check is DOWN
* @tpSince EAP 7.4.0.CD21
*/
@Test
public void testDeploymentsStatusDown() throws ConfigurationException, IOException, ManagementClientRelatedException {
OnlineManagementClient client = ManagementClientProvider.onlineStandalone();
try {
executeCliCommand(client, "deployment disable " + ARCHIVE_NAME);

RestAssured.get(HealthUrlProvider.readyEndpoint()).then()
.contentType(ContentType.JSON)
.body("status", is("DOWN"),
"checks.find{it.name == 'deployments-status'}.status", is("DOWN"),
"checks.find{it.name == 'server-state'}.status", is("UP"),
"checks.find{it.name == 'boot-errors'}.status", is("UP"),
"checks.find{it.name == 'deployments-status'}.data", is(notNullValue()));
} finally {
executeCliCommand(client, "deployment enable " + ARCHIVE_NAME);
client.close();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.jboss.eap.qe.microprofile.health;

import org.jboss.eap.qe.microprofile.tooling.server.configuration.arquillian.MicroProfileServerSetupTask;
import org.jboss.eap.qe.microprofile.tooling.server.configuration.creaper.ManagementClientProvider;
import org.wildfly.extras.creaper.core.online.OnlineManagementClient;
import org.wildfly.extras.creaper.core.online.operations.admin.Administration;

/**
* Add system property {@code MP_HEALTH_DISABLE_DEFAULT_PROCEDURES} for MP Health to disable vendor specific checks
*/
public class DisableDefaultHealthProceduresSetupTask implements MicroProfileServerSetupTask {

public static final String MP_HEALTH_DISABLE_DEFAULT_PROCEDURES = "mp.health.disable-default-procedures";

@Override
public void setup() throws Exception {
try (OnlineManagementClient client = ManagementClientProvider.onlineStandalone()) {
client.execute(String.format("/system-property=%s:add(value=true)", MP_HEALTH_DISABLE_DEFAULT_PROCEDURES))
.assertSuccess();
new Administration(client).reload();
}
}

@Override
public void tearDown() throws Exception {
try (OnlineManagementClient client = ManagementClientProvider.onlineStandalone()) {
client.execute(String.format("/system-property=%s:remove", MP_HEALTH_DISABLE_DEFAULT_PROCEDURES))
.assertSuccess();
new Administration(client).reload();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.as.arquillian.api.ServerSetup;
import org.jboss.eap.qe.microprofile.health.tools.HealthUrlProvider;
import org.jboss.eap.qe.microprofile.tooling.server.configuration.ConfigurationException;
import org.jboss.shrinkwrap.api.Archive;
Expand All @@ -23,6 +24,7 @@

@RunAsClient
@RunWith(Arquillian.class)
@ServerSetup({ DisableDefaultHealthProceduresSetupTask.class })
public class HealthDeprecatedTest {

@Deployment(testable = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.as.arquillian.api.ServerSetup;
import org.jboss.eap.qe.microprofile.health.tools.HealthUrlProvider;
import org.jboss.eap.qe.microprofile.tooling.server.configuration.ConfigurationException;
import org.jboss.shrinkwrap.api.Archive;
Expand All @@ -22,6 +23,7 @@

@RunAsClient
@RunWith(Arquillian.class)
@ServerSetup({ DisableDefaultHealthProceduresSetupTask.class })
public class HealthNullTest {

@Deployment(testable = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.as.arquillian.api.ServerSetup;
import org.jboss.eap.qe.microprofile.health.tools.HealthUrlProvider;
import org.jboss.eap.qe.microprofile.tooling.server.configuration.ConfigurationException;
import org.jboss.shrinkwrap.api.Archive;
Expand All @@ -24,6 +25,7 @@

@RunAsClient
@RunWith(Arquillian.class)
@ServerSetup({ DisableDefaultHealthProceduresSetupTask.class })
public class HealthTest {

@Deployment(testable = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.as.arquillian.api.ServerSetup;
import org.jboss.eap.qe.microprofile.health.tools.HealthUrlProvider;
import org.jboss.eap.qe.microprofile.tooling.server.configuration.ConfigurationException;
import org.jboss.shrinkwrap.api.Archive;
Expand All @@ -24,6 +25,7 @@

@RunAsClient
@RunWith(Arquillian.class)
@ServerSetup({ DisableDefaultHealthProceduresSetupTask.class })
public class MimeTypeHealthTest {

@Deployment(testable = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.as.arquillian.api.ServerSetup;
import org.jboss.eap.qe.microprofile.health.tools.HealthUrlProvider;
import org.jboss.eap.qe.microprofile.tooling.server.configuration.ConfigurationException;
import org.jboss.shrinkwrap.api.Archive;
Expand All @@ -26,6 +27,7 @@
* Multiple deployment scenario.
*/
@RunWith(Arquillian.class)
@ServerSetup({ DisableDefaultHealthProceduresSetupTask.class })
public class MultiDeploymentHealthTest {

@Deployment(name = "deployment1", order = 1, testable = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.as.arquillian.api.ServerSetup;
import org.jboss.eap.qe.microprofile.health.tools.HealthUrlProvider;
import org.jboss.eap.qe.microprofile.tooling.server.configuration.ConfigurationException;
import org.jboss.shrinkwrap.api.Archive;
Expand All @@ -24,6 +25,7 @@

@RunAsClient
@RunWith(Arquillian.class)
@ServerSetup({ DisableDefaultHealthProceduresSetupTask.class })
public class SimplifiedHealthTest {

@Deployment(testable = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,8 @@ public void delayedConstructorTest()
get(HealthUrlProvider.readyEndpoint(arqProps)).then()
.statusCode(503)
.body("status", is("DOWN"),
"checks.name", containsInAnyOrder(DelayedReadinessHealthCheck.NAME));
"checks.name", containsInAnyOrder(DelayedReadinessHealthCheck.NAME, "deployments-status",
"boot-errors", "server-state"));
} finally {
controller.stop(ManualTests.ARQUILLIAN_CONTAINER);
}
Expand Down Expand Up @@ -300,7 +301,8 @@ public void unexpectedHealthChecksTest()
.statusCode(200)
.body("status", is("UP"),
"checks.name", containsInAnyOrder(
"ready-deployment." + DelayedLivenessHealthCheck.class.getSimpleName() + ".war"));
"ready-deployment." + DelayedLivenessHealthCheck.class.getSimpleName() + ".war",
"deployments-status", "boot-errors", "server-state"));
} finally {
controller.stop(ManualTests.ARQUILLIAN_CONTAINER);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,20 @@ public Boolean call() {
if (response.getStatusCode() == 503) {
if (checks == null) {
addState(DOWN_NO_CONTENT());
} else if (checks.size() == 0) {
} else if ((checks.size() == 4) && contains(checks, "empty-readiness-checks")) {
addState(DOWN_NO_CHECK());
} else if (checks.get(0).get("name").equals(DelayedReadinessHealthCheck.NAME)) {
} else if ((checks.size() == 4) && contains(checks, DelayedReadinessHealthCheck.NAME)) {
istraka marked this conversation as resolved.
Show resolved Hide resolved
addState(ReadinessState.DOWN_WITH_CHECK());
}
} else if (response.getStatusCode() == 200) {
if (checks == null) {
throw new RuntimeException("Readiness probe is UP (200) however missing JSON content");
}
if (checks.size() == 0) {
if ((checks.size() == 4) && contains(checks, "empty-readiness-checks")) {
addState(UP_NO_CHECK());
} else if (checks.get(0).get("name").equals(DelayedReadinessHealthCheck.NAME)) {
} else if ((checks.size() == 4) && contains(checks, DelayedReadinessHealthCheck.NAME)) {
addState(UP_WITH_CHECK());
} else if (checks.get(0).get("name").startsWith(DEFAULT_READINESS_CHECK_NAME_PREFIX)) {
} else if ((checks.size() == 4) && contains(checks, DEFAULT_READINESS_CHECK_NAME_PREFIX)) {
addState(UP_WITH_DEFAULT_CHECK());
}
}
Expand Down Expand Up @@ -92,6 +92,23 @@ private int lastIndexOfStates() {
return states.size() - 1;
}

/**
* @param list collection to find in
* @param key which we are looking for
* @return true if key {@code name} atribute startsWith {@code key}. False otherwise.
*/
private boolean contains(List<Map<String, String>> list, String key) {
if (list == null) {
return false;
}
for (Map<String, String> item : list) {
if (item.get("name").startsWith(key)) {
return true;
}
}
return false;
}

public void stop() {
shouldStop.set(true);
}
Expand Down
Loading