use WireMock for offline tests
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
60d94fc5bb
commit
36102326db
12
pom.xml
12
pom.xml
@ -129,18 +129,18 @@
|
|||||||
<version>3.8.0</version>
|
<version>3.8.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.mockito</groupId>
|
|
||||||
<artifactId>mockito-inline</artifactId>
|
|
||||||
<version>3.8.0</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.stefanbirkner</groupId>
|
<groupId>com.github.stefanbirkner</groupId>
|
||||||
<artifactId>system-lambda</artifactId>
|
<artifactId>system-lambda</artifactId>
|
||||||
<version>1.2.0</version>
|
<version>1.2.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.tomakehurst</groupId>
|
||||||
|
<artifactId>wiremock</artifactId>
|
||||||
|
<version>2.27.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-io</groupId>
|
<groupId>commons-io</groupId>
|
||||||
<artifactId>commons-io</artifactId>
|
<artifactId>commons-io</artifactId>
|
||||||
|
@ -16,37 +16,32 @@
|
|||||||
|
|
||||||
package de.stklcode.jvault.connector;
|
package de.stklcode.jvault.connector;
|
||||||
|
|
||||||
import de.stklcode.jvault.connector.exception.InvalidRequestException;
|
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||||
import de.stklcode.jvault.connector.exception.PermissionDeniedException;
|
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
|
||||||
import de.stklcode.jvault.connector.exception.VaultConnectorException;
|
import de.stklcode.jvault.connector.exception.*;
|
||||||
import org.apache.http.ProtocolVersion;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.apache.http.entity.ContentType;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.apache.http.entity.StringEntity;
|
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
|
||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
|
||||||
import org.apache.http.message.BasicStatusLine;
|
|
||||||
import org.junit.jupiter.api.*;
|
|
||||||
import org.junit.jupiter.api.function.Executable;
|
import org.junit.jupiter.api.function.Executable;
|
||||||
import org.mockito.MockedStatic;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.net.ServerSocket;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||||
|
import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
|
||||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
import static org.hamcrest.CoreMatchers.nullValue;
|
import static org.hamcrest.CoreMatchers.nullValue;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.core.Is.is;
|
import static org.hamcrest.core.Is.is;
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JUnit test for HTTP Vault connector.
|
* JUnit test for HTTP Vault connector.
|
||||||
@ -58,40 +53,33 @@ import static org.mockito.Mockito.*;
|
|||||||
class HTTPVaultConnectorOfflineTest {
|
class HTTPVaultConnectorOfflineTest {
|
||||||
private static final String INVALID_URL = "foo:/\\1nv4l1d_UrL";
|
private static final String INVALID_URL = "foo:/\\1nv4l1d_UrL";
|
||||||
|
|
||||||
private static MockedStatic<HttpClientBuilder> hcbMock;
|
private static WireMockServer wireMock;
|
||||||
private static CloseableHttpClient httpMock;
|
|
||||||
private final CloseableHttpResponse responseMock = mock(CloseableHttpResponse.class);
|
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
static void prepare() {
|
static void prepare() {
|
||||||
// Mock the static HTTPClient creation.
|
// Initialize HTTP mock.
|
||||||
hcbMock = mockStatic(HttpClientBuilder.class);
|
wireMock = new WireMockServer(WireMockConfiguration.options().dynamicPort());
|
||||||
hcbMock.when(HttpClientBuilder::create).thenReturn(new MockedHttpClientBuilder());
|
wireMock.start();
|
||||||
|
WireMock.configureFor("localhost", wireMock.port());
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
static void tearDown() {
|
static void tearDown() {
|
||||||
hcbMock.close();
|
wireMock.stop();
|
||||||
}
|
wireMock = null;
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void init() {
|
|
||||||
// Re-initialize HTTP mock to ensure fresh (empty) results.
|
|
||||||
httpMock = mock(CloseableHttpClient.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test exceptions thrown during request.
|
* Test exceptions thrown during request.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void requestExceptionTest() throws IOException {
|
void requestExceptionTest() throws IOException {
|
||||||
HTTPVaultConnector connector = new HTTPVaultConnector("http://127.0.0.1", null, 0, 250);
|
HTTPVaultConnector connector = new HTTPVaultConnector(wireMock.url("/"), null, 0, 250);
|
||||||
|
|
||||||
// Test invalid response code.
|
// Test invalid response code.
|
||||||
final int responseCode = 400;
|
final int responseCode = 400;
|
||||||
mockResponse(responseCode, "", ContentType.APPLICATION_JSON);
|
mockHttpResponse(responseCode, "", "application/json");
|
||||||
InvalidResponseException e = assertThrows(
|
VaultConnectorException e = assertThrows(
|
||||||
InvalidResponseException.class,
|
InvalidResponseException.class,
|
||||||
connector::getHealth,
|
connector::getHealth,
|
||||||
"Querying health status succeeded on invalid instance"
|
"Querying health status succeeded on invalid instance"
|
||||||
@ -101,7 +89,7 @@ class HTTPVaultConnectorOfflineTest {
|
|||||||
assertThat("Response message where none was expected", ((InvalidResponseException) e).getResponse(), is(nullValue()));
|
assertThat("Response message where none was expected", ((InvalidResponseException) e).getResponse(), is(nullValue()));
|
||||||
|
|
||||||
// Simulate permission denied response.
|
// Simulate permission denied response.
|
||||||
mockResponse(responseCode, "{\"errors\":[\"permission denied\"]}", ContentType.APPLICATION_JSON);
|
mockHttpResponse(responseCode, "{\"errors\":[\"permission denied\"]}", "application/json");
|
||||||
assertThrows(
|
assertThrows(
|
||||||
PermissionDeniedException.class,
|
PermissionDeniedException.class,
|
||||||
connector::getHealth,
|
connector::getHealth,
|
||||||
@ -109,25 +97,27 @@ class HTTPVaultConnectorOfflineTest {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Test exception thrown during request.
|
// Test exception thrown during request.
|
||||||
when(httpMock.execute(any())).thenThrow(new IOException("Test Exception"));
|
try (ServerSocket s = new ServerSocket(0)) {
|
||||||
|
connector = new HTTPVaultConnector("http://localst:" + s.getLocalPort() + "/", null, 0, 250);
|
||||||
|
}
|
||||||
e = assertThrows(
|
e = assertThrows(
|
||||||
InvalidResponseException.class,
|
ConnectionException.class,
|
||||||
connector::getHealth,
|
connector::getHealth,
|
||||||
"Querying health status succeeded on invalid instance"
|
"Querying health status succeeded on invalid instance"
|
||||||
);
|
);
|
||||||
assertThat("Unexpected exception message", e.getMessage(), is("Unable to read response"));
|
assertThat("Unexpected exception message", e.getMessage(), is("Unable to connect to Vault server"));
|
||||||
assertThat("Unexpected cause", e.getCause(), instanceOf(IOException.class));
|
assertThat("Unexpected cause", e.getCause(), instanceOf(IOException.class));
|
||||||
|
|
||||||
// Now simulate a failing request that succeeds on second try.
|
// Now simulate a failing request that succeeds on second try.
|
||||||
connector = new HTTPVaultConnector("https://127.0.0.1", null, 1, 250);
|
connector = new HTTPVaultConnector(wireMock.url("/"), null, 1, 250);
|
||||||
doReturn(responseMock).doReturn(responseMock).when(httpMock).execute(any());
|
|
||||||
doReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, ""))
|
|
||||||
.doReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, ""))
|
|
||||||
.doReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, ""))
|
|
||||||
.doReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, ""))
|
|
||||||
.when(responseMock).getStatusLine();
|
|
||||||
when(responseMock.getEntity()).thenReturn(new StringEntity("{}", ContentType.APPLICATION_JSON));
|
|
||||||
|
|
||||||
|
WireMock.stubFor(
|
||||||
|
WireMock.any(anyUrl())
|
||||||
|
.willReturn(aResponse().withStatus(500))
|
||||||
|
.willReturn(aResponse().withStatus(500))
|
||||||
|
.willReturn(aResponse().withStatus(500))
|
||||||
|
.willReturn(aResponse().withStatus(200).withBody("{}").withHeader("Content-Type", "application/json"))
|
||||||
|
);
|
||||||
assertDoesNotThrow(connector::getHealth, "Request failed unexpectedly");
|
assertDoesNotThrow(connector::getHealth, "Request failed unexpectedly");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +177,7 @@ class HTTPVaultConnectorOfflineTest {
|
|||||||
* This test is designed to test exceptions caught and thrown by seal-methods if Vault is not reachable.
|
* This test is designed to test exceptions caught and thrown by seal-methods if Vault is not reachable.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void sealExceptionTest() {
|
void sealExceptionTest() throws IOException {
|
||||||
HTTPVaultConnector connector = new HTTPVaultConnector(INVALID_URL);
|
HTTPVaultConnector connector = new HTTPVaultConnector(INVALID_URL);
|
||||||
VaultConnectorException e = assertThrows(
|
VaultConnectorException e = assertThrows(
|
||||||
InvalidRequestException.class,
|
InvalidRequestException.class,
|
||||||
@ -196,21 +186,23 @@ class HTTPVaultConnectorOfflineTest {
|
|||||||
);
|
);
|
||||||
assertThat("Unexpected exception message", e.getMessage(), is("Invalid URI format"));
|
assertThat("Unexpected exception message", e.getMessage(), is("Invalid URI format"));
|
||||||
|
|
||||||
// Simulate NULL response (mock not supplied with data).
|
// Simulate no connection.
|
||||||
connector = new HTTPVaultConnector("https://127.0.0.1", null, 0, 250);
|
try (ServerSocket s = new ServerSocket(0)) {
|
||||||
|
connector = new HTTPVaultConnector("http://localst:" + s.getLocalPort() + "/", null, 0, 250);
|
||||||
|
}
|
||||||
e = assertThrows(
|
e = assertThrows(
|
||||||
InvalidResponseException.class,
|
ConnectionException.class,
|
||||||
connector::sealStatus,
|
connector::sealStatus,
|
||||||
"Querying seal status succeeded on invalid instance"
|
"Querying seal status succeeded on invalid instance"
|
||||||
);
|
);
|
||||||
assertThat("Unexpected exception message", e.getMessage(), is("Response unavailable"));
|
assertThat("Unexpected exception message", e.getMessage(), is("Unable to connect to Vault server"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This test is designed to test exceptions caught and thrown by seal-methods if Vault is not reachable.
|
* This test is designed to test exceptions caught and thrown by seal-methods if Vault is not reachable.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void healthExceptionTest() {
|
void healthExceptionTest() throws IOException {
|
||||||
HTTPVaultConnector connector = new HTTPVaultConnector(INVALID_URL);
|
HTTPVaultConnector connector = new HTTPVaultConnector(INVALID_URL);
|
||||||
VaultConnectorException e = assertThrows(
|
VaultConnectorException e = assertThrows(
|
||||||
InvalidRequestException.class,
|
InvalidRequestException.class,
|
||||||
@ -219,14 +211,16 @@ class HTTPVaultConnectorOfflineTest {
|
|||||||
);
|
);
|
||||||
assertThat("Unexpected exception message", e.getMessage(), is("Invalid URI format"));
|
assertThat("Unexpected exception message", e.getMessage(), is("Invalid URI format"));
|
||||||
|
|
||||||
// Simulate NULL response (mock not supplied with data).
|
// Simulate no connection.
|
||||||
connector = new HTTPVaultConnector("https://127.0.0.1", null, 0, 250);
|
try (ServerSocket s = new ServerSocket(0)) {
|
||||||
|
connector = new HTTPVaultConnector("http://localhost:" + s.getLocalPort() + "/", null, 0, 250);
|
||||||
|
}
|
||||||
e = assertThrows(
|
e = assertThrows(
|
||||||
InvalidResponseException.class,
|
ConnectionException.class,
|
||||||
connector::getHealth,
|
connector::getHealth,
|
||||||
"Querying health status succeeded on invalid instance"
|
"Querying health status succeeded on invalid instance"
|
||||||
);
|
);
|
||||||
assertThat("Unexpected exception message", e.getMessage(), is("Response unavailable"));
|
assertThat("Unexpected exception message", e.getMessage(), is("Unable to connect to Vault server"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -234,11 +228,11 @@ class HTTPVaultConnectorOfflineTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void parseExceptionTest() throws IOException {
|
void parseExceptionTest() throws IOException {
|
||||||
HTTPVaultConnector connector = new HTTPVaultConnector("https://127.0.0.1", null, 0, 250);
|
HTTPVaultConnector connector = new HTTPVaultConnector(wireMock.url("/"), null, 0, 250);
|
||||||
// Mock authorization.
|
// Mock authorization.
|
||||||
setPrivate(connector, "authorized", true);
|
setPrivate(connector, "authorized", true);
|
||||||
// Mock response.
|
// Mock response.
|
||||||
mockResponse(200, "invalid", ContentType.APPLICATION_JSON);
|
mockHttpResponse(200, "invalid", "application/json");
|
||||||
|
|
||||||
// Now test the methods.
|
// Now test the methods.
|
||||||
assertParseError(connector::sealStatus, "sealStatus() succeeded on invalid instance");
|
assertParseError(connector::sealStatus, "sealStatus() succeeded on invalid instance");
|
||||||
@ -267,12 +261,12 @@ class HTTPVaultConnectorOfflineTest {
|
|||||||
* Test requests that expect an empty response with code 204, but receive a 200 body.
|
* Test requests that expect an empty response with code 204, but receive a 200 body.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void nonEmpty204ResponseTest() throws IOException {
|
void nonEmpty204ResponseTest() {
|
||||||
HTTPVaultConnector connector = new HTTPVaultConnector("https://127.0.0.1", null, 0, 250);
|
HTTPVaultConnector connector = new HTTPVaultConnector(wireMock.url("/"), null, 0, 250);
|
||||||
// Mock authorization.
|
// Mock authorization.
|
||||||
setPrivate(connector, "authorized", true);
|
setPrivate(connector, "authorized", true);
|
||||||
// Mock response.
|
// Mock response.
|
||||||
mockResponse(200, "{}", ContentType.APPLICATION_JSON);
|
mockHttpResponse(200, "{}", "application/json");
|
||||||
|
|
||||||
// Now test the methods expecting a 204.
|
// Now test the methods expecting a 204.
|
||||||
assertThrows(
|
assertThrows(
|
||||||
@ -361,20 +355,11 @@ class HTTPVaultConnectorOfflineTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mockResponse(int status, String body, ContentType type) throws IOException {
|
private void mockHttpResponse(int status, String body, String contentType) {
|
||||||
when(httpMock.execute(any())).thenReturn(responseMock);
|
WireMock.stubFor(
|
||||||
when(responseMock.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), status, ""));
|
WireMock.any(anyUrl()).willReturn(
|
||||||
when(responseMock.getEntity()).thenReturn(new StringEntity(body, type));
|
aResponse().withStatus(status).withBody(body).withHeader("Content-Type", contentType)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Mocked {@link HttpClientBuilder} that always returns the mocked client.
|
|
||||||
*/
|
|
||||||
private static class MockedHttpClientBuilder extends HttpClientBuilder {
|
|
||||||
@Override
|
|
||||||
public CloseableHttpClient build() {
|
|
||||||
return httpMock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user