diff --git a/src/main/java/com/amihaiemil/docker/RtVolume.java b/src/main/java/com/amihaiemil/docker/RtVolume.java
index 0ab93e0f..7efec933 100644
--- a/src/main/java/com/amihaiemil/docker/RtVolume.java
+++ b/src/main/java/com/amihaiemil/docker/RtVolume.java
@@ -1,10 +1,11 @@
package com.amihaiemil.docker;
-import org.apache.http.client.HttpClient;
-
-import javax.json.JsonObject;
import java.io.IOException;
import java.net.URI;
+import javax.json.JsonObject;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpDelete;
/**
* Runtime {@link Volume}.
@@ -51,4 +52,29 @@ public JsonObject inspect()
throws IOException, UnexpectedResponseException {
return new Inspection(this.client, this.baseUri.toString());
}
+
+ @Override
+ public void remove() throws IOException, UnexpectedResponseException {
+ this.remove(false);
+ }
+
+ @Override
+ public void remove(final boolean force)
+ throws IOException, UnexpectedResponseException {
+ final UncheckedUriBuilder uri = new UncheckedUriBuilder(
+ this.baseUri.toString()
+ );
+ uri.addParameter("force", String.valueOf(force));
+ final HttpDelete delete = new HttpDelete(
+ uri.build()
+ );
+ try {
+ this.client.execute(
+ delete,
+ new MatchStatus(delete.getURI(), HttpStatus.SC_OK)
+ );
+ } finally {
+ delete.releaseConnection();
+ }
+ }
}
diff --git a/src/main/java/com/amihaiemil/docker/RtVolumes.java b/src/main/java/com/amihaiemil/docker/RtVolumes.java
index 435dc1e0..1a9f9c02 100644
--- a/src/main/java/com/amihaiemil/docker/RtVolumes.java
+++ b/src/main/java/com/amihaiemil/docker/RtVolumes.java
@@ -27,9 +27,13 @@
import java.io.IOException;
import java.net.URI;
+import javax.json.Json;
+import javax.json.JsonObjectBuilder;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
/**
* Runtime {@link Volumes}.
@@ -80,6 +84,33 @@ public void prune() throws IOException, UnexpectedResponseException {
}
}
+ @Override
+ public void create(final String name)
+ throws IOException, UnexpectedResponseException {
+ JsonObjectBuilder json = Json.createObjectBuilder();
+ json.add("Name", name);
+ final HttpPost create =
+ new HttpPost(
+ String.format("%s/%s", this.baseUri.toString(), "create")
+ );
+ try {
+ create.setEntity(
+ new StringEntity(
+ json.build().toString(), ContentType.APPLICATION_JSON
+ )
+ );
+ this.client.execute(
+ create,
+ new MatchStatus(
+ create.getURI(),
+ HttpStatus.SC_CREATED
+ )
+ );
+ } finally {
+ create.releaseConnection();
+ }
+ }
+
@Override
public Docker docker() {
return this.docker;
diff --git a/src/main/java/com/amihaiemil/docker/Volume.java b/src/main/java/com/amihaiemil/docker/Volume.java
index 26f23ef0..cb87d7be 100644
--- a/src/main/java/com/amihaiemil/docker/Volume.java
+++ b/src/main/java/com/amihaiemil/docker/Volume.java
@@ -25,8 +25,8 @@
*/
package com.amihaiemil.docker;
-import javax.json.JsonObject;
import java.io.IOException;
+import javax.json.JsonObject;
/**
* A volume manager.
@@ -35,7 +35,6 @@
* @version $Id$
* @see Docker Volume API
* @since 0.0.6
- * @todo #179:30min Continue implementing create and remove volume operations.
*
*/
public interface Volume extends JsonObject {
@@ -50,4 +49,24 @@ public interface Volume extends JsonObject {
*/
JsonObject inspect() throws IOException, UnexpectedResponseException;
+ /**
+ * Remove a volume.
+ * @throws IOException If something goes wrong.
+ * @throws UnexpectedResponseException If the status response is not
+ * the expected one (200 OK).
+ * @see Remove a volume
+ */
+ void remove() throws IOException, UnexpectedResponseException;
+
+ /**
+ * Remove a volume.
+ * @param force If true remove volumes that are in use
+ * @throws IOException If something goes wrong.
+ * @throws UnexpectedResponseException If the status response is not
+ * the expected one (200 OK).
+ * @see Remove a volume
+ */
+ void remove(final boolean force)
+ throws IOException, UnexpectedResponseException;
+
}
diff --git a/src/main/java/com/amihaiemil/docker/Volumes.java b/src/main/java/com/amihaiemil/docker/Volumes.java
index f47a58f8..65a0398a 100644
--- a/src/main/java/com/amihaiemil/docker/Volumes.java
+++ b/src/main/java/com/amihaiemil/docker/Volumes.java
@@ -33,9 +33,23 @@
* @author Boris Kuzmic (boris.kuzmic@gmail.com)
* @version $Id$
* @since 0.0.1
+ * @todo #183:30min Extend create with options to specify driver,
+ * driver options and add labels as specified at:
+ * https://docs.docker.com/engine/api/v1.35/#operation/VolumeCreate
*/
public interface Volumes extends Iterable {
+ /**
+ * Create a volume.
+ * @param name Name of the volume.
+ * @throws IOException If something goes wrong.
+ * @throws UnexpectedResponseException If the status response is not
+ * the expected one (200 OK).
+ * @see Create a volume
+ */
+ void create(final String name)
+ throws IOException, UnexpectedResponseException;
+
/**
* Deletes unused volumes.
* @throws IOException If an I/O error occurs.
diff --git a/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java b/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java
index d03e97fb..dbe1c0b6 100644
--- a/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java
+++ b/src/test/java/com/amihaiemil/docker/ListedVolumesTestCase.java
@@ -63,6 +63,5 @@ public void iterateAll() {
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 d23c0c2b..6cc49d63 100644
--- a/src/test/java/com/amihaiemil/docker/RtVolumeTestCase.java
+++ b/src/test/java/com/amihaiemil/docker/RtVolumeTestCase.java
@@ -3,6 +3,9 @@
import com.amihaiemil.docker.mock.AssertRequest;
import com.amihaiemil.docker.mock.Condition;
import com.amihaiemil.docker.mock.Response;
+import java.net.URI;
+import javax.json.Json;
+import javax.json.JsonObject;
import org.apache.http.HttpStatus;
import org.hamcrest.MatcherAssert;
import org.hamcrest.collection.IsCollectionWithSize;
@@ -10,10 +13,6 @@
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)
@@ -87,4 +86,90 @@ public void inspectsItself() throws Exception {
);
}
+ /**
+ * RtVolume.remove() must send a DELETE request to the volume's url.
+ * @throws Exception If something goes wrong.
+ */
+ @Test
+ public void removeSendsCorrectRequest() throws Exception {
+ new RtVolume(
+ Json.createObjectBuilder().build(),
+ new AssertRequest(
+ new Response(HttpStatus.SC_OK),
+ new Condition(
+ "RtVolume.remove() must send a DELETE HTTP request",
+ req -> "DELETE".equals(req.getRequestLine().getMethod())
+ ),
+ new Condition(
+ "RtVolume.remove() must send the request to the volume url",
+ req -> "http://localhost/volumes/test?force=false".equals(
+ req.getRequestLine().getUri()
+ )
+ )
+ ),
+ URI.create("http://localhost/volumes/test"),
+ DOCKER
+ ).remove();
+ }
+
+ /**
+ * RtVolume.remove(true) must send a DELETE request to the volume's url
+ * with force param set to true.
+ * @throws Exception If something goes wrong.
+ */
+ @Test
+ public void removeWithForce() throws Exception {
+ new RtVolume(
+ Json.createObjectBuilder().build(),
+ new AssertRequest(
+ new Response(HttpStatus.SC_OK),
+ new Condition(
+ "RtVolume.remove() must send a DELETE HTTP request",
+ req -> "DELETE".equals(req.getRequestLine().getMethod())
+ ),
+ new Condition(
+ "RtVolume.remove() must send the request to the volume url",
+ req -> "http://localhost/volumes/test?force=true".equals(
+ req.getRequestLine().getUri()
+ )
+ )
+ ),
+ URI.create("http://localhost/volumes/test"),
+ DOCKER
+ ).remove(true);
+ }
+
+ /**
+ * RtVolume.remove() must throw UnexpectedResponseException if service
+ * responds with 404.
+ * @throws Exception The UnexpectedResponseException
+ */
+ @Test(expected = UnexpectedResponseException.class)
+ public void removeErrorOn404() throws Exception {
+ new RtVolume(
+ Json.createObjectBuilder().build(),
+ new AssertRequest(
+ new Response(HttpStatus.SC_NOT_FOUND)
+ ),
+ URI.create("http://localhost/volumes/test"),
+ DOCKER
+ ).remove();
+ }
+
+ /**
+ * RtVolume.remove() must throw UnexpectedResponseException if service
+ * responds with 409.
+ * @throws Exception The UnexpectedResponseException
+ */
+ @Test(expected = UnexpectedResponseException.class)
+ public void removeErrorOn409() throws Exception {
+ new RtVolume(
+ Json.createObjectBuilder().build(),
+ new AssertRequest(
+ new Response(HttpStatus.SC_CONFLICT)
+ ),
+ URI.create("http://localhost/volumes/test"),
+ DOCKER
+ ).remove();
+ }
}
diff --git a/src/test/java/com/amihaiemil/docker/RtVolumesTestCase.java b/src/test/java/com/amihaiemil/docker/RtVolumesTestCase.java
index 545f483c..840c73b3 100644
--- a/src/test/java/com/amihaiemil/docker/RtVolumesTestCase.java
+++ b/src/test/java/com/amihaiemil/docker/RtVolumesTestCase.java
@@ -66,6 +66,48 @@ public void pruneThrowsErrorOnResponse500() throws Exception {
).prune();
}
+ /**
+ * RtVolumes.create() must send a correct POST request sends
+ * and exist successfully on response code 201.
+ * @throws Exception If something goes wrong.
+ */
+ @Test
+ public void createOk() throws Exception {
+ new ListedVolumes(
+ new AssertRequest(
+ new Response(HttpStatus.SC_CREATED),
+ new Condition(
+ "RtVolume.create() must send a POST HTTP request",
+ req -> "POST".equals(req.getRequestLine().getMethod())
+ ),
+ new Condition(
+ "RtVolume.create() must send the request to the create url",
+ req -> "http://localhost/volumes/create".equals(
+ req.getRequestLine().getUri()
+ )
+ )
+ ),
+ URI.create("http://localhost/volumes"),
+ DOCKER
+ ).create("test");
+ }
+
+ /**
+ * RtVolumes.create() must throw UnexpectedResponseException if service
+ * responds with 500.
+ * @throws Exception The UnexpectedResponseException.
+ */
+ @Test(expected = UnexpectedResponseException.class)
+ public void createThrowsErrorOnResponse500() throws Exception {
+ new ListedVolumes(
+ new AssertRequest(
+ new Response(HttpStatus.SC_INTERNAL_SERVER_ERROR)
+ ),
+ URI.create("http://localhost/volumes"),
+ DOCKER
+ ).create("test");
+ }
+
/**
* RtVolumes can return its Docker parent.
*/