Merge branch 'stable-2.14' into stable-2.15
* stable-2.14:
Allow to disable health check endpoint
AbstractIndexRestApiServlet: Log operation type in lower case
Make debug logging consistent in forwarder and cache servlet
Use Logger's built-in string formatting
Restrict endpoints to change health status to admins
Add unit tests for HealthServlet
Initial implementation of health servlet
Change-Id: Idb83c5beac343490b8cb7ea031b2fb40863c7f25
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
index aba6c05..32e49af 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
@@ -84,6 +84,11 @@
// common parameters to cache, event index and websession sections
static final String SYNCHRONIZE_KEY = "synchronize";
+ // health check section
+ static final String HEALTH_CHECK_SECTION = "healthCheck";
+ static final String ENABLE_KEY = "enable";
+ static final boolean DEFAULT_HEALTH_CHECK_ENABLED = true;
+
// websession section
static final String WEBSESSION_SECTION = "websession";
static final String CLEANUP_INTERVAL_KEY = "cleanupInterval";
@@ -110,6 +115,7 @@
private final Websession websession;
private PeerInfoStatic peerInfoStatic;
private PeerInfoJGroups peerInfoJGroups;
+ private HealthCheck healthCheck;
public enum PeerInfoStrategy {
JGROUPS,
@@ -138,6 +144,7 @@
event = new Event(cfg);
index = new Index(cfg);
websession = new Websession(cfg);
+ healthCheck = new HealthCheck(cfg);
}
public Main main() {
@@ -180,12 +187,16 @@
return websession;
}
+ public HealthCheck healthCheck() {
+ return healthCheck;
+ }
+
private static int getInt(Config cfg, String section, String name, int defaultValue) {
try {
return cfg.getInt(section, name, defaultValue);
} catch (IllegalArgumentException e) {
- log.error(String.format("invalid value for %s; using default value %d", name, defaultValue));
- log.debug("Failed to retrieve integer value: " + e.getMessage(), e);
+ log.error("invalid value for {}; using default value {}", name, defaultValue);
+ log.debug("Failed to retrieve integer value: {}", e.getMessage(), e);
return defaultValue;
}
}
@@ -194,8 +205,8 @@
try {
return cfg.getBoolean(section, name, defaultValue);
} catch (IllegalArgumentException e) {
- log.error(String.format("invalid value for %s; using default value %s", name, defaultValue));
- log.debug("Failed to retrieve boolean value: " + e.getMessage(), e);
+ log.error("invalid value for {}; using default value {}", name, defaultValue);
+ log.debug("Failed to retrieve boolean value: {}", e.getMessage(), e);
return defaultValue;
}
}
@@ -403,4 +414,16 @@
return cleanupInterval;
}
}
+
+ public static class HealthCheck {
+ private final boolean enabled;
+
+ private HealthCheck(Config cfg) {
+ enabled = cfg.getBoolean(HEALTH_CHECK_SECTION, ENABLE_KEY, DEFAULT_HEALTH_CHECK_ENABLED);
+ }
+
+ public boolean enabled() {
+ return enabled;
+ }
+ }
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/HttpModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/HttpModule.java
index 57d1d91..3209b1b 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/HttpModule.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/HttpModule.java
@@ -15,6 +15,7 @@
package com.ericsson.gerrit.plugins.highavailability;
import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.RestForwarderServletModule;
+import com.ericsson.gerrit.plugins.highavailability.health.HealthServletModule;
import com.ericsson.gerrit.plugins.highavailability.websession.file.FileBasedWebsessionModule;
import com.google.gerrit.httpd.plugins.HttpPluginModule;
import com.google.inject.Inject;
@@ -30,6 +31,9 @@
@Override
protected void configureServlets() {
install(new RestForwarderServletModule());
+ if (config.healthCheck().enabled()) {
+ install(new HealthServletModule());
+ }
if (config.websession().synchronize()) {
install(new FileBasedWebsessionModule());
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java
index 5b7cc60..ddd1ac2 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java
@@ -24,6 +24,7 @@
import com.google.gwtorm.server.OrmException;
import java.io.IOException;
import java.util.HashMap;
+import java.util.Locale;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.ServletException;
@@ -79,7 +80,7 @@
rsp.setCharacterEncoding(UTF_8.name());
String path = req.getPathInfo();
T id = parse(path.substring(path.lastIndexOf('/') + 1));
- logger.debug("{} {} {}", operation.name(), type, id);
+ logger.debug("{} {} {}", operation.name().toLowerCase(Locale.US), type, id);
try {
Context.setForwardedEvent(true);
AtomicInteger idLock = getAndIncrementIdLock(id);
@@ -92,7 +93,7 @@
rsp.setStatus(SC_NO_CONTENT);
} catch (IOException e) {
sendError(rsp, SC_CONFLICT, e.getMessage());
- logger.error(String.format("Unable to update %s index", type), e);
+ logger.error("Unable to update {} index", type, e);
} catch (OrmException e) {
String msg = String.format("Error trying to find %s \n", type);
sendError(rsp, SC_NOT_FOUND, msg);
@@ -127,7 +128,7 @@
try {
rsp.sendError(statusCode, message);
} catch (IOException e) {
- logger.error("Failed to send error messsage: " + e.getMessage(), e);
+ logger.error("Failed to send error messsage: {}", e.getMessage(), e);
}
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java
index 253ff4a..86483c9 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java
@@ -61,7 +61,7 @@
Cache<?, ?> cache = cacheMap.get(cacheKey.pluginName, cacheKey.cacheName);
if (cache == null) {
String msg = String.format("cache %s not found", cacheName);
- logger.error("Failed to process eviction request: " + msg);
+ logger.error("Failed to process eviction request: {}", msg);
sendError(rsp, SC_BAD_REQUEST, msg);
} else {
Context.setForwardedEvent(true);
@@ -69,7 +69,7 @@
rsp.setStatus(SC_NO_CONTENT);
}
} catch (IOException e) {
- logger.error("Failed to process eviction request: " + e.getMessage(), e);
+ logger.error("Failed to process eviction request: {}", e.getMessage(), e);
sendError(rsp, SC_BAD_REQUEST, e.getMessage());
} finally {
Context.unsetForwardedEvent();
@@ -100,7 +100,7 @@
try {
rsp.sendError(statusCode, message);
} catch (IOException e) {
- logger.error("Failed to send error messsage: " + e.getMessage(), e);
+ logger.error("Failed to send error messsage: {}", e.getMessage(), e);
}
}
@@ -108,9 +108,10 @@
if (Constants.PROJECT_LIST.equals(cacheName)) {
// One key is holding the list of projects
cache.invalidateAll();
+ logger.debug("Invalidated cache {}", cacheName);
} else {
cache.invalidate(key);
+ logger.debug("Invalidated cache {}[{}]", cacheName, key);
}
- logger.debug("Invalidated " + cacheName);
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/EventRestApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/EventRestApiServlet.java
index 92f3d0d..e25e7eb 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/EventRestApiServlet.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/EventRestApiServlet.java
@@ -95,7 +95,7 @@
try {
rsp.sendError(statusCode, message);
} catch (IOException e) {
- logger.error("Failed to send error messsage: " + e.getMessage(), e);
+ logger.error("Failed to send error messsage: {}", e.getMessage(), e);
}
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java
index c1c46d9..01ea665 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java
@@ -105,7 +105,7 @@
@Override
public boolean evict(final String cacheName, final Object key) {
- return new Request("evict for cache " + cacheName + "[" + key + "]") {
+ return new Request("invalidate cache " + cacheName + "[" + key + "]") {
@Override
HttpResult send() throws IOException {
String json = GsonParser.toJson(cacheName, key);
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServlet.java
new file mode 100644
index 0000000..d01382b
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServlet.java
@@ -0,0 +1,88 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// 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.
+
+package com.ericsson.gerrit.plugins.highavailability.health;
+
+import static com.google.gerrit.server.permissions.GlobalPermission.ADMINISTRATE_SERVER;
+import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
+import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
+import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
+import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
+
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import java.io.IOException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class HealthServlet extends HttpServlet {
+ private static final Logger log = LoggerFactory.getLogger(HealthServlet.class);
+ private static final long serialVersionUID = -1L;
+
+ private final Provider<CurrentUser> currentUserProvider;
+ private final PermissionBackend permissionBackend;
+ private boolean healthy;
+
+ @Inject
+ HealthServlet(Provider<CurrentUser> currentUserProvider, PermissionBackend permissionBackend) {
+ this.currentUserProvider = currentUserProvider;
+ this.permissionBackend = permissionBackend;
+ this.healthy = true;
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse rsp) {
+ if (!permissionBackend.user(currentUserProvider.get()).testOrFalse(ADMINISTRATE_SERVER)) {
+ sendError(rsp, SC_FORBIDDEN);
+ return;
+ }
+ this.healthy = true;
+ rsp.setStatus(SC_NO_CONTENT);
+ }
+
+ @Override
+ protected void doDelete(HttpServletRequest req, HttpServletResponse rsp) {
+ if (!permissionBackend.user(currentUserProvider.get()).testOrFalse(ADMINISTRATE_SERVER)) {
+ sendError(rsp, SC_FORBIDDEN);
+ return;
+ }
+ this.healthy = false;
+ rsp.setStatus(SC_NO_CONTENT);
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse rsp) {
+ if (healthy) {
+ rsp.setStatus(SC_NO_CONTENT);
+ } else {
+ sendError(rsp, SC_SERVICE_UNAVAILABLE);
+ }
+ }
+
+ private void sendError(HttpServletResponse rsp, int statusCode) {
+ try {
+ rsp.sendError(statusCode);
+ } catch (IOException e) {
+ rsp.setStatus(SC_INTERNAL_SERVER_ERROR);
+ log.error("Failed to send error response", e);
+ }
+ }
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServletModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServletModule.java
new file mode 100644
index 0000000..f3318a9
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServletModule.java
@@ -0,0 +1,24 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// 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.
+
+package com.ericsson.gerrit.plugins.highavailability.health;
+
+import com.google.gerrit.httpd.plugins.HttpPluginModule;
+
+public class HealthServletModule extends HttpPluginModule {
+ @Override
+ protected void configureServlets() {
+ serve("/health").with(HealthServlet.class);
+ }
+}
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 42ce673..2289c83 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -30,6 +30,8 @@
[http]
: user = username
: password = password
+[healthcheck]
+: enable = true
main.sharedDirectory
: Path to a directory accessible from both master instances.
@@ -152,3 +154,6 @@
* y, year, years (`1 year` is treated as `365 days`)
If a time unit suffix is not specified, `hours` is assumed.
Defaults to 24 hours.
+
+healthcheck.enable
+: Whether to enable the health check endpoint. Defaults to 'true'.
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
index e9b39c7..42102c7 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
@@ -20,6 +20,7 @@
import static com.ericsson.gerrit.plugins.highavailability.Configuration.CONNECTION_TIMEOUT_KEY;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_CLEANUP_INTERVAL_MS;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_CLUSTER_NAME;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_HEALTH_CHECK_ENABLED;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_MAX_TRIES;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_PEER_INFO_STRATEGY;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_RETRY_INTERVAL;
@@ -27,7 +28,9 @@
import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_SYNCHRONIZE;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_THREAD_POOL_SIZE;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_TIMEOUT_MS;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.ENABLE_KEY;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.EVENT_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.HEALTH_CHECK_SECTION;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.HTTP_SECTION;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.INDEX_SECTION;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGROUPS_SECTION;
@@ -533,4 +536,12 @@
assertThat(matcher.matches(cache)).isFalse();
}
}
+
+ @Test
+ public void testHealthCheckEnabled() throws Exception {
+ when(configMock.getBoolean(HEALTH_CHECK_SECTION, ENABLE_KEY, DEFAULT_HEALTH_CHECK_ENABLED))
+ .thenReturn(false);
+ initializeConfiguration();
+ assertThat(configuration.healthCheck().enabled()).isFalse();
+ }
}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServletTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServletTest.java
new file mode 100644
index 0000000..b8a69cb
--- /dev/null
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServletTest.java
@@ -0,0 +1,145 @@
+// Copyright (C) 2017 Ericsson
+//
+// 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.
+
+package com.ericsson.gerrit.plugins.highavailability.health;
+
+import static com.google.gerrit.server.permissions.GlobalPermission.ADMINISTRATE_SERVER;
+import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
+import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
+import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
+import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackend.WithUser;
+import com.google.inject.Provider;
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class HealthServletTest {
+
+ @Mock private Provider<CurrentUser> currentUserProviderMock;
+ @Mock private CurrentUser currentUserMock;
+ @Mock private PermissionBackend permissionBackendMock;
+ @Mock private WithUser withUserMock;
+
+ private HealthServlet servlet;
+
+ @Before
+ public void setUp() throws Exception {
+ when(currentUserProviderMock.get()).thenReturn(currentUserMock);
+ when(permissionBackendMock.user(currentUserMock)).thenReturn(withUserMock);
+ when(withUserMock.testOrFalse(ADMINISTRATE_SERVER)).thenReturn(true);
+ servlet = new HealthServlet(currentUserProviderMock, permissionBackendMock);
+ }
+
+ @Test
+ public void shouldBeHealthyByDefault() {
+ assertIsHealthy();
+ }
+
+ @Test
+ public void testTransitionToUnhealthy() throws IOException {
+ assertIsHealthy();
+
+ // transition from healthy to unhealthy
+ HttpServletResponse responseMock = mock(HttpServletResponse.class);
+ servlet.doDelete(null, responseMock);
+ verify(responseMock).setStatus(SC_NO_CONTENT);
+ assertIsUnhealthy();
+
+ // setting to unhealthy again should not change anything
+ responseMock = mock(HttpServletResponse.class);
+ servlet.doDelete(null, responseMock);
+ verify(responseMock).setStatus(SC_NO_CONTENT);
+ assertIsUnhealthy();
+ }
+
+ @Test
+ public void testTransitionToUnhealthyByNonAdmins() throws IOException {
+ assertIsHealthy();
+
+ when(withUserMock.testOrFalse(ADMINISTRATE_SERVER)).thenReturn(false);
+ HttpServletResponse responseMock = mock(HttpServletResponse.class);
+ servlet.doDelete(null, responseMock);
+ verify(responseMock).sendError(SC_FORBIDDEN);
+ assertIsHealthy();
+ }
+
+ @Test
+ public void testTransitionToHealty() throws IOException {
+ // first, mark as unhealthy
+ servlet.doDelete(null, mock(HttpServletResponse.class));
+ assertIsUnhealthy();
+
+ // transition from unhealthy to healthy
+ HttpServletResponse responseMock = mock(HttpServletResponse.class);
+ servlet.doPost(null, responseMock);
+ verify(responseMock).setStatus(SC_NO_CONTENT);
+ assertIsHealthy();
+
+ // setting to healthy again should not change anything
+ responseMock = mock(HttpServletResponse.class);
+ servlet.doPost(null, responseMock);
+ verify(responseMock).setStatus(SC_NO_CONTENT);
+ assertIsHealthy();
+ }
+
+ @Test
+ public void testTransitionToHealthyByNonAdmins() throws IOException {
+ // first, mark as unhealthy
+ servlet.doDelete(null, mock(HttpServletResponse.class));
+ assertIsUnhealthy();
+
+ when(withUserMock.testOrFalse(ADMINISTRATE_SERVER)).thenReturn(false);
+ HttpServletResponse responseMock = mock(HttpServletResponse.class);
+ servlet.doPost(null, responseMock);
+ verify(responseMock).sendError(SC_FORBIDDEN);
+ assertIsUnhealthy();
+ }
+
+ @Test
+ public void testErrorWhileSendingUnhealthyResponse() throws IOException {
+ HttpServletResponse responseMock = mock(HttpServletResponse.class);
+ servlet.doDelete(null, responseMock);
+ verify(responseMock).setStatus(SC_NO_CONTENT);
+
+ responseMock = mock(HttpServletResponse.class);
+ doThrow(new IOException("someError")).when(responseMock).sendError(SC_SERVICE_UNAVAILABLE);
+ servlet.doGet(null, responseMock);
+ verify(responseMock).setStatus(SC_INTERNAL_SERVER_ERROR);
+ }
+
+ private void assertIsHealthy() {
+ HttpServletResponse responseMock = mock(HttpServletResponse.class);
+ servlet.doGet(null, responseMock);
+ verify(responseMock).setStatus(SC_NO_CONTENT);
+ }
+
+ private void assertIsUnhealthy() throws IOException {
+ HttpServletResponse responseMock = mock(HttpServletResponse.class);
+ servlet.doGet(null, responseMock);
+ verify(responseMock).sendError(SC_SERVICE_UNAVAILABLE);
+ }
+}