iterate() throws IOException {
get.releaseConnection();
}
}
+
+ // @todo #83:30min Several API calls required an authentication header as
+ // explained here:
+ // https://docs.docker.com/engine/api/v1.35/#section/Authentication
+ // (including Images.create()). Find a way to make a reusable object from
+ // that action and introduce it here.
+ // @checkstyle ParameterNumber (4 lines)
+ @Override
+ public Images create(
+ final String name, final URL source, final String repo, final String tag
+ ) throws IOException, UnexpectedResponseException {
+ final HttpPost create = new HttpPost(
+ new UncheckedUriBuilder(this.baseUri.toString().concat("/create"))
+ .addParameter("fromImage", name)
+ .addParameter("fromSrc", source.toString())
+ .addParameter("repo", repo)
+ .addParameter("tag", tag)
+ .build()
+ );
+ try {
+ final int status = this.client.execute(create)
+ .getStatusLine()
+ .getStatusCode();
+ if (HttpStatus.SC_OK != status) {
+ throw new UnexpectedResponseException(
+ create.getURI().toString(), status, HttpStatus.SC_OK
+ );
+ }
+ return this;
+ } finally {
+ create.releaseConnection();
+ }
+ }
}
diff --git a/src/main/java/com/amihaiemil/docker/UncheckedUriBuilder.java b/src/main/java/com/amihaiemil/docker/UncheckedUriBuilder.java
new file mode 100644
index 00000000..9058d3fb
--- /dev/null
+++ b/src/main/java/com/amihaiemil/docker/UncheckedUriBuilder.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;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import org.apache.http.client.utils.URIBuilder;
+
+/**
+ * A {@link URIBuilder} that hides checked exceptions in the methods used
+ * throughout this library. Used under the assumption that the structure
+ * of URIs created using this class are valid.
+ * @author George Aristy (george.aristy@gmail.com)
+ * @version $Id$
+ * @since 0.0.1
+ */
+final class UncheckedUriBuilder extends URIBuilder {
+ /**
+ * Ctor.
+ * @param uri Base URI.
+ * @throws IllegalArgumentException From {@link URI#create(String)}.
+ * @throws NullPointerException From {@link URI#create(String)}.
+ */
+ UncheckedUriBuilder(
+ final String uri
+ ) throws IllegalArgumentException, NullPointerException {
+ super(URI.create(uri));
+ }
+
+ @Override
+ public UncheckedUriBuilder addParameter(
+ final String name, final String value
+ ) {
+ super.addParameter(name, value);
+ return this;
+ }
+
+ @Override
+ public URI build() {
+ try {
+ return super.build();
+ } catch (final URISyntaxException ex) {
+ throw new IllegalStateException(
+ "Unexpected error while building a URI!", ex
+ );
+ }
+ }
+}
diff --git a/src/test/java/com/amihaiemil/docker/RtImagesTestCase.java b/src/test/java/com/amihaiemil/docker/RtImagesTestCase.java
index 3b09c0c7..b50abf59 100644
--- a/src/test/java/com/amihaiemil/docker/RtImagesTestCase.java
+++ b/src/test/java/com/amihaiemil/docker/RtImagesTestCase.java
@@ -26,8 +26,10 @@
package com.amihaiemil.docker;
import com.amihaiemil.docker.mock.AssertRequest;
+import com.amihaiemil.docker.mock.Condition;
import com.amihaiemil.docker.mock.Response;
import java.net.URI;
+import java.net.URL;
import java.util.concurrent.atomic.AtomicInteger;
import javax.json.Json;
import org.apache.http.HttpStatus;
@@ -85,4 +87,66 @@ public void iterateFailsIfResponseIs500() throws Exception {
URI.create("http://localhost")
).iterate();
}
+
+ /**
+ * {@link RtImages#create(String, URL, String, String)} must construct the
+ * URL with parameters correctly.
+ *
+ * Notice the escaped characters for the 'fromSrc' parameter's value.
+ * @throws Exception If an error occurs.
+ */
+ @Test
+ public void createSetsGivenParameters() throws Exception {
+ new RtImages(
+ new AssertRequest(
+ new Response(HttpStatus.SC_OK),
+ new Condition(
+ // @checkstyle LineLength (1 line)
+ "RtImages.create() failed to correctly build the request URI.",
+ req -> {
+ System.out.println(req.getRequestLine().getUri());
+ return req.getRequestLine().getUri().endsWith(
+ // @checkstyle LineLength (1 line)
+ "/create?fromImage=testImage&fromSrc=http%3A%2F%2Fdocker.registry.com&repo=testRepo&tag=1.23"
+ );
+ }
+ )
+ ),
+ URI.create("http://localhost")
+ )
+ .create(
+ "testImage", new URL("http://docker.registry.com"),
+ "testRepo", "1.23"
+ );
+ }
+
+ /**
+ * RtImages.create() must throw an {@link UnexpectedResponseException}
+ * if the docker API responds with status code 404.
+ * @throws Exception The UnexpectedResponseException.
+ */
+ @Test(expected = UnexpectedResponseException.class)
+ public void createErrorOnStatus404() throws Exception {
+ new RtImages(
+ new AssertRequest(
+ new Response(HttpStatus.SC_NOT_FOUND)
+ ),
+ URI.create("http://localhost")
+ ).create("", new URL("http://registry.docker.com"), "", "");
+ }
+
+ /**
+ * RtImages.create() must throw an {@link UnexpectedResponseException}
+ * if the docker API responds with status code 500.
+ * @throws Exception The UnexpectedResponseException.
+ */
+ @Test(expected = UnexpectedResponseException.class)
+ public void createErrorOnStatus500() throws Exception {
+ new RtImages(
+ new AssertRequest(
+ new Response(HttpStatus.SC_INTERNAL_SERVER_ERROR)
+ ),
+ URI.create("http://localhost")
+ ).create("", new URL("http://registry.docker.com"), "", "");
+ }
}
diff --git a/src/test/java/com/amihaiemil/docker/mock/Response.java b/src/test/java/com/amihaiemil/docker/mock/Response.java
index f4cec46b..05933722 100644
--- a/src/test/java/com/amihaiemil/docker/mock/Response.java
+++ b/src/test/java/com/amihaiemil/docker/mock/Response.java
@@ -65,6 +65,16 @@ public final class Response implements HttpResponse {
*/
private final HttpEntity payload;
+ /**
+ * Ctor.
+ *
+ * Response with no payload.
+ * @param status The {@link HttpStatus http status code}
+ */
+ public Response(final int status) {
+ this(status, "");
+ }
+
/**
* Ctor.
*