From 6771963d2bb1de5972fa5ce2a010adeecb77d5f6 Mon Sep 17 00:00:00 2001 From: Boris Kuzmic Date: Thu, 6 Dec 2018 08:12:11 +0100 Subject: [PATCH 1/3] Implementing iterable Volumes --- .../com/amihaiemil/docker/ListedVolumes.java | 25 +++++- .../java/com/amihaiemil/docker/RtVolume.java | 54 +++++++++++++ .../java/com/amihaiemil/docker/RtVolumes.java | 23 +++++- .../java/com/amihaiemil/docker/Volume.java | 19 ++++- .../java/com/amihaiemil/docker/Volumes.java | 13 +++- .../docker/ListedVolumesTestCase.java | 59 ++++++++++++++ .../amihaiemil/docker/RtVolumeTestCase.java | 77 +++++++++++++++++++ 7 files changed, 263 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/amihaiemil/docker/RtVolume.java create mode 100644 src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java create mode 100644 src/test/java/com/amihaiemil/docker/RtVolumeTestCase.java diff --git a/src/main/java/com/amihaiemil/docker/ListedVolumes.java b/src/main/java/com/amihaiemil/docker/ListedVolumes.java index fe9ef446..a91905e3 100644 --- a/src/main/java/com/amihaiemil/docker/ListedVolumes.java +++ b/src/main/java/com/amihaiemil/docker/ListedVolumes.java @@ -26,16 +26,22 @@ package com.amihaiemil.docker; import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; import java.net.URI; +import java.util.Iterator; /** * Listed volumes. * @author Marco Teixeira (marcoo.teixeira@gmail.com) * @version $Id$ * @since 0.0.6 + * @todo #181:30min Finish implementation here, add a Map to this class, that + * would hold the actual filters and apply them when making the call in the + * iterator() method. Also, more ctors should be available, at least one with + * filters and one without filters. */ -public class ListedVolumes extends RtVolumes { +final class ListedVolumes extends RtVolumes { /** * Ctor. @@ -46,4 +52,21 @@ public class ListedVolumes extends RtVolumes { ListedVolumes(final HttpClient client, final URI uri, final Docker dkr) { super(client, uri, dkr); } + + @Override + public Iterator iterator() { + return new ResourcesIterator<>( + super.client(), + new HttpGet(super.baseUri().toString() + "/volumes"), + volume -> new RtVolume( + volume, + super.client(), + URI.create( + super.baseUri().toString() + "/" + + volume.getString("Name") + ), + super.docker() + ) + ); + } } diff --git a/src/main/java/com/amihaiemil/docker/RtVolume.java b/src/main/java/com/amihaiemil/docker/RtVolume.java new file mode 100644 index 00000000..0ab93e0f --- /dev/null +++ b/src/main/java/com/amihaiemil/docker/RtVolume.java @@ -0,0 +1,54 @@ +package com.amihaiemil.docker; + +import org.apache.http.client.HttpClient; + +import javax.json.JsonObject; +import java.io.IOException; +import java.net.URI; + +/** + * Runtime {@link Volume}. + * @author Boris Kuzmic (boris.kuzmic@gmail.com) + * @since 0.0.7 + */ +final class RtVolume extends JsonResource implements Volume { + + /** + * Apache HttpClient which sends the requests. + */ + private final HttpClient client; + + /** + * Base URI. + */ + private final URI baseUri; + + /** + * Docker API. + */ + private final Docker docker; + + /** + * Ctor. + * @param rep JsonObject representation of this Volume. + * @param client The http client. + * @param uri The URI for this image. + * @param dkr The docker entry point. + * @checkstyle ParameterNumber (5 lines) + */ + RtVolume( + final JsonObject rep, final HttpClient client, + final URI uri, final Docker dkr + ) { + super(rep); + this.client = client; + this.baseUri = uri; + this.docker = dkr; + } + + @Override + public JsonObject inspect() + throws IOException, UnexpectedResponseException { + return new Inspection(this.client, this.baseUri.toString()); + } +} diff --git a/src/main/java/com/amihaiemil/docker/RtVolumes.java b/src/main/java/com/amihaiemil/docker/RtVolumes.java index 2aa869c2..de4362ad 100644 --- a/src/main/java/com/amihaiemil/docker/RtVolumes.java +++ b/src/main/java/com/amihaiemil/docker/RtVolumes.java @@ -35,7 +35,7 @@ * @version $Id$ * @since 0.0.6 */ -public abstract class RtVolumes implements Volumes { +abstract class RtVolumes implements Volumes { /** * Apache HttpClient which sends the requests. */ @@ -62,4 +62,25 @@ public abstract class RtVolumes implements Volumes { this.baseUri = uri; this.docker = dkr; } + + @Override + public Docker docker() { + return this.docker; + } + + /** + * Get the (protected) HttpClient for subclasses. + * @return HttpClient. + */ + HttpClient client() { + return this.client; + } + + /** + * Get the (protected) base URI for subclasses. + * @return URI. + */ + URI baseUri() { + return this.baseUri; + } } diff --git a/src/main/java/com/amihaiemil/docker/Volume.java b/src/main/java/com/amihaiemil/docker/Volume.java index cc747473..26f23ef0 100644 --- a/src/main/java/com/amihaiemil/docker/Volume.java +++ b/src/main/java/com/amihaiemil/docker/Volume.java @@ -25,14 +25,29 @@ */ package com.amihaiemil.docker; +import javax.json.JsonObject; +import java.io.IOException; + /** * A volume manager. * @author Marco Teixeira (marcoo.teixeira@gmail.com) + * @author Boris Kuzmic (boris.kuzmic@gmail.com) * @version $Id$ * @see Docker Volume API * @since 0.0.6 - * @todo #169:30min Continue the implementation of Volume. + * @todo #179:30min Continue implementing create and remove volume operations. * */ -public interface Volume { +public interface Volume extends JsonObject { + + /** + * Return low-level information about this volume. + * @return JsonObject information. + * @see Inspect Volume + * @throws IOException If something goes wrong. + * @throws UnexpectedResponseException If the status response is not + * the expected one (200 OK). + */ + JsonObject inspect() throws IOException, UnexpectedResponseException; + } diff --git a/src/main/java/com/amihaiemil/docker/Volumes.java b/src/main/java/com/amihaiemil/docker/Volumes.java index 8db330f8..84f589b1 100644 --- a/src/main/java/com/amihaiemil/docker/Volumes.java +++ b/src/main/java/com/amihaiemil/docker/Volumes.java @@ -28,10 +28,17 @@ /** * Volumes API. * @author Mihai Andronache (amihaiemil@gmail.com) + * @author Boris Kuzmic (boris.kuzmic@gmail.com) * @version $Id$ * @since 0.0.1 - * @todo #169:30min Extend Iterable of Volumes to - * continue implementing the rest of the operations for the volume. + * @todo #180:30min Continue implementing prune volumes operation. */ -public interface Volumes { +public interface Volumes extends Iterable { + + /** + * Return the Docker engine where these Images came from. + * @return Docker. + */ + Docker docker(); + } diff --git a/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java b/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java new file mode 100644 index 00000000..dba5def4 --- /dev/null +++ b/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java @@ -0,0 +1,59 @@ +package com.amihaiemil.docker; + +import com.amihaiemil.docker.mock.AssertRequest; +import com.amihaiemil.docker.mock.Condition; +import com.amihaiemil.docker.mock.Response; +import org.apache.http.HttpStatus; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; +import org.mockito.Mockito; + +import java.net.URI; +import java.util.Iterator; + +/** + * Unit tests for {@link ListedVolumes}. + * @author Boris Kuzmic (boris.kuzmic@gmail.com) + * @since 0.0.7 + */ +public final class ListedVolumesTestCase { + + /** + * {@link ListedVolumes} can iterate over them without + * filters. + */ + @Test + public void iterateAll() { + final Volumes all = new ListedVolumes( + new AssertRequest( + new Response( + HttpStatus.SC_OK, + "[{\"Name\": \"abc1\"}, {\"Name\":\"cde2\"}]" + ), + new Condition( + "iterate() must send a GET request", + req -> "GET".equals(req.getRequestLine().getMethod()) + ), + new Condition( + "iterate() resource URL must be '/volumes'", + req -> req.getRequestLine() + .getUri().endsWith("/volumes") + ) + ), + URI.create("http://localhost/volumes"), + Mockito.mock(Docker.class) + ); + MatcherAssert.assertThat(all, Matchers.iterableWithSize(2)); + final Iterator itr = all.iterator(); + MatcherAssert.assertThat( + itr.next().getString("Name"), + Matchers.equalTo("abc1") + ); + MatcherAssert.assertThat( + itr.next().getString("Name"), + Matchers.equalTo("cde2") + ); + + } +} diff --git a/src/test/java/com/amihaiemil/docker/RtVolumeTestCase.java b/src/test/java/com/amihaiemil/docker/RtVolumeTestCase.java new file mode 100644 index 00000000..e2c86f25 --- /dev/null +++ b/src/test/java/com/amihaiemil/docker/RtVolumeTestCase.java @@ -0,0 +1,77 @@ +package com.amihaiemil.docker; + +import com.amihaiemil.docker.mock.AssertRequest; +import com.amihaiemil.docker.mock.Condition; +import com.amihaiemil.docker.mock.Response; +import org.apache.http.HttpStatus; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; +import org.mockito.Mockito; + +import javax.json.Json; +import javax.json.JsonObject; +import java.net.URI; + +/** + * Unit tests for RtVolume. + * @author Boris Kuzmic (boris.kuzmic@gmail.com) + * @since 0.0.7 + * @checkstyle MethodName (500 lines) + */ +public final class RtVolumeTestCase { + + /** + * Mock docker. + */ + private static final Docker DOCKER = Mockito.mock(Docker.class); + + /** + * RtVolume can return info about itself. + * @throws Exception If something goes wrong. + */ + @Test + public void inspectsItself() throws Exception { + final Volume volume = new RtVolume( + Json.createObjectBuilder().build(), + new AssertRequest( + new Response( + HttpStatus.SC_OK, + Json.createObjectBuilder() + .add("Name", "v1") + .add("Driver", "custom") + .add("Mountpoint", "/var/lib/docker/volumes/v1") + .add("Scope", "local") + .build().toString() + ), + new Condition( + "Method should be a GET", + req -> req.getRequestLine().getMethod().equals("GET") + ), + new Condition( + "Resource path must be /{name}", + req -> req.getRequestLine().getUri().endsWith("/v1") + ) + ), + URI.create("http://localhost:80/1.35/volumes/v1"), + DOCKER + ); + final JsonObject info = volume.inspect(); + MatcherAssert.assertThat(info.keySet(), Matchers.hasSize(4)); + MatcherAssert.assertThat( + info.getString("Name"), Matchers.equalTo("v1") + ); + MatcherAssert.assertThat( + info.getString("Driver"), + Matchers.equalTo("custom") + ); + MatcherAssert.assertThat( + info.getString("Mountpoint"), + Matchers.equalTo("/var/lib/docker/volumes/v1") + ); + MatcherAssert.assertThat( + info.getString("Scope"), Matchers.equalTo("local") + ); + } + +} From aba4ea17b1ea6298b7db1f5f25b1ed8f21a6e762 Mon Sep 17 00:00:00 2001 From: Boris Kuzmic Date: Thu, 6 Dec 2018 13:21:57 +0100 Subject: [PATCH 2/3] Fixing problems found in review --- .../com/amihaiemil/docker/ListedVolumes.java | 12 +++++++--- .../docker/ListedVolumesTestCase.java | 14 +++++++---- .../amihaiemil/docker/RtVolumeTestCase.java | 23 ++++++++++++++----- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/amihaiemil/docker/ListedVolumes.java b/src/main/java/com/amihaiemil/docker/ListedVolumes.java index a91905e3..73d175f5 100644 --- a/src/main/java/com/amihaiemil/docker/ListedVolumes.java +++ b/src/main/java/com/amihaiemil/docker/ListedVolumes.java @@ -57,13 +57,19 @@ final class ListedVolumes extends RtVolumes { public Iterator iterator() { return new ResourcesIterator<>( super.client(), - new HttpGet(super.baseUri().toString() + "/volumes"), + new HttpGet( + String.format("%s/%s", + super.baseUri().toString(), + "volumes") + ), volume -> new RtVolume( volume, super.client(), URI.create( - super.baseUri().toString() + "/" - + volume.getString("Name") + String.format("%s/%s", + super.baseUri().toString(), + volume.getString("Name") + ) ), super.docker() ) diff --git a/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java b/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java index dba5def4..2e2db817 100644 --- a/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java +++ b/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java @@ -5,7 +5,8 @@ import com.amihaiemil.docker.mock.Response; import org.apache.http.HttpStatus; import org.hamcrest.MatcherAssert; -import org.hamcrest.Matchers; +import org.hamcrest.collection.IsIterableWithSize; +import org.hamcrest.core.IsEqual; import org.junit.Test; import org.mockito.Mockito; @@ -44,15 +45,20 @@ public void iterateAll() { URI.create("http://localhost/volumes"), Mockito.mock(Docker.class) ); - MatcherAssert.assertThat(all, Matchers.iterableWithSize(2)); + MatcherAssert.assertThat( + "There should be 2 volumes in the list", + all, new IsIterableWithSize<>(new IsEqual<>(2)) + ); final Iterator itr = all.iterator(); MatcherAssert.assertThat( + "Name should match abc1", itr.next().getString("Name"), - Matchers.equalTo("abc1") + new IsEqual<>("abc1") ); MatcherAssert.assertThat( + "Name should match cde2", itr.next().getString("Name"), - Matchers.equalTo("cde2") + new IsEqual<>("cde2") ); } diff --git a/src/test/java/com/amihaiemil/docker/RtVolumeTestCase.java b/src/test/java/com/amihaiemil/docker/RtVolumeTestCase.java index e2c86f25..e48d43f7 100644 --- a/src/test/java/com/amihaiemil/docker/RtVolumeTestCase.java +++ b/src/test/java/com/amihaiemil/docker/RtVolumeTestCase.java @@ -5,7 +5,8 @@ import com.amihaiemil.docker.mock.Response; import org.apache.http.HttpStatus; import org.hamcrest.MatcherAssert; -import org.hamcrest.Matchers; +import org.hamcrest.collection.IsCollectionWithSize; +import org.hamcrest.core.IsEqual; import org.junit.Test; import org.mockito.Mockito; @@ -57,20 +58,30 @@ public void inspectsItself() throws Exception { DOCKER ); final JsonObject info = volume.inspect(); - MatcherAssert.assertThat(info.keySet(), Matchers.hasSize(4)); MatcherAssert.assertThat( - info.getString("Name"), Matchers.equalTo("v1") + "Size of Json keys should be 4", + info.keySet(), + new IsCollectionWithSize<>( + new IsEqual<>(4))); + MatcherAssert.assertThat( + "Name value should be 'v1'", + info.getString("Name"), + new IsEqual<>("v1") ); MatcherAssert.assertThat( + "Driver value should be 'custom'", info.getString("Driver"), - Matchers.equalTo("custom") + new IsEqual<>("custom") ); MatcherAssert.assertThat( + "Mountpoint value should be '/var/lib/docker/volumes/v1'", info.getString("Mountpoint"), - Matchers.equalTo("/var/lib/docker/volumes/v1") + new IsEqual<>("/var/lib/docker/volumes/v1") ); MatcherAssert.assertThat( - info.getString("Scope"), Matchers.equalTo("local") + "Scope value should be 'local'", + info.getString("Scope"), + new IsEqual<>("local") ); } From 5a8ab3e28f16be28a57f8be1044416450b22f765 Mon Sep 17 00:00:00 2001 From: Boris Kuzmic Date: Thu, 6 Dec 2018 13:51:23 +0100 Subject: [PATCH 3/3] Fixing indentation --- .../docker/ListedVolumesTestCase.java | 19 +++++++++++-------- .../amihaiemil/docker/RtVolumeTestCase.java | 10 ++++++---- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java b/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java index 2e2db817..d03e97fb 100644 --- a/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java +++ b/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java @@ -46,19 +46,22 @@ public void iterateAll() { Mockito.mock(Docker.class) ); MatcherAssert.assertThat( - "There should be 2 volumes in the list", - all, new IsIterableWithSize<>(new IsEqual<>(2)) + "There should be 2 volumes in the list", + all, + new IsIterableWithSize<>( + new IsEqual<>(2) + ) ); final Iterator itr = all.iterator(); MatcherAssert.assertThat( - "Name should match abc1", - itr.next().getString("Name"), - new IsEqual<>("abc1") + "Name should match abc1", + itr.next().getString("Name"), + new IsEqual<>("abc1") ); MatcherAssert.assertThat( - "Name should match cde2", - itr.next().getString("Name"), - new IsEqual<>("cde2") + "Name should match cde2", + itr.next().getString("Name"), + new IsEqual<>("cde2") ); } diff --git a/src/test/java/com/amihaiemil/docker/RtVolumeTestCase.java b/src/test/java/com/amihaiemil/docker/RtVolumeTestCase.java index e48d43f7..d23c0c2b 100644 --- a/src/test/java/com/amihaiemil/docker/RtVolumeTestCase.java +++ b/src/test/java/com/amihaiemil/docker/RtVolumeTestCase.java @@ -59,10 +59,12 @@ public void inspectsItself() throws Exception { ); final JsonObject info = volume.inspect(); MatcherAssert.assertThat( - "Size of Json keys should be 4", - info.keySet(), - new IsCollectionWithSize<>( - new IsEqual<>(4))); + "Size of Json keys should be 4", + info.keySet(), + new IsCollectionWithSize<>( + new IsEqual<>(4) + ) + ); MatcherAssert.assertThat( "Name value should be 'v1'", info.getString("Name"),