diff --git a/src/main/java/com/amihaiemil/docker/ListedVolumes.java b/src/main/java/com/amihaiemil/docker/ListedVolumes.java index fe9ef446..73d175f5 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,27 @@ 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( + String.format("%s/%s", + super.baseUri().toString(), + "volumes") + ), + volume -> new RtVolume( + volume, + super.client(), + URI.create( + String.format("%s/%s", + 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..d03e97fb --- /dev/null +++ b/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java @@ -0,0 +1,68 @@ +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.collection.IsIterableWithSize; +import org.hamcrest.core.IsEqual; +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( + "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") + ); + MatcherAssert.assertThat( + "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 new file mode 100644 index 00000000..d23c0c2b --- /dev/null +++ b/src/test/java/com/amihaiemil/docker/RtVolumeTestCase.java @@ -0,0 +1,90 @@ +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.collection.IsCollectionWithSize; +import org.hamcrest.core.IsEqual; +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( + "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"), + new IsEqual<>("custom") + ); + MatcherAssert.assertThat( + "Mountpoint value should be '/var/lib/docker/volumes/v1'", + info.getString("Mountpoint"), + new IsEqual<>("/var/lib/docker/volumes/v1") + ); + MatcherAssert.assertThat( + "Scope value should be 'local'", + info.getString("Scope"), + new IsEqual<>("local") + ); + } + +}