diff --git a/pom.xml b/pom.xml
index f426226..e257e73 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,6 +18,7 @@
17
${java.version}
${java.version}
+ ${java.version}
${git.commit.author.time}
diff --git a/src/main/java/org/flowable/mockwebserver/MockHttpStatus.java b/src/main/java/org/flowable/mockwebserver/MockHttpStatus.java
index 41aea81..3c5d348 100644
--- a/src/main/java/org/flowable/mockwebserver/MockHttpStatus.java
+++ b/src/main/java/org/flowable/mockwebserver/MockHttpStatus.java
@@ -14,6 +14,7 @@
/**
* An enum of some known HTTP status codes.
+ * This is inspired by the Spring Framework HttpStatus enum.
*
* @author Filip Hrisafov
*/
@@ -21,44 +22,168 @@ public enum MockHttpStatus implements MockHttpStatusCode {
// 2xx Success
+ /**
+ * {@code 200 OK}.
+ * @see HTTP/1.1: Semantics and Content, section 6.3.1
+ */
OK(200, "OK"),
+ /**
+ * {@code 201 Created}.
+ * @see HTTP/1.1: Semantics and Content, section 6.3.2
+ */
CREATED(201, "Created"),
+ /**
+ * {@code 202 Accepted}.
+ * @see HTTP/1.1: Semantics and Content, section 6.3.3
+ */
ACCEPTED(202, "Accepted"),
+ /**
+ * {@code 204 No Content}.
+ * @see HTTP/1.1: Semantics and Content, section 6.3.5
+ */
NO_CONTENT(204, "No Content"),
// 3xx Redirection
+ /**
+ * {@code 300 Multiple Choices}.
+ * @see HTTP/1.1: Semantics and Content, section 6.4.1
+ */
MULTIPLE_CHOICES(300, "Multiple Choices"),
+ /**
+ * {@code 301 Moved Permanently}.
+ * @see HTTP/1.1: Semantics and Content, section 6.4.2
+ */
MOVED_PERMANENTLY(301, "Moved Permanently"),
+ /**
+ * {@code 302 Found}.
+ * @see HTTP/1.1: Semantics and Content, section 6.4.3
+ */
FOUND(302, "Found"),
+ /**
+ * {@code 303 See Other}.
+ * @see HTTP/1.1: Semantics and Content, section 6.4.4
+ */
SEE_OTHER(303, "See Other"),
+ /**
+ * {@code 304 Not Modified}.
+ * @see HTTP/1.1: Conditional Requests, section 4.1
+ */
NOT_MODIFIED(304, "Not Modified"),
+ /**
+ * {@code 307 Temporary Redirect}.
+ * @see HTTP/1.1: Semantics and Content, section 6.4.7
+ */
TEMPORARY_REDIRECT(307, "Temporary Redirect"),
+ /**
+ * {@code 308 Permanent Redirect}.
+ * @see RFC 7238
+ */
PERMANENT_REDIRECT(308, "Permanent Redirect"),
// 4xx Client Error
+ /**
+ * {@code 400 Bad Request}.
+ * @see HTTP/1.1: Semantics and Content, section 6.5.1
+ */
BAD_REQUEST(400, "Bad Request"),
+ /**
+ * {@code 401 Unauthorized}.
+ * @see HTTP/1.1: Authentication, section 3.1
+ */
UNAUTHORIZED(401, "Unauthorized"),
+ /**
+ * {@code 402 Payment Required}.
+ * @see HTTP/1.1: Semantics and Content, section 6.5.2
+ */
PAYMENT_REQUIRED(402, "Payment Required"),
+ /**
+ * {@code 403 Forbidden}.
+ * @see HTTP/1.1: Semantics and Content, section 6.5.3
+ */
FORBIDDEN(403, "Forbidden"),
+ /**
+ * {@code 404 Not Found}.
+ * @see HTTP/1.1: Semantics and Content, section 6.5.4
+ */
NOT_FOUND(404, "Not Found"),
+ /**
+ * {@code 405 Method Not Allowed}.
+ * @see HTTP/1.1: Semantics and Content, section 6.5.5
+ */
METHOD_NOT_ALLOWED(405, "Method Not Allowed"),
+ /**
+ * {@code 406 Not Acceptable}.
+ * @see HTTP/1.1: Semantics and Content, section 6.5.6
+ */
NOT_ACCEPTABLE(406, "Not Acceptable"),
+ /**
+ * {@code 409 Conflict}.
+ * @see HTTP/1.1: Semantics and Content, section 6.5.8
+ */
CONFLICT(409, "Conflict"),
+ /**
+ * {@code 411 Length Required}.
+ * @see
+ * HTTP/1.1: Semantics and Content, section 6.5.10
+ */
LENGTH_REQUIRED(411, "Length Required"),
+ /**
+ * {@code 413 Payload Too Large}.
+ * @see
+ * HTTP/1.1: Semantics and Content, section 6.5.11
+ */
PAYLOAD_TOO_LARGE(413, "Payload Too Large"),
+ /**
+ * {@code 414 URI Too Long}.
+ * @see
+ * HTTP/1.1: Semantics and Content, section 6.5.12
+ */
URI_TOO_LONG(414, "URI Too Long"),
+ /**
+ * {@code 415 Unsupported Media Type}.
+ * @see
+ * HTTP/1.1: Semantics and Content, section 6.5.13
+ */
UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"),
+ /**
+ * {@code 418 I'm a teapot}.
+ * @see HTCPCP/1.0
+ */
I_AM_A_TEAPOT(418, "I'm a teapot"),
+ /**
+ * {@code 429 Too Many Requests}.
+ * @see Additional HTTP Status Codes
+ */
TOO_MANY_REQUESTS(429, "Too Many Requests"),
// 5xx Server Error
+ /**
+ * {@code 500 Internal Server Error}.
+ * @see HTTP/1.1: Semantics and Content, section 6.6.1
+ */
INTERNAL_SERVER_ERROR(500, "Internal Server Error"),
+ /**
+ * {@code 501 Not Implemented}.
+ * @see HTTP/1.1: Semantics and Content, section 6.6.2
+ */
NOT_IMPLEMENTED(501, "Not Implemented"),
+ /**
+ * {@code 502 Bad Gateway}.
+ * @see HTTP/1.1: Semantics and Content, section 6.6.3
+ */
BAD_GATEWAY(502, "Bad Gateway"),
+ /**
+ * {@code 503 Service Unavailable}.
+ * @see HTTP/1.1: Semantics and Content, section 6.6.4
+ */
SERVICE_UNAVAILABLE(503, "Service Unavailable"),
+ /**
+ * {@code 504 Gateway Timeout}.
+ * @see HTTP/1.1: Semantics and Content, section 6.6.5
+ */
GATEWAY_TIMEOUT(504, "Gateway Timeout"),
;
diff --git a/src/main/java/org/flowable/mockwebserver/MockHttpStatusCode.java b/src/main/java/org/flowable/mockwebserver/MockHttpStatusCode.java
index 1d8fbc6..ee8468b 100644
--- a/src/main/java/org/flowable/mockwebserver/MockHttpStatusCode.java
+++ b/src/main/java/org/flowable/mockwebserver/MockHttpStatusCode.java
@@ -14,6 +14,7 @@
/**
* Represents an HTTP status code.
+ * This is inspired by the Spring Framework HttpStatusCode interface.
*
* @author Filip Hrisafov
* @see MockHttpStatus for known status codes
@@ -22,11 +23,15 @@
public sealed interface MockHttpStatusCode permits MockHttpStatus, CustomMockHttpStatus {
/**
+ * The HTTP status code.
+ *
* @return The HTTP status code
*/
int code();
/**
+ * The reason for the HTTP status code.
+ *
* @return The reason for the HTTP status code
*/
String reason();
@@ -73,6 +78,13 @@ static MockHttpStatusCode from(int code) {
};
}
+ /**
+ * Create a custom {@link MockHttpStatusCode} with the given code and reason
+ *
+ * @param code the code to create the status for
+ * @param reason the custom reason for the code
+ * @return the custom status
+ */
static MockHttpStatusCode from(int code, String reason) {
return new CustomMockHttpStatus(code, reason);
}
diff --git a/src/main/java/org/flowable/mockwebserver/MockResponse.java b/src/main/java/org/flowable/mockwebserver/MockResponse.java
index 12ae001..14586dd 100644
--- a/src/main/java/org/flowable/mockwebserver/MockResponse.java
+++ b/src/main/java/org/flowable/mockwebserver/MockResponse.java
@@ -17,20 +17,24 @@
import org.microhttp.Response;
/**
+ * The response that will be returned by the {@link MockWebServer} when a request is made.
+ *
* @author Filip Hrisafov
*/
-public class MockResponse {
+public final class MockResponse {
- protected final Response response;
- protected final Duration delay;
+ final Response response;
+ final Duration delay;
- protected MockResponse(Response response, Duration delay) {
+ MockResponse(Response response, Duration delay) {
this.response = response;
this.delay = delay;
}
/**
- * Create a new builder for a {@link MockResponse} with a default status of {@link MockHttpStatus#OK}
+ * Create a new builder for a {@link MockResponse} with a default status of {@link MockHttpStatus#OK}.
+ *
+ * @return The builder for fluent API
*/
public static MockResponseBuilder newBuilder() {
return MockResponseBuilder.newBuilder();
diff --git a/src/main/java/org/flowable/mockwebserver/MockResponseBuilder.java b/src/main/java/org/flowable/mockwebserver/MockResponseBuilder.java
index f6b63c4..1f55a92 100644
--- a/src/main/java/org/flowable/mockwebserver/MockResponseBuilder.java
+++ b/src/main/java/org/flowable/mockwebserver/MockResponseBuilder.java
@@ -33,63 +33,73 @@
*
* @author Filip Hrisafov
*/
-public class MockResponseBuilder {
+public final class MockResponseBuilder {
- protected static final byte[] EMPTY_BYTE = new byte[0];
+ private static final byte[] EMPTY_BYTE = new byte[0];
- protected MockHttpStatusCode status = MockHttpStatus.OK;
- protected final Map> headers = new LinkedHashMap<>();
- protected byte[] body = EMPTY_BYTE;
- protected Duration delay;
+ private MockHttpStatusCode status = MockHttpStatus.OK;
+ private final Map> headers = new LinkedHashMap<>();
+ private byte[] body = EMPTY_BYTE;
+ private Duration delay;
- protected MockResponseBuilder() {
+ private MockResponseBuilder() {
header("Content-Length", "0");
}
/**
- * Create a new builder for a {@link MockResponse} with a default status of {@link MockHttpStatus#OK}
+ * Create a new builder for a {@link MockResponse} with a default status of {@link MockHttpStatus#OK}.
+ *
+ * @return The builder for fluent API
*/
public static MockResponseBuilder newBuilder() {
return new MockResponseBuilder();
}
/**
- * Set the status of the response to {@link MockHttpStatus#OK}
+ * Set the status of the response to {@link MockHttpStatus#OK}.
+ *
+ * @return The builder for fluent API
*/
public MockResponseBuilder ok() {
return status(MockHttpStatus.OK);
}
/**
- * Set the status of the response to {@link MockHttpStatus#NOT_FOUND}
+ * Set the status of the response to {@link MockHttpStatus#NOT_FOUND}.
+ *
+ * @return The builder for fluent API
*/
public MockResponseBuilder notFound() {
return status(MockHttpStatus.NOT_FOUND);
}
/**
- * Set the status of the response to the given code
- */
- public MockResponseBuilder responseCode(int code) {
- return status(MockHttpStatusCode.from(code));
- }
-
- /**
- * Set the status of the response to the given code
+ * Set the status of the response to the given code.
+ *
+ * @param code the status code of the response
+ * @return The builder for fluent API
*/
public MockResponseBuilder statusCode(int code) {
return status(MockHttpStatusCode.from(code));
}
/**
- * Set the status of the response to the given code and reason
+ * Set the status of the response to the given code and reason.
+ *
+ * @param code the status code of the response
+ * @param reason the reason of the response
+ * @return The builder for fluent API
*/
public MockResponseBuilder status(int code, String reason) {
return status(MockHttpStatusCode.from(code, reason));
}
/**
- * Set the status of the response
+ * Set the status of the response.
+ *
+ * @param status the status of the response
+ *
+ * @return The builder for fluent API
*/
public MockResponseBuilder status(MockHttpStatusCode status) {
if (status == null) {
@@ -105,6 +115,7 @@ public MockResponseBuilder status(MockHttpStatusCode status) {
*
* @param name the name of the header
* @param value the value of the header
+ * @return The builder for fluent API
*/
public MockResponseBuilder header(String name, String value) {
headers.remove(name);
@@ -112,10 +123,11 @@ public MockResponseBuilder header(String name, String value) {
}
/**
- * Add a header to the response
+ * Add a header to the response.
*
* @param name the name of the header
* @param value the value of the header
+ * @return The builder for fluent API
*/
public MockResponseBuilder addHeader(String name, String value) {
this.headers.computeIfAbsent(name, k -> new ArrayList<>())
@@ -128,6 +140,7 @@ public MockResponseBuilder addHeader(String name, String value) {
* This method will read all the bytes from the body.
*
* @param body the input stream to read the bytes from
+ * @return The builder for fluent API
*/
public MockResponseBuilder body(InputStream body) {
try {
@@ -142,6 +155,7 @@ public MockResponseBuilder body(InputStream body) {
* This method will read all the bytes from the body.
*
* @param body the input stream to read the bytes from
+ * @return The builder for fluent API
*/
public MockResponseBuilder body(byte[] body) {
this.body = Arrays.copyOf(body, body.length);
@@ -155,6 +169,7 @@ public MockResponseBuilder body(byte[] body) {
* The charset used is {@link StandardCharsets#UTF_8}.
*
* @param body the body of the response
+ * @return The builder for fluent API
*/
public MockResponseBuilder jsonBody(String body) {
return jsonBody(body, StandardCharsets.UTF_8);
@@ -166,6 +181,7 @@ public MockResponseBuilder jsonBody(String body) {
*
* @param body the body of the response
* @param charset the charset of the body
+ * @return The builder for fluent API
*/
public MockResponseBuilder jsonBody(String body, Charset charset) {
body(body, charset);
@@ -177,6 +193,7 @@ public MockResponseBuilder jsonBody(String body, Charset charset) {
* The charset used is {@link StandardCharsets#UTF_8}.
*
* @param body the body of the response
+ * @return The builder for fluent API
*/
public MockResponseBuilder body(String body) {
return body(body, StandardCharsets.UTF_8);
@@ -187,6 +204,7 @@ public MockResponseBuilder body(String body) {
*
* @param body the body of the response
* @param charset the charset of the body
+ * @return The builder for fluent API
*/
public MockResponseBuilder body(String body, Charset charset) {
this.body = body.getBytes(charset);
@@ -200,6 +218,7 @@ public MockResponseBuilder body(String body, Charset charset) {
*
* @param timeout the timeout of the delay
* @param timeUnit the time unit of the timeout
+ * @return The builder for fluent API
*/
public MockResponseBuilder bodyDelay(long timeout, TimeUnit timeUnit) {
if (timeout <= 0) {
@@ -213,6 +232,7 @@ public MockResponseBuilder bodyDelay(long timeout, TimeUnit timeUnit) {
* The delay must be positive.
*
* @param delay the delay of the response body
+ * @return The builder for fluent API
*/
public MockResponseBuilder bodyDelay(Duration delay) {
if (delay.isNegative() || delay.isZero()) {
@@ -223,7 +243,9 @@ public MockResponseBuilder bodyDelay(Duration delay) {
}
/**
- * Build the {@link MockResponse} instance
+ * Build the {@link MockResponse} instance.
+ *
+ * @return the {@link MockResponse} instance
*/
public MockResponse build() {
List headers = new ArrayList<>(this.headers.size());
diff --git a/src/main/java/org/flowable/mockwebserver/MockWebServer.java b/src/main/java/org/flowable/mockwebserver/MockWebServer.java
index 92eafce..0f1fbb2 100644
--- a/src/main/java/org/flowable/mockwebserver/MockWebServer.java
+++ b/src/main/java/org/flowable/mockwebserver/MockWebServer.java
@@ -34,11 +34,11 @@
*
* @author Filip Hrisafov
*/
-public class MockWebServer {
+public final class MockWebServer {
- protected final TestHandler handler;
- protected EventLoop eventLoop;
- protected Options options;
+ private final TestHandler handler;
+ private EventLoop eventLoop;
+ private Options options;
/**
* Create a new mock webserver with a queue based response provider.
@@ -103,16 +103,22 @@ public void shutdown() {
}
/**
- * Returns a URL for connecting to this server under the {@code /} path.
+ * The URL for connecting to this server.
+ * This will return something like {@code http://:/}.
+ *
+ * @return a URL for connecting to this server under the {@code /} path.
*/
public String url() {
return url("/");
}
/**
- * Returns a URL for connecting to this server.
+ * Return a URL for connecting to this server using the given path.
+ * This will return something like {@code http://:}.
+ * Note if the path does not start with {@code /} it will be added.
*
- * @param path the request path, such as "/".
+ * @param path the request path, such as "/v1".
+ * @return a URL for connecting to this server using the given path.
*/
public String url(String path) {
if (eventLoop == null) {
@@ -120,7 +126,7 @@ public String url(String path) {
}
try {
- return "http://" + options.host() + ":" + eventLoop.getPort() + path;
+ return "http://" + options.host() + ":" + eventLoop.getPort() + (path.startsWith("/") ? path : "/" + path);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
@@ -228,10 +234,10 @@ public int getPort() {
}
}
- protected static class QueueResponseProvider implements Function {
+ private static class QueueResponseProvider implements Function {
- protected final BlockingQueue responseQueue = new LinkedBlockingQueue<>();
- protected MockResponse defaultResponse;
+ private final BlockingQueue responseQueue = new LinkedBlockingQueue<>();
+ private MockResponse defaultResponse;
@Override
public MockResponse apply(RecordedRequest recordedRequest) {
@@ -243,13 +249,13 @@ public MockResponse apply(RecordedRequest recordedRequest) {
}
}
- protected static class TestHandler implements Handler {
+ private static class TestHandler implements Handler {
- protected final Function responseProvider;
- protected final BlockingQueue requestQueue = new LinkedBlockingQueue<>();
- protected final AtomicLong requestCount = new AtomicLong(0);
+ private final Function responseProvider;
+ private final BlockingQueue requestQueue = new LinkedBlockingQueue<>();
+ private final AtomicLong requestCount = new AtomicLong(0);
- protected TestHandler(Function responseProvider) {
+ private TestHandler(Function responseProvider) {
this.responseProvider = responseProvider;
}
@@ -264,7 +270,7 @@ public void handle(Request request, Consumer callback) {
}
}
- protected void handle(MockResponse response, Consumer callback) {
+ private void handle(MockResponse response, Consumer callback) {
Duration delay = response.delay;
if (delay != null) {
long sleep = delay.toMillis();
@@ -282,7 +288,7 @@ protected void handle(MockResponse response, Consumer callback) {
}
- protected long requestCount() {
+ private long requestCount() {
return requestCount.get();
}
}
diff --git a/src/main/java/org/flowable/mockwebserver/RecordedRequest.java b/src/main/java/org/flowable/mockwebserver/RecordedRequest.java
index f9f88ff..4a1edb5 100644
--- a/src/main/java/org/flowable/mockwebserver/RecordedRequest.java
+++ b/src/main/java/org/flowable/mockwebserver/RecordedRequest.java
@@ -29,11 +29,11 @@
*
* @author Filip Hrisafov
*/
-public class RecordedRequest {
+public final class RecordedRequest {
- protected final Request request;
+ private final Request request;
- public RecordedRequest(Request request) {
+ RecordedRequest(Request request) {
this.request = request;
}
@@ -59,6 +59,8 @@ public RequestUrl requestUrl() {
}
/**
+ * The method of the request.
+ *
* @return the method of the request
*/
public String method() {
@@ -116,15 +118,20 @@ public Body body() {
return new Body(request.body());
}
- public static class Body {
+ /**
+ * This represents the body of the request.
+ */
+ public static final class Body {
- protected final byte[] bytes;
+ private final byte[] bytes;
- protected Body(byte[] bytes) {
+ private Body(byte[] bytes) {
this.bytes = bytes;
}
/**
+ * The body of the request as a string using the UTF-8 charset.
+ *
* @return the body of the request as a string using the UTF-8 charset.
*/
public String asString() {
@@ -132,6 +139,9 @@ public String asString() {
}
/**
+ * The body of the request as a string using the given charset.
+ *
+ * @param charset the charset to use to parse the body
* @return the body of the request as a string using give charset
*/
public String asString(Charset charset) {
@@ -139,6 +149,8 @@ public String asString(Charset charset) {
}
/**
+ * The body of the request as a byte array.
+ *
* @return the body of the request as a byte array
*/
public byte[] asByteArray() {
@@ -146,8 +158,20 @@ public byte[] asByteArray() {
}
}
+ /**
+ * This represents the parsed request URL.
+ *
+ * @param path the path of the request (without the query parameters)
+ * @param queryParameters the query parameters of the request
+ */
public record RequestUrl(String path, Map queryParameters) {
+ /**
+ * Create a new instance of the {@link RequestUrl}.
+ *
+ * @param path the path of the request (without the query parameters)
+ * @param queryParameters the query parameters of the request
+ */
public RequestUrl {
queryParameters = Collections.unmodifiableMap(queryParameters);
}
diff --git a/src/test/java/org/flowable/mockwebserver/ExampleTest.java b/src/test/java/org/flowable/mockwebserver/ExampleTest.java
index afbb281..920076d 100644
--- a/src/test/java/org/flowable/mockwebserver/ExampleTest.java
+++ b/src/test/java/org/flowable/mockwebserver/ExampleTest.java
@@ -125,5 +125,7 @@ void queryPets() throws IOException, InterruptedException {
"type": "dog"
}
""");
+
+ assertThat(server.requestCount()).isEqualTo(2);
}
}