diff --git a/src/test/java/com/amihaiemil/docker/mock/Response.java b/src/test/java/com/amihaiemil/docker/mock/Response.java index 4bb1b030..f459d687 100644 --- a/src/test/java/com/amihaiemil/docker/mock/Response.java +++ b/src/test/java/com/amihaiemil/docker/mock/Response.java @@ -29,8 +29,10 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; -import java.time.Instant; +import java.util.Date; import java.util.Locale; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.http.Header; import org.apache.http.HeaderIterator; import org.apache.http.HttpEntity; @@ -40,9 +42,10 @@ import org.apache.http.StatusLine; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.message.BasicHttpResponse; import org.apache.http.message.BasicStatusLine; import org.apache.http.params.HttpParams; -import org.apache.http.util.EntityUtils; /** * An {@link HttpResponse} suitable for tests. Can be configured with @@ -51,20 +54,14 @@ * @author George Aristy (george.aristy@gmail.com) * @version $Id$ * @since 0.0.1 - * @todo #79:30min The 'asString()' method needs a little more work (fix the - * formatting on the date header value, etc) and then test the 'printTo()' - * method in conjunction with the UnixServer. */ public final class Response implements HttpResponse { + /** - * This response's status line. + * Its backbone, holding what we need. */ - private final StatusLine statusLine; - /** - * This response's payload. - */ - private final HttpEntity payload; - + private HttpResponse backbone; + /** * Ctor. *

@@ -82,17 +79,26 @@ public Response(final int status) { * @param jsonPayload The json payload */ public Response(final int status, final String jsonPayload) { - this.statusLine = new BasicStatusLine( - new ProtocolVersion("HTTP", 1, 1), status, "" + this.backbone = new BasicHttpResponse( + new BasicStatusLine( + new ProtocolVersion("HTTP", 1, 1), status, "REASON" + ) ); - this.payload = new StringEntity( - jsonPayload, ContentType.APPLICATION_JSON + this.backbone.setEntity( + new StringEntity( + jsonPayload, ContentType.APPLICATION_JSON + ) + ); + this.backbone.setHeader("Date", new Date().toString()); + this.backbone.setHeader( + "Content-Length", String.valueOf(jsonPayload.getBytes().length) ); + this.backbone.setHeader("Content-Type", "application/json"); } @Override public StatusLine getStatusLine() { - return this.statusLine; + return this.backbone.getStatusLine(); } @Override @@ -124,7 +130,7 @@ public void setReasonPhrase(final String reason) @Override public HttpEntity getEntity() { - return this.payload; + return this.backbone.getEntity(); } @Override @@ -235,7 +241,7 @@ public void setParams(final HttpParams params) { public void printTo(final WritableByteChannel channel) throws IOException { channel.write( ByteBuffer.wrap( - this.asString().getBytes(Charsets.UTF8_CHARSET) + this.toString().getBytes(Charsets.UTF8_CHARSET) ) ); } @@ -243,30 +249,31 @@ public void printTo(final WritableByteChannel channel) throws IOException { /** * This response as a string. * @return String representation of this {@link Response}. - * @throws IOException If an error occurs. */ - private String asString() throws IOException { + @Override + public String toString() { final String CRLF = "" + (char) 0x0D + (char) 0x0A; - final StringBuilder builder = new StringBuilder("HTTP/") - .append(this.statusLine.getProtocolVersion()) - .append(" ") - .append(this.statusLine.getStatusCode()) - .append(" ") - .append(this.statusLine.getReasonPhrase()) - .append(CRLF) - .append("Date: ") - .append(Instant.now()) - .append(CRLF); - if (this.payload.getContentLength() > 0) { - builder.append("ContentType: ") - .append(this.payload.getContentType().getValue()) - .append(CRLF) - .append("Content-Length: ") - .append(this.payload.getContentLength()) - .append(CRLF) - .append(CRLF) - .append(EntityUtils.toString(this.payload)); + try { + final StringBuilder builder = new StringBuilder() + .append(this.backbone.getStatusLine().toString()) + .append(CRLF) + .append( + Stream.of( + this.backbone.getAllHeaders() + ).map(header -> header.toString()) + .collect(Collectors.joining(CRLF)) + ) + .append(CRLF).append(CRLF) + .append( + new BasicResponseHandler().handleEntity( + this.backbone.getEntity() + ) + ); + return builder.toString(); + } catch (final IOException ex) { + throw new IllegalStateException( + "IOException when reading the HTTP response. " + ex + ); } - return builder.toString(); } } diff --git a/src/test/java/com/amihaiemil/docker/mock/ResponseTestCase.java b/src/test/java/com/amihaiemil/docker/mock/ResponseTestCase.java new file mode 100644 index 00000000..c089e334 --- /dev/null +++ b/src/test/java/com/amihaiemil/docker/mock/ResponseTestCase.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2018, Mihai Emil Andronache + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1)Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2)Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3)Neither the name of docker-java-api nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.amihaiemil.docker.mock; + +import javax.json.Json; +import org.apache.http.HttpStatus; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * Unit tests for {@link Response}. + * @author Mihai Andronache (amihaiemil@gmail.com) + * @version $Id$ + * @since 0.0.2 + */ +public final class ResponseTestCase { + + /** + * {@link Response} can return its String representation. + */ + @Test + public void toStringWorks() { + MatcherAssert.assertThat( + new Response( + HttpStatus.SC_OK, + Json.createArrayBuilder() + .add( + Json.createObjectBuilder() + .add("Id", "sha256:e216a057b1cb1efc1") + ).add( + Json.createObjectBuilder() + .add("Id", "sha256:3e314f95dcace0f5e") + ).build().toString() + ).toString(), + Matchers.allOf( + Matchers.startsWith("HTTP/1.1 200 REASON"), + Matchers.endsWith( + // @checkstyle LineLength (1 lines) + "[{\"Id\":\"sha256:e216a057b1cb1efc1\"},{\"Id\":\"sha256:3e314f95dcace0f5e\"}]" + ), + Matchers.containsString("Content-Length: 69"), + Matchers.containsString("" + (char) 0x0D + (char) 0x0A) + ) + ); + } + +}