Add integration tests #2388
diff --git a/integration-tests/digitalocean/README.adoc b/integration-tests/digitalocean/README.adoc
index bad96cf..cf474c9 100644
--- a/integration-tests/digitalocean/README.adoc
+++ b/integration-tests/digitalocean/README.adoc
@@ -4,10 +4,11 @@
To run `camel-quarkus-digitalocean` integration tests using Digitalocean API interactions, you will need a Digitalocean Token. Create a Digitalocean https://www.digitalocean.com/docs/apis-clis/api/create-personal-access-token/[Access Token].
-Then set the following environment variable:
+Then set the following environment variables:
[source,shell]
----
DIGITALOCEAN_AUTH_TOKEN=your-api-token
+DIGITALOCEAN_PUBLIC_KEY=your-public-key-to-run-key-tests
----
diff --git a/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanResource.java b/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanResource.java
index 6ba0357..246c57c 100644
--- a/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanResource.java
+++ b/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanResource.java
@@ -23,25 +23,40 @@
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
+import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import com.myjeeva.digitalocean.pojo.Account;
import com.myjeeva.digitalocean.pojo.Action;
import com.myjeeva.digitalocean.pojo.Backup;
+import com.myjeeva.digitalocean.pojo.Delete;
import com.myjeeva.digitalocean.pojo.Droplet;
+import com.myjeeva.digitalocean.pojo.FloatingIP;
+import com.myjeeva.digitalocean.pojo.Image;
+import com.myjeeva.digitalocean.pojo.Key;
+import com.myjeeva.digitalocean.pojo.Region;
+import com.myjeeva.digitalocean.pojo.Size;
import com.myjeeva.digitalocean.pojo.Snapshot;
+import com.myjeeva.digitalocean.pojo.Tag;
+import com.myjeeva.digitalocean.pojo.Volume;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.component.digitalocean.constants.DigitalOceanHeaders;
import org.apache.camel.component.digitalocean.constants.DigitalOceanOperations;
import org.jboss.logging.Logger;
-@Path("digitalocean/droplet")
+@SuppressWarnings("unchecked")
+@Path("digitalocean")
@ApplicationScoped
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
public class DigitaloceanResource {
private static final Logger LOG = Logger.getLogger(DigitaloceanResource.class);
@@ -49,12 +64,13 @@
private static final String DROPLET_SIZE_1_GB = "s-1vcpu-1gb";
private static final String DROPLET_IMAGE = "ubuntu-20-04-x64";
private static final List<String> DROPLET_TAGS = Arrays.asList("tag1", "tag2");
+ private static final int VOLUME_SIZE_5_GB = 5;
@Inject
ProducerTemplate producerTemplate;
@PUT
- @Path("{name}")
+ @Path("droplet/{name}")
public int createDroplet(@PathParam("name") String name) {
LOG.infof("creating a droplet with name %s", name);
Map<String, Object> headers = createHeaders(name);
@@ -64,9 +80,6 @@
/**
* Creates the headers for operation `Create a Droplet`
- *
- * @param name
- * @return
*/
private Map<String, Object> createHeaders(String name) {
Map<String, Object> headers = new HashMap<>();
@@ -80,7 +93,7 @@
}
@DELETE
- @Path("{id}")
+ @Path("droplet/{id}")
public Response deleteDroplet(@PathParam("id") int id) {
LOG.infof("deleting a droplet with id %s", id);
Map<String, Object> headers = new HashMap<>();
@@ -91,29 +104,27 @@
}
@GET
- @Path("{id}")
+ @Path("droplet/{id}")
public Droplet getDroplet(@PathParam("id") int id) {
LOG.infof("getting droplet with id %s", id);
Map<String, Object> headers = new HashMap<>();
headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
headers.put(DigitalOceanHeaders.ID, id);
- Droplet droplet = producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, Droplet.class);
- return droplet;
+ return producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, Droplet.class);
}
@GET
- @Path("actions/{id}")
+ @Path("droplet/actions/{id}")
public List<Action> getActions(@PathParam("id") int id) {
- LOG.infof("getting actions's droplet with id %s", id);
+ LOG.infof("getting action's droplet with id %s", id);
Map<String, Object> headers = new HashMap<>();
headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.listActions);
headers.put(DigitalOceanHeaders.ID, id);
- List<Action> actions = producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
- return actions;
+ return producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
}
@POST
- @Path("snapshot/{id}")
+ @Path("droplet/snapshot/{id}")
public Action snapshotDroplet(@PathParam("id") int id, String snapshotName) {
LOG.infof("snapshot droplet %s with name %s", id, snapshotName);
Map<String, Object> headers = new HashMap<>();
@@ -124,53 +135,52 @@
}
@GET
- @Path("snapshots/{id}")
+ @Path("droplet/snapshots/{id}")
public List<Snapshot> getSnapshots(@PathParam("id") int id) {
LOG.infof("getting snapshot's droplet with id %s", id);
Map<String, Object> headers = new HashMap<>();
headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.listSnapshots);
headers.put(DigitalOceanHeaders.ID, id);
- List<Snapshot> snapshots = producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
- return snapshots;
+ return producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
}
@GET
- @Path("backups/enable/{id}")
+ @Path("droplet/backups/enable/{id}")
public Action enableBackups(@PathParam("id") int id) {
LOG.infof("Enable backups for droplet %s", id);
return doAction(id, DigitalOceanOperations.enableBackups);
}
@GET
- @Path("backups/disable/{id}")
+ @Path("droplet/backups/disable/{id}")
public Action disableBackups(@PathParam("id") int id) {
LOG.infof("disable backups for droplet %s", id);
return doAction(id, DigitalOceanOperations.disableBackups);
}
@GET
- @Path("on/{id}")
+ @Path("droplet/on/{id}")
public Action turnOn(@PathParam("id") int id) {
LOG.infof("Turn on droplet %s", id);
return doAction(id, DigitalOceanOperations.powerOn);
}
@GET
- @Path("off/{id}")
+ @Path("droplet/off/{id}")
public Action turnOff(@PathParam("id") int id) {
LOG.infof("Turn off droplet %s", id);
return doAction(id, DigitalOceanOperations.powerOff);
}
@GET
- @Path("reboot/{id}")
+ @Path("droplet/reboot/{id}")
public Action rebootDroplet(@PathParam("id") int id) {
LOG.infof("Reboot droplet %s", id);
return doAction(id, DigitalOceanOperations.reboot);
}
@GET
- @Path("ipv6/{id}")
+ @Path("droplet/ipv6/{id}")
public Action enableIpv6(@PathParam("id") int id) {
LOG.infof("Enable Ipv6 for droplet %s", id);
return doAction(id, DigitalOceanOperations.enableIpv6);
@@ -184,35 +194,362 @@
}
@GET
- @Path("backups/{id}")
+ @Path("droplet/backups/{id}")
public List<Backup> getBackups(@PathParam("id") int id) {
- LOG.infof("getting backups's droplet with id %s", id);
+ LOG.infof("getting backup's droplet with id %s", id);
Map<String, Object> headers = new HashMap<>();
headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.listBackups);
headers.put(DigitalOceanHeaders.ID, id);
- List<Backup> backups = producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
- return backups;
+ return producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
}
@GET
- @Path("neighbors/{id}")
+ @Path("droplet/neighbors/{id}")
public List<Droplet> getNeighbors(@PathParam("id") int id) {
- LOG.infof("getting neighbors's droplet with id %s", id);
+ LOG.infof("getting neighbor's droplet with id %s", id);
Map<String, Object> headers = new HashMap<>();
headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.listNeighbors);
headers.put(DigitalOceanHeaders.ID, id);
- List<Droplet> neighbors = producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
- return neighbors;
+ return producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
}
@GET
- @Path("neighbors")
+ @Path("droplet/neighbors")
public List<Droplet> getAllNeighbors() {
LOG.infof("getting all neighbors");
Map<String, Object> headers = new HashMap<>();
headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.listAllNeighbors);
- List<Droplet> neighbors = producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
- return neighbors;
+ return producerTemplate.requestBodyAndHeaders("direct:droplet", null, headers, List.class);
}
+ @GET
+ @Path("account")
+ public Account getAccount() {
+ LOG.infof("getting the account");
+ return producerTemplate.requestBody("direct:account", null, Account.class);
+ }
+
+ @GET
+ @Path("action/{id}")
+ public Action getAction(@PathParam("id") Integer id) {
+ LOG.infof("getting the action %s", id);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.ID, id);
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
+ return producerTemplate.requestBodyAndHeaders("direct:actions", null, headers, Action.class);
+ }
+
+ @GET
+ @Path("actions")
+ public List<Action> getActions() {
+ LOG.infof("getting all account's actions");
+ return producerTemplate.requestBodyAndHeader("direct:actions", null, DigitalOceanHeaders.OPERATION,
+ DigitalOceanOperations.list, List.class);
+ }
+
+ @GET
+ @Path("images")
+ public List<Image> getImages() {
+ LOG.infof("getting all account's images");
+ return producerTemplate.requestBodyAndHeader("direct:images", null, DigitalOceanHeaders.OPERATION,
+ DigitalOceanOperations.list, List.class);
+ }
+
+ @GET
+ @Path("images/{id}")
+ public Image getImageById(@PathParam("id") Integer id) {
+ LOG.infof("getting an image by id %s", id);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.ID, id);
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
+ return producerTemplate.requestBodyAndHeaders("direct:images", null, headers, Image.class);
+ }
+
+ @GET
+ @Path("images/user")
+ public List<Image> getUserImages() {
+ LOG.infof("getting user's images");
+ return producerTemplate.requestBodyAndHeader("direct:images", null, DigitalOceanHeaders.OPERATION,
+ DigitalOceanOperations.ownList, List.class);
+ }
+
+ @GET
+ @Path("snapshots")
+ public List<Snapshot> getSnapshots() {
+ LOG.infof("getting all account's snapshots");
+ return producerTemplate.requestBodyAndHeader("direct:snapshots", null, DigitalOceanHeaders.OPERATION,
+ DigitalOceanOperations.list, List.class);
+ }
+
+ @GET
+ @Path("snapshots/{id}")
+ public Snapshot getSnapshotById(@PathParam("id") Integer id) {
+ LOG.infof("getting an snapshot by id %s", id);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.ID, id);
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
+ return producerTemplate.requestBodyAndHeaders("direct:snapshots", null, headers, Snapshot.class);
+ }
+
+ @DELETE
+ @Path("snapshots/{id}")
+ public Response deleteSnapshot(@PathParam("id") Integer id) {
+ LOG.infof("delete snapshot %s", id);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.delete);
+ headers.put(DigitalOceanHeaders.ID, id);
+ producerTemplate.sendBodyAndHeaders("direct:snapshots", null, headers);
+ return Response.ok().build();
+ }
+
+ @GET
+ @Path("sizes")
+ public List<Size> getSizes() {
+ LOG.infof("getting all available sizes");
+ return producerTemplate.requestBody("direct:sizes", null, List.class);
+ }
+
+ @GET
+ @Path("regions")
+ public List<Region> getRegions() {
+ LOG.infof("getting all available regions");
+ return producerTemplate.requestBody("direct:regions", null, List.class);
+ }
+
+ @PUT
+ @Path("floatingIP")
+ public String createFloatingIP(Integer dropletId) {
+ LOG.infof("create floating IP for droplet %s", dropletId);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.create);
+ headers.put(DigitalOceanHeaders.DROPLET_ID, dropletId);
+ // if pending task on droplet : API returns an exception. There should be a retry later
+ try {
+ FloatingIP floatingIP = producerTemplate.requestBodyAndHeaders("direct:floatingIPs", null, headers,
+ FloatingIP.class);
+ return floatingIP.getIp();
+ } catch (Exception e) {
+ LOG.errorf("Enable to create and assign Floating IP - Please retry - error message : %s" + e.getMessage());
+ }
+ return "";
+ }
+
+ @GET
+ @Path("floatingIP/{id}")
+ public FloatingIP getFloatingIpById(@PathParam("id") String id) {
+ LOG.infof("get floating IP %s", id);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
+ headers.put(DigitalOceanHeaders.FLOATING_IP_ADDRESS, id);
+ return producerTemplate.requestBodyAndHeaders("direct:floatingIPs", null, headers, FloatingIP.class);
+ }
+
+ @GET
+ @Path("floatingIP")
+ public List<FloatingIP> getAllFloatingIps() {
+ LOG.infof("get all floating IPs");
+ return producerTemplate.requestBodyAndHeader("direct:floatingIPs", null,
+ DigitalOceanHeaders.OPERATION, DigitalOceanOperations.list, List.class);
+ }
+
+ @GET
+ @Path("floatingIP/unassign/{id}")
+ public Action unassignFloatingIp(@PathParam("id") String id) {
+ LOG.infof("unassign floating IP %s");
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.unassign);
+ headers.put(DigitalOceanHeaders.FLOATING_IP_ADDRESS, id);
+ // if pending task on droplet : API returns an exception. There should be a retry later
+ try {
+ return producerTemplate.requestBodyAndHeaders("direct:floatingIPs", null, headers, Action.class);
+ } catch (Exception e) {
+ LOG.errorf("Enable to unassign Floating IP - Please retry - error message : %s" + e.getMessage());
+ }
+ return new Action();
+ }
+
+ @DELETE
+ @Path("floatingIP/{id}")
+ public Delete deleteFloatingIp(@PathParam("id") String id) {
+ LOG.infof("delete floating IP %s", id);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.delete);
+ headers.put(DigitalOceanHeaders.FLOATING_IP_ADDRESS, id);
+ // if pending task on droplet : API returns an exception. There should be a retry later
+ try {
+ return producerTemplate.requestBodyAndHeaders("direct:floatingIPs", null, headers, Delete.class);
+ } catch (Exception e) {
+ LOG.errorf("Enable to delete Floating IP - Please retry - error message : %s" + e.getMessage());
+ }
+ return new Delete(false);
+
+ }
+
+ @GET
+ @Path("floatingIP/actions/{id}")
+ public List<Action> getFloatingIpsActions(@PathParam("id") String id) {
+ LOG.infof("get all floating IPs actions %s", id);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.listActions);
+ headers.put(DigitalOceanHeaders.FLOATING_IP_ADDRESS, id);
+ return (List<Action>) producerTemplate.requestBodyAndHeaders("direct:floatingIPs", null, headers, List.class);
+ }
+
+ @PUT
+ @Path("blockStorages")
+ public String createVolume(String name) {
+ LOG.infof("create volume for region %s with size %s named %s", REGION_FRANKFURT, VOLUME_SIZE_5_GB, name);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.create);
+ headers.put(DigitalOceanHeaders.REGION, REGION_FRANKFURT);
+ headers.put(DigitalOceanHeaders.VOLUME_SIZE_GIGABYTES, VOLUME_SIZE_5_GB);
+ headers.put(DigitalOceanHeaders.NAME, name);
+ headers.put(DigitalOceanHeaders.DESCRIPTION, "volume_" + name);
+ Volume volume = producerTemplate.requestBodyAndHeaders("direct:blockStorages", null, headers, Volume.class);
+ return volume.getId();
+ }
+
+ @GET
+ @Path("blockStorages/{id}")
+ public Volume getVolumeById(@PathParam("id") String volumeId) {
+ LOG.infof("getting volume %s", volumeId);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
+ headers.put(DigitalOceanHeaders.ID, volumeId);
+ headers.put(DigitalOceanHeaders.REGION, REGION_FRANKFURT);
+ return producerTemplate.requestBodyAndHeaders("direct:blockStorages", null, headers, Volume.class);
+ }
+
+ @POST
+ @Path("blockStorages/attach/{name}")
+ public Action attachVolumeToDroplet(@PathParam("name") String volumeName, String dropletId) {
+ LOG.infof("attach volume %s to droplet %s in region %s", volumeName, dropletId, REGION_FRANKFURT);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.attach);
+ headers.put(DigitalOceanHeaders.VOLUME_NAME, volumeName);
+ headers.put(DigitalOceanHeaders.DROPLET_ID, dropletId);
+ headers.put(DigitalOceanHeaders.REGION, REGION_FRANKFURT);
+ return producerTemplate.requestBodyAndHeaders("direct:blockStorages", null, headers, Action.class);
+ }
+
+ @POST
+ @Path("blockStorages/detach/{name}")
+ public Action detachVolumeToDroplet(@PathParam("name") String volumeName, String dropletId) {
+ LOG.infof("detach volume %s to droplet %s in region %s", volumeName, dropletId, REGION_FRANKFURT);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.detach);
+ headers.put(DigitalOceanHeaders.VOLUME_NAME, volumeName);
+ headers.put(DigitalOceanHeaders.DROPLET_ID, dropletId);
+ headers.put(DigitalOceanHeaders.REGION, REGION_FRANKFURT);
+ return producerTemplate.requestBodyAndHeaders("direct:blockStorages", null, headers, Action.class);
+ }
+
+ @GET
+ @Path("blockStorages")
+ public List<Volume> getAvailableVolumes() {
+ LOG.infof("get all avalaible volumes for region %s", REGION_FRANKFURT);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.list);
+ headers.put(DigitalOceanHeaders.REGION, REGION_FRANKFURT);
+ return producerTemplate.requestBodyAndHeaders("direct:blockStorages", null, headers, List.class);
+ }
+
+ @DELETE
+ @Path("blockStorages")
+ public Delete deleteVolume(String volumeId) {
+ LOG.infof("delete volume %s", volumeId);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.delete);
+ headers.put(DigitalOceanHeaders.ID, volumeId);
+ return producerTemplate.requestBodyAndHeaders("direct:blockStorages", null, headers, Delete.class);
+ }
+
+ @PUT
+ @Path("keys/{name}")
+ public Integer createKey(@PathParam("name") String name, String publicKey) {
+ LOG.infof("create key %s", name);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.create);
+ headers.put(DigitalOceanHeaders.NAME, name);
+ headers.put(DigitalOceanHeaders.KEY_PUBLIC_KEY, publicKey);
+ Key key = producerTemplate.requestBodyAndHeaders("direct:keys", null, headers, Key.class);
+ return key.getId();
+ }
+
+ @GET
+ @Path("keys/{id}")
+ public Key getKeyById(@PathParam("id") Integer id) {
+ LOG.infof("get key %s", id);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
+ headers.put(DigitalOceanHeaders.ID, id);
+ return producerTemplate.requestBodyAndHeaders("direct:keys", null, headers, Key.class);
+ }
+
+ @GET
+ @Path("keys")
+ public List<Key> getKeys() {
+ LOG.infof("get keys");
+ return producerTemplate.requestBodyAndHeader("direct:keys", null, DigitalOceanHeaders.OPERATION,
+ DigitalOceanOperations.list, List.class);
+ }
+
+ @POST
+ @Path("keys/{id}")
+ public Key updateKey(@PathParam("id") Integer id, String name) {
+ LOG.infof("update key %s with name %s", id, name);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.update);
+ headers.put(DigitalOceanHeaders.ID, id);
+ headers.put(DigitalOceanHeaders.NAME, name);
+ return producerTemplate.requestBodyAndHeaders("direct:keys", null, headers, Key.class);
+ }
+
+ @DELETE
+ @Path("keys/{id}")
+ public Delete deleteKey(@PathParam("id") Integer id) {
+ LOG.infof("delete key %s", id);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.delete);
+ headers.put(DigitalOceanHeaders.ID, id);
+ return producerTemplate.requestBodyAndHeaders("direct:keys", null, headers, Delete.class);
+ }
+
+ @POST
+ @Path("tags/{name}")
+ public Tag createTag(@PathParam("name") String name) {
+ LOG.infof("create tag %s", name);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.create);
+ headers.put(DigitalOceanHeaders.NAME, name);
+ return producerTemplate.requestBodyAndHeaders("direct:tags", null, headers, Tag.class);
+ }
+
+ @GET
+ @Path("tags/{name}")
+ public Tag getTag(@PathParam("name") String name) {
+ LOG.infof("get tag %s", name);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.get);
+ headers.put(DigitalOceanHeaders.NAME, name);
+ return producerTemplate.requestBodyAndHeaders("direct:tags", null, headers, Tag.class);
+ }
+
+ @GET
+ @Path("tags")
+ public List<Tag> getAllTags() {
+ LOG.infof("get tags");
+ return producerTemplate.requestBodyAndHeader("direct:tags", null, DigitalOceanHeaders.OPERATION,
+ DigitalOceanOperations.list, List.class);
+ }
+
+ @DELETE
+ @Path("tags/{name}")
+ public Delete deleteTag(@PathParam("name") String name) {
+ LOG.infof("delete tag %s", name);
+ Map<String, Object> headers = new HashMap<>();
+ headers.put(DigitalOceanHeaders.OPERATION, DigitalOceanOperations.delete);
+ headers.put(DigitalOceanHeaders.NAME, name);
+ return producerTemplate.requestBodyAndHeaders("direct:tags", null, headers, Delete.class);
+ }
}
diff --git a/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanRoute.java b/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanRoute.java
index 29b1fa3..243ad0a 100644
--- a/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanRoute.java
+++ b/integration-tests/digitalocean/src/main/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanRoute.java
@@ -53,5 +53,34 @@
from("direct:droplet")
.toF("digitalocean:droplets?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+ from("direct:account")
+ .toF("digitalocean:account?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+ from("direct:actions")
+ .toF("digitalocean:actions?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+ from("direct:images")
+ .toF("digitalocean:images?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+ from("direct:snapshots")
+ .toF("digitalocean:snapshots?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+ from("direct:sizes")
+ .toF("digitalocean:sizes?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+ from("direct:regions")
+ .toF("digitalocean:regions?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+ from("direct:floatingIPs")
+ .toF("digitalocean:floatingIPs?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+ from("direct:blockStorages")
+ .toF("digitalocean:blockStorages?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+ from("direct:keys")
+ .toF("digitalocean:keys?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
+
+ from("direct:tags")
+ .toF("digitalocean:tags?oAuthToken=%s&digitalOceanClient=#digitalOceanClient", oAuthToken);
}
}
diff --git a/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanDropletIT.java b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanDropletIT.java
new file mode 100644
index 0000000..a371fa8
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanDropletIT.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.digitalocean.it;
+
+import io.quarkus.test.junit.NativeImageTest;
+
+@NativeImageTest
+public class DigitaloceanDropletIT extends DigitaloceanDropletTest {
+}
diff --git a/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanDropletTest.java b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanDropletTest.java
new file mode 100644
index 0000000..5f00d2e
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanDropletTest.java
@@ -0,0 +1,451 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.digitalocean.it;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import org.apache.camel.quarkus.test.wiremock.MockServer;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static io.restassured.RestAssured.given;
+import static org.awaitility.Awaitility.await;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@SuppressWarnings("unchecked")
+@QuarkusTest
+@QuarkusTestResource(DigitaloceanTestResource.class)
+public class DigitaloceanDropletTest {
+ static final long timeout = 5;
+ static TimeUnit timeoutUnit = TimeUnit.SECONDS;
+ static boolean waitBlockStorageAction = false;
+
+ @MockServer
+ WireMockServer server;
+
+ @BeforeAll
+ public static void initTimeoutUnit() {
+ // add timeout if not using MockServer
+ // when using a Digitalocean Key, it takes at least 2 minutes to create a droplet or snapshot
+ String key = System.getenv("DIGITALOCEAN_AUTH_TOKEN");
+ if (key != null) {
+ timeoutUnit = TimeUnit.MINUTES;
+ waitBlockStorageAction = true;
+ }
+ }
+
+ /**
+ * Testing droplet producer and all tests of producers related to an existing droplet
+ *
+ */
+ @Test
+ void testDroplets() throws InterruptedException {
+ // insert multiple droplets
+ Integer dropletId = RestAssured.given().contentType(ContentType.JSON).put("/digitalocean/droplet/droplet1")
+ .then().extract().body().as(Integer.class);
+ assertNotNull(dropletId);
+
+ // get the droplet by dropletId1 until its status is active and ready
+ // it takes time only if using a oAuthToken from Digitalocean
+ waitActiveDroplet(dropletId);
+
+ // test actions on droplet
+ performActions(dropletId);
+
+ // test actions
+ testResultActions(dropletId);
+
+ // test neighbors
+ testNeighbors(dropletId);
+
+ // test floating IP
+ testFloatingIP(dropletId);
+
+ // test images
+ testImages();
+
+ // test snapshots
+ testSnapshots();
+
+ // test block storages
+ testBlockStorages(dropletId);
+
+ // delete the droplet with id droplet 1
+ given()
+ .when()
+ .delete("/digitalocean/droplet/" + dropletId)
+ .then()
+ .statusCode(202);
+ }
+
+ private void performActions(Integer dropletId) {
+ // action : enable backups
+ given()
+ .contentType(ContentType.JSON)
+ .get("/digitalocean/droplet/backups/enable/" + dropletId)
+ .then()
+ .body("resourceId", equalTo(dropletId))
+ .body("type", equalTo("ENABLE_BACKUPS"));
+
+ // action : power off, before taking a snapshot
+ given()
+ .contentType(ContentType.JSON)
+ .get("/digitalocean/droplet/off/" + dropletId)
+ .then()
+ .body("resourceId", equalTo(dropletId));
+
+ // take a snapshot
+ given()
+ .contentType(ContentType.JSON)
+ .body("snapshot1")
+ .post("/digitalocean/droplet/snapshot/" + dropletId)
+ .then()
+ .body("resourceId", equalTo(dropletId));
+
+ waitForSnapshot(dropletId);
+
+ // action : disable backups
+ given()
+ .when()
+ .get("/digitalocean/droplet/backups/disable/" + dropletId)
+ .then()
+ .body("resourceId", equalTo(dropletId));
+
+ // action : power on
+ given()
+ .contentType(ContentType.JSON)
+ .get("/digitalocean/droplet/on/" + dropletId)
+ .then()
+ .body("resourceId", equalTo(dropletId));
+
+ // Reboot droplet
+ given()
+ .contentType(ContentType.JSON)
+ .get("/digitalocean/droplet/reboot/" + dropletId)
+ .then()
+ .body("resourceId", equalTo(dropletId));
+
+ // enable Ipv6
+ given()
+ .contentType(ContentType.JSON)
+ .get("/digitalocean/droplet/ipv6/" + dropletId)
+ .then()
+ .body("resourceId", equalTo(dropletId));
+ }
+
+ /**
+ * Test the result of actions performed
+ *
+ */
+ private void testResultActions(Integer dropletId) {
+ // getting the droplet actions
+ List<Map<String, Object>> actions = RestAssured.given().contentType(ContentType.JSON)
+ .get("/digitalocean/droplet/actions/" + dropletId)
+ .then().extract().body().as(List.class);
+ List<String> types = Arrays.asList("ENABLE_BACKUPS", "DISABLE_BACKUPS", "SNAPSHOT", "POWER_ON", "POWER_OFF", "REBOOT",
+ "ENABLE_IPV6");
+ assertActions(actions, types);
+
+ // getting the snapshot action id
+ Integer snapshotActionId = getSnapshotActionId(actions);
+
+ // getting one action
+ given()
+ .get("/digitalocean/action/" + snapshotActionId)
+ .then()
+ .body("id", equalTo(snapshotActionId));
+
+ // getting all actions on the account
+ actions = RestAssured.given().contentType(ContentType.JSON)
+ .get("/digitalocean/actions/")
+ .then().extract().body().as(List.class);
+ types = Arrays.asList("ENABLE_BACKUPS", "DISABLE_BACKUPS", "SNAPSHOT", "POWER_ON", "POWER_OFF", "REBOOT");
+ assertActions(actions, types);
+ }
+
+ /**
+ * Gets the snapshots and waits until the snapshot is created in Digitalocean.
+ *
+ */
+ private void waitForSnapshot(Integer dropletId) {
+ await().atMost(timeout, timeoutUnit).until(() -> {
+ String path = "/digitalocean/droplet/snapshots/" + dropletId;
+ List<Map<String, Object>> result = given().when().get(path).then().extract().as(List.class);
+ // Look for the snapshot
+ Optional<Map<String, Object>> optional = result.stream()
+ .filter(s -> "snapshot1".equals(s.get("name")))
+ .findAny();
+ return optional.isPresent();
+ });
+ }
+
+ /**
+ * Gets the droplet and waits until the droplet is Active in Digitalocean.
+ *
+ */
+ private void waitActiveDroplet(Integer dropletId) {
+ await().atMost(timeout, timeoutUnit).until(() -> {
+ String path = "/digitalocean/droplet/" + dropletId;
+ Map<String, Object> droplet = given()
+ .contentType(ContentType.JSON).get(path).then().extract().as(Map.class);
+ return droplet != null && dropletId.equals(droplet.get("id")) && "ACTIVE".equals(droplet.get("status"));
+ });
+ }
+
+ /**
+ * Assert all the actions
+ *
+ */
+ private void assertActions(List<Map<String, Object>> actions, List<String> types) {
+ // verify there are actions
+ assertNotNull(actions);
+ // verify there are at least the 7 created actions in the test
+ assertTrue(actions.size() >= types.size());
+ types.forEach(type -> assertAction(actions, type));
+ }
+
+ /**
+ * assert a single action
+ *
+ */
+ private void assertAction(List<Map<String, Object>> actions, String actionType) {
+ Optional<Map<String, Object>> optional = actions.stream()
+ .filter(a -> actionType.equals(a.get("type")))
+ .findAny();
+ assertTrue(optional.isPresent());
+ }
+
+ /**
+ * Get action of type SNAPSHOT
+ *
+ */
+ private Integer getSnapshotActionId(List<Map<String, Object>> actions) {
+ return actions.stream()
+ .filter(a -> "SNAPSHOT".equals(a.get("type")))
+ .findAny()
+ .map(b -> (Integer) b.get("id"))
+ .orElse(null);
+ }
+
+ private void testNeighbors(int dropletId) {
+ given()
+ .when()
+ .get("/digitalocean/droplet/neighbors/" + dropletId)
+ .then()
+ .statusCode(200);
+ }
+
+ private void testImages() {
+ // getting all images
+ List<Map<String, Object>> images = RestAssured.given().contentType(ContentType.JSON)
+ .get("/digitalocean/images")
+ .then().extract().body().as(List.class);
+ // there's at least the image created for the backup
+ assertNotNull(images);
+
+ // get one image id
+ Integer imageId = images.stream().findAny().map(image -> (Integer) image.get("id")).orElse(null);
+ assertNotNull(imageId);
+
+ // get the image with id
+ given().contentType(ContentType.JSON)
+ .get("/digitalocean/images/" + imageId)
+ .then()
+ .body("id", equalTo(imageId));
+
+ // test user's images
+ images = RestAssured.given().contentType(ContentType.JSON)
+ .get("/digitalocean/images/user")
+ .then().extract().body().as(List.class);
+ assertNotNull(images);
+ }
+
+ private void testSnapshots() {
+ // getting all snapshots
+ List<Map<String, Object>> images = RestAssured.given().contentType(ContentType.JSON)
+ .get("/digitalocean/snapshots")
+ .then().extract().body().as(List.class);
+ // there's at least the image created for the backup
+ assertNotNull(images);
+
+ // get one snapshot id
+ Integer snapshotId = images.stream().findAny().map(snapshot -> (Integer) snapshot.get("id")).orElse(null);
+ assertNotNull(snapshotId);
+
+ // get the snapshot with id
+ given().contentType(ContentType.JSON)
+ .get("/digitalocean/snapshots/" + snapshotId)
+ .then()
+ .body("id", equalTo(snapshotId));
+
+ // delete snapshot
+ given().contentType(ContentType.JSON)
+ .delete("/digitalocean/snapshots/" + snapshotId)
+ .then()
+ .statusCode(200);
+ }
+
+ private void testFloatingIP(Integer dropletId) {
+ AtomicReference<String> floatingIp = new AtomicReference<>();
+ // create a floating IP for the droplet
+ await().atMost(timeout, timeoutUnit).until(() -> {
+ floatingIp.set(given().contentType(ContentType.JSON)
+ .body(dropletId)
+ .put("/digitalocean/floatingIP")
+ .then().extract().body().asString());
+ return !floatingIp.get().equals("");
+ });
+
+ // gets the floating IP
+ given()
+ .contentType(ContentType.JSON)
+ .get("/digitalocean/floatingIP/" + floatingIp)
+ .then()
+ .body("ip", equalTo(floatingIp.get()));
+
+ // gets all the floating IP
+ List<Map<String, Object>> floatingIps = given()
+ .contentType(ContentType.JSON)
+ .get("/digitalocean/floatingIP")
+ .then().extract().body().as(List.class);
+ Optional<Map<String, Object>> floatingIpResult = floatingIps.stream()
+ .filter(f -> floatingIp.get().equals(f.get("ip")))
+ .findAny();
+ assertTrue(floatingIpResult.isPresent());
+
+ // unassign a floating IP
+ final Map<String, Object>[] action = new Map[1];
+ await().atMost(timeout, timeoutUnit).until(() -> {
+ action[0] = given()
+ .contentType(ContentType.JSON)
+ .get("/digitalocean/floatingIP/unassign/" + floatingIp)
+ .then().extract().body().as(Map.class);
+ return action[0] != null && "UNASSIGN_FLOATING_IP".equals(action[0].get("type"));
+ });
+ Integer actionId = (Integer) action[0].get("id");
+
+ // get all action of a floating IP
+ List<Map<String, Object>> actions = given()
+ .contentType(ContentType.JSON)
+ .get("/digitalocean/floatingIP/actions/" + floatingIp)
+ .then().extract().body().as(List.class);
+ assertNotNull(actions);
+ Optional<Map<String, Object>> actionUnassign = actions.stream()
+ .filter(a -> actionId.equals(a.get("id")))
+ .findAny();
+ assertTrue(actionUnassign.isPresent());
+
+ // delete a floating ip
+ await().atMost(timeout, timeoutUnit).until(() -> {
+ Map<String, Object> delete = given()
+ .contentType(ContentType.JSON)
+ .delete("/digitalocean/floatingIP/" + floatingIp)
+ .then().extract().body().as(Map.class);
+ return delete != null && (Boolean) delete.get("isRequestSuccess");
+ });
+ }
+
+ private void testBlockStorages(Integer dropletId) throws InterruptedException {
+ // create a volume
+ String volumeId = given()
+ .contentType(ContentType.JSON)
+ .body("volume1")
+ .when()
+ .put("/digitalocean/blockStorages")
+ .then().extract().body().asString();
+ assertNotNull(volumeId);
+
+ // get the volume
+ given()
+ .get("/digitalocean/blockStorages/" + volumeId)
+ .then()
+ .body("name", equalTo("volume1"));
+
+ // get all volumes in the region FRA1
+ List<Map<String, Object>> volumes = given()
+ .get("/digitalocean/blockStorages")
+ .then()
+ .extract().body().as(List.class);
+ assertNotNull(volumes);
+ Map<String, Object> expectedResult = volumes.stream()
+ .filter(v -> "volume1".equals(v.get("name")))
+ .findAny().orElse(null);
+ assertNotNull(expectedResult);
+
+ // attach to droplet
+ given()
+ .contentType(ContentType.JSON)
+ .body(dropletId)
+ .when()
+ .post("/digitalocean/blockStorages/attach/volume1")
+ .then()
+ .body("type", equalTo("ATTACH"));
+
+ // wait until the volume is attached : or else it's impossible to detach
+ waitAttachedVolume(dropletId, volumeId);
+
+ // detach from droplet
+ given()
+ .contentType(ContentType.JSON)
+ .body(dropletId)
+ .when()
+ .post("/digitalocean/blockStorages/detach/volume1")
+ .then()
+ .statusCode(200);
+
+ // wait until detach action is performed :: only when using digitalocean
+ // if the volume is droped before being detached, there's an error in delete action, and it will be impossible to get the drop result
+ if (waitBlockStorageAction) {
+ Thread.sleep(10000);
+ }
+
+ // drop the volume
+ given()
+ .contentType(ContentType.JSON)
+ .body(volumeId)
+ .when()
+ .delete("/digitalocean/blockStorages")
+ .then()
+ .body("isRequestSuccess", equalTo(true));
+
+ }
+
+ /**
+ * Gets the droplet and waits until the volume is attached to the droplet
+ *
+ */
+ private void waitAttachedVolume(Integer dropletId, String volumeId) {
+ await().atMost(timeout, timeoutUnit).until(() -> {
+ String path = "/digitalocean/droplet/" + dropletId;
+ Map<String, Object> droplet = given()
+ .contentType(ContentType.JSON).get(path).then().extract().as(Map.class);
+ return droplet.get("volumeIds") != null && ((List<String>) droplet.get("volumeIds")).contains(volumeId);
+ });
+ }
+}
diff --git a/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTest.java b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTest.java
index c401351..0578458 100644
--- a/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTest.java
+++ b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTest.java
@@ -16,11 +16,9 @@
*/
package org.apache.camel.quarkus.component.digitalocean.it;
-import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.concurrent.TimeUnit;
import com.github.tomakehurst.wiremock.WireMockServer;
import io.quarkus.test.common.QuarkusTestResource;
@@ -28,182 +26,144 @@
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import org.apache.camel.quarkus.test.wiremock.MockServer;
+import org.hamcrest.CoreMatchers;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
-import static org.awaitility.Awaitility.await;
-import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.notNullValue;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
+@SuppressWarnings("unchecked")
@QuarkusTest
@QuarkusTestResource(DigitaloceanTestResource.class)
class DigitaloceanTest {
-
+ static String publicKey;
@MockServer
WireMockServer server;
- static long timeout = 5;
- static TimeUnit timeoutUnit = TimeUnit.SECONDS;
-
@BeforeAll
- public static void initTimeoutUnit() {
- // add timeout if not using MockServer
- // when using a Digitalocean Key, it takes at least 2 minutes to create a droplet or snapshot
- String key = System.getenv("DIGITALOCEAN_AUTH_TOKEN");
+ public static void initPublicKey() {
+ String key = System.getenv("DIGITALOCEAN_PUBLIC_KEY");
if (key != null) {
- timeoutUnit = TimeUnit.MINUTES;
+ publicKey = key;
+ } else {
+ publicKey = "ssh-rsa AEXAMPLEaC1yc2EAAAADAQABAAAAQQDDHr/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example";
}
}
@Test
- void testDroplets() {
- // insert multiple droplets
- Integer dropletId = RestAssured.given().contentType(ContentType.JSON).put("/digitalocean/droplet/droplet1")
- .then().extract().body().as(Integer.class);
- assertNotNull(dropletId);
-
- // get the droplet by dropletId1 until its status is active and ready
- // it takes time only if using a oAuthToken from Digitalocean
- waitActiveDroplet(dropletId);
-
- // action : enable backups
- given()
- .contentType(ContentType.JSON)
- .get("/digitalocean/droplet/backups/enable/" + dropletId)
- .then()
- .body("resourceId", equalTo(dropletId))
- .body("type", equalTo("ENABLE_BACKUPS"));
-
- // action : power off, before taking a snapshot
- given()
- .contentType(ContentType.JSON)
- .get("/digitalocean/droplet/off/" + dropletId)
- .then()
- .body("resourceId", equalTo(dropletId));
-
- // take a snapshot
- given()
- .contentType(ContentType.JSON)
- .body("snapshot1")
- .post("/digitalocean/droplet/snapshot/" + dropletId)
- .then()
- .body("resourceId", equalTo(dropletId));
-
- // action : disable backups
+ void testAccount() {
given()
.when()
- .get("/digitalocean/droplet/backups/disable/" + dropletId)
+ .get("/digitalocean/account/")
.then()
- .body("resourceId", equalTo(dropletId));
+ .body("uuid", notNullValue());
+ }
- // wait for Droplet to be active
- waitActiveDroplet(dropletId);
-
- // action : power on
- given()
- .contentType(ContentType.JSON)
- .get("/digitalocean/droplet/on/" + dropletId)
- .then()
- .body("resourceId", equalTo(dropletId));
-
- // Reboot droplet
- given()
- .contentType(ContentType.JSON)
- .get("/digitalocean/droplet/reboot/" + dropletId)
- .then()
- .body("resourceId", equalTo(dropletId));
-
- // enable Ipv6
- given()
- .contentType(ContentType.JSON)
- .get("/digitalocean/droplet/ipv6/" + dropletId)
- .then()
- .body("resourceId", equalTo(dropletId));
-
- // getting the droplet actions
- List<Map> actions = RestAssured.given().contentType(ContentType.JSON)
- .get("/digitalocean/droplet/actions/" + dropletId)
+ @Test
+ void testSizes() {
+ List<Map<String, Object>> sizes = RestAssured.given().contentType(ContentType.JSON)
+ .get("/digitalocean/sizes")
.then().extract().body().as(List.class);
- assertActions(actions);
+ assertNotNull(sizes);
+ Optional<Map<String, Object>> size_1Gb = sizes.stream()
+ .filter(s -> "s-1vcpu-1gb".equals(s.get("slug")))
+ .findFirst();
+ assertTrue(size_1Gb.isPresent());
+ }
- // test neigbors
- testNeighbors(dropletId);
+ @Test
+ void testRegions() {
+ List<Map<String, Object>> regions = RestAssured.given().contentType(ContentType.JSON)
+ .get("/digitalocean/regions")
+ .then().extract().body().as(List.class);
+ assertNotNull(regions);
+ Optional<Map<String, Object>> nyc1Region = regions.stream()
+ .filter(r -> "nyc1".equals(r.get("slug")))
+ .findFirst();
+ assertTrue(nyc1Region.isPresent());
+ }
- // delete the droplet with id droplet 1
+ @Test
+ void testKeys() {
+ // create a key
+ String name = "TestKey1";
+
+ Integer publicKeyId = given()
+ .contentType(ContentType.JSON)
+ .body(publicKey)
+ .put("/digitalocean/keys/" + name)
+ .then().extract().body().as(Integer.class);
+
+ // get the key
given()
- .when()
- .delete("/digitalocean/droplet/" + dropletId)
+ .contentType(ContentType.JSON)
+ .get("/digitalocean/keys/" + publicKeyId)
.then()
- .statusCode(202);
+ .body("id", equalTo(publicKeyId))
+ .body("name", equalTo(name));
- }
+ // update key
+ name = "updated_TestKey1";
+ given()
+ .contentType(ContentType.JSON)
+ .body(name)
+ .post("/digitalocean/keys/" + publicKeyId)
+ .then()
+ .body("id", equalTo(publicKeyId))
+ .body("name", equalTo(name));
- /**
- * Gets the snapshots and waits until the snapshot is created in Digitalocean.
- *
- * @param dropletId
- */
- private void waitForSnapshot(Integer dropletId) {
- await().atMost(this.timeout, this.timeoutUnit).until(() -> {
- String path = "/digitalocean/droplet/snapshots/" + dropletId;
- List<Map> result = given().when().get(path).then().extract().as(List.class);
- // Look for the snapshot
- Optional optional = result.stream()
- .filter(s -> "snapshot1".equals(s.get("name")))
- .findAny();
- return optional.isPresent();
- });
- }
-
- /**
- * Gets the droplet and waits until the droplet is Active in Digitalocean.
- *
- * @param dropletId
- */
- private void waitActiveDroplet(Integer dropletId) {
- await().atMost(this.timeout, this.timeoutUnit).until(() -> {
- String path = "/digitalocean/droplet/" + dropletId;
- Map droplet = given()
- .contentType(ContentType.JSON).get(path).then().extract().as(Map.class);
- return droplet != null && dropletId.equals(droplet.get("id")) && "ACTIVE".equals(droplet.get("status"));
- });
- }
-
- /**
- * Assert all the actions
- *
- * @param actions
- */
- private void assertActions(List<Map> actions) {
- // verify there are actions
- assertNotNull(actions);
- // verify there are at least the 7 created actions in the test
- assertTrue(actions.size() >= 7);
- List<String> types = Arrays.asList("ENABLE_BACKUPS", "DISABLE_BACKUPS", "SNAPSHOT", "POWER_ON", "POWER_OFF", "REBOOT",
- "ENABLE_IPV6");
- types.forEach(type -> assertAction(actions, type));
- }
-
- /**
- * assert a single action
- *
- * @param actions
- * @param actionType
- */
- private void assertAction(List<Map> actions, String actionType) {
- Optional<Map> optional = actions.stream()
- .filter(a -> actionType.equals(a.get("type")))
+ // List keys
+ List<Map<String, Object>> keys = given()
+ .get("/digitalocean/keys")
+ .then().extract().body().as(List.class);
+ Optional<Map<String, Object>> resultKey = keys.stream()
+ .filter(m -> publicKeyId.equals(m.get("id")))
.findAny();
- assertTrue(optional.isPresent());
+ assertTrue(resultKey.isPresent());
+
+ // delete the key
+ given()
+ .delete("/digitalocean/keys/" + publicKeyId)
+ .then()
+ .body("isRequestSuccess", CoreMatchers.equalTo(true));
+
}
- void testNeighbors(int dropletId) {
+ @Test
+ void testTags() {
+ // create a tag
+ String name = "awesome";
given()
- .when()
- .get("/digitalocean/droplet/neighbors/" + dropletId)
+ .contentType(ContentType.JSON)
+ .post("/digitalocean/tags/" + name)
.then()
- .statusCode(200);
+ .body("name", equalTo(name));
+
+ // get a tag
+ given()
+ .get("/digitalocean/tags/" + name)
+ .then()
+ .body("name", equalTo(name));
+
+ // get all tags
+ List<Map<String, Object>> tags = given()
+ .contentType(ContentType.JSON)
+ .get("/digitalocean/tags/")
+ .then().extract().body().as(List.class);
+ Optional<Map<String, Object>> resultKey = tags.stream()
+ .filter(t -> name.equals(t.get("name")))
+ .findAny();
+ assertTrue(resultKey.isPresent());
+
+ // delete the tag
+ given()
+ .delete("/digitalocean/tags/" + name)
+ .then()
+ .body("isRequestSuccess", CoreMatchers.equalTo(true));
+
}
}
diff --git a/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTestResource.java b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTestResource.java
index 1d08000..7e31a36 100644
--- a/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTestResource.java
+++ b/integration-tests/digitalocean/src/test/java/org/apache/camel/quarkus/component/digitalocean/it/DigitaloceanTestResource.java
@@ -22,6 +22,7 @@
public class DigitaloceanTestResource extends WireMockTestResourceLifecycleManager {
private static final String DIGITALOCEAN_BASE_URL = "api.digitalocean.com";
private static final String DIGITALOCEAN_AUTH_TOKEN = "DIGITALOCEAN_AUTH_TOKEN";
+ private static final String DIGITALOCEAN_PUBLIC_KEY = "DIGITALOCEAN_PUBLIC_KEY";
@Override
protected String getRecordTargetBaseUrl() {
@@ -30,7 +31,7 @@
@Override
protected boolean isMockingEnabled() {
- return !envVarsPresent(DIGITALOCEAN_AUTH_TOKEN);
+ return !envVarsPresent(DIGITALOCEAN_AUTH_TOKEN, DIGITALOCEAN_PUBLIC_KEY);
}
@Override
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/account.json b/integration-tests/digitalocean/src/test/resources/mappings/account.json
new file mode 100644
index 0000000..0c083a5
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/account.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/account?per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"account\":{\"droplet_limit\":25,\"floating_ip_limit\":5,\"volume_limit\":10,\"email\":\"sammy@digitalocean.com\",\"uuid\":\"b6fr89dbf6d9156cace5f3c78dc9851d957381ef\",\"email_verified\":true,\"status\":\"active\",\"status_message\":\"\"}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/action.json b/integration-tests/digitalocean/src/test/resources/mappings/action.json
new file mode 100644
index 0000000..d83f90b
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/action.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/actions/36805187?per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"action\":{\"id\":36805187,\"status\":\"completed\",\"type\":\"create\",\"started_at\":\"2014-11-14T16:29:21Z\",\"completed_at\":\"2014-11-14T16:30:06Z\",\"resource_id\":3164444,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/actionFloatingIp.json b/integration-tests/digitalocean/src/test/resources/mappings/actionFloatingIp.json
new file mode 100644
index 0000000..46372d5
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/actionFloatingIp.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6eb",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/floating_ips/45.55.96.47/actions",
+ "method": "POST"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"action\":{\"id\":68212773,\"status\":\"in-progress\",\"type\":\"unassign_ip\",\"started_at\":\"2015-10-15T17:46:15Z\",\"completed_at\":null,\"resource_id\":758603823,\"resource_type\":\"floating_ip\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"region_slug\":\"nyc3\"}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6eb",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/actions.json b/integration-tests/digitalocean/src/test/resources/mappings/actions.json
new file mode 100644
index 0000000..7bd5c9b
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/actions.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/actions?page=1&per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"actions\":[{\"id\":36805187,\"status\":\"completed\",\"type\":\"snapshot\",\"started_at\":\"2014-11-14T16:37:34Z\",\"completed_at\":\"2014-11-14T16:39:32Z\",\"resource_id\":3164494,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"},{\"id\":36805188,\"status\":\"completed\",\"type\":\"disable_backups\",\"started_at\":\"2014-11-14T16:37:34Z\",\"completed_at\":\"2014-11-14T16:39:32Z\",\"resource_id\":3164494,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"},{\"id\":36805189,\"status\":\"completed\",\"type\":\"enable_backups\",\"started_at\":\"2014-11-14T16:37:34Z\",\"completed_at\":\"2014-11-14T16:39:32Z\",\"resource_id\":3164494,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"},{\"id\":36805190,\"status\":\"completed\",\"type\":\"power_off\",\"started_at\":\"2014-11-14T16:37:34Z\",\"completed_at\":\"2014-11-14T16:39:32Z\",\"resource_id\":3164494,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"},{\"id\":36805191,\"status\":\"completed\",\"type\":\"power_on\",\"started_at\":\"2014-11-14T16:37:34Z\",\"completed_at\":\"2014-11-14T16:39:32Z\",\"resource_id\":3164494,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"},{\"id\":36805192,\"status\":\"completed\",\"type\":\"reboot\",\"started_at\":\"2014-11-14T16:37:34Z\",\"completed_at\":\"2014-11-14T16:39:32Z\",\"resource_id\":3164494,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"},{\"id\":36805193,\"status\":\"completed\",\"type\":\"enable_ipv6\",\"started_at\":\"2014-11-14T16:37:34Z\",\"completed_at\":\"2014-11-14T16:39:32Z\",\"resource_id\":3164494,\"resource_type\":\"droplet\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-3gb\",\"m-1vcpu-8gb\",\"s-3vcpu-1gb\",\"s-1vcpu-2gb\",\"s-2vcpu-2gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-1vcpu-1gb\",\"c-1vcpu-2gb\",\"s-24vcpu-128gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\",\"server_id\",\"install_agent\",\"storage\",\"image_transfer\"],\"available\":true},\"region_slug\":\"nyc3\"}],\"links\":{\"pages\":{\"last\":\"https:\/\/api.digitalocean.com\/v2\/droplets\/3164494\/actions?page=3&per_page=1\",\"next\":\"https:\/\/api.digitalocean.com\/v2\/droplets\/3164494\/actions?page=2&per_page=1\"}},\"meta\":{\"total\":7}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/actionsBlockStorage.json b/integration-tests/digitalocean/src/test/resources/mappings/actionsBlockStorage.json
new file mode 100644
index 0000000..8ced42b
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/actionsBlockStorage.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/volumes/actions",
+ "method": "POST"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"action\":{\"id\":72531856,\"status\":\"completed\",\"type\":\"attach_volume\",\"started_at\":\"2015-11-12T17:51:03Z\",\"completed_at\":\"2015-11-12T17:51:14Z\",\"resource_id\":null,\"resource_type\":\"volume\",\"region\":{\"name\":\"Frankfurt 1\",\"slug\":\"fra1\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"region_slug\":\"fra1\"}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/createBlockStorage.json b/integration-tests/digitalocean/src/test/resources/mappings/createBlockStorage.json
new file mode 100644
index 0000000..c68ba89
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/createBlockStorage.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6eb",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/volumes",
+ "method": "POST"
+ },
+ "response": {
+ "status": 200,
+ "body" : "{\"volume\":{\"id\":\"506f78a4-e098-11e5-ad9f-000f53306ae1\",\"region\":{\"name\":\"New York 1\",\"slug\":\"nyc1\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"droplet_ids\":[],\"name\":\"example\",\"description\":\"Block store for examples\",\"size_gigabytes\":10,\"filesystem_type\":\"ext4\",\"filesystem_label\":\"example\",\"created_at\":\"2016-03-02T17:00:49Z\"}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6eb",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/createFloatingIp.json b/integration-tests/digitalocean/src/test/resources/mappings/createFloatingIp.json
new file mode 100644
index 0000000..83a4a0f
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/createFloatingIp.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6eb",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/floating_ips",
+ "method": "POST"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"floating_ip\":{\"ip\":\"45.55.96.47\",\"droplet\":null,\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"locked\":false},\"links\":{}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6eb",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/createKey.json b/integration-tests/digitalocean/src/test/resources/mappings/createKey.json
new file mode 100644
index 0000000..3afb625
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/createKey.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6eb",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/account/keys",
+ "method": "POST"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"ssh_key\":{\"id\":512190,\"fingerprint\":\"3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa\",\"public_key\":\"ssh-rsa AEXAMPLEaC1yc2EAAAADAQABAAAAQQDDHr\/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example\",\"name\":\"TestKey1\"}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6eb",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/createTag.json b/integration-tests/digitalocean/src/test/resources/mappings/createTag.json
new file mode 100644
index 0000000..663fdb0
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/createTag.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6eb",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/tags",
+ "method": "POST"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"tag\":{\"name\":\"awesome\",\"resources\":{\"count\":0,\"droplets\":{\"count\":0},\"images\":{\"count\":0},\"volumes\":{\"count\":0},\"volume_snapshots\":{\"count\":0},\"databases\":{\"count\":0}}}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6eb",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/deleteBlockStorage.json b/integration-tests/digitalocean/src/test/resources/mappings/deleteBlockStorage.json
new file mode 100644
index 0000000..e1db36d
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/deleteBlockStorage.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ea",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/volumes/506f78a4-e098-11e5-ad9f-000f53306ae1",
+ "method": "DELETE"
+ },
+ "response": {
+ "status": 204,
+ "body" : "{\"delete\": {\"request_status\": true, \"status_code\": 204}, \"rate_limit\": { \"limit\": 5000, \"remaining\": 4998, \"reset\": \"2021-03-23T12:13:10+01\"}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ea",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/deleteFloatingIp.json b/integration-tests/digitalocean/src/test/resources/mappings/deleteFloatingIp.json
new file mode 100644
index 0000000..36fb6f4
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/deleteFloatingIp.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ea",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/floating_ips/45.55.96.47",
+ "method": "DELETE"
+ },
+ "response": {
+ "status": 204,
+ "body" : "{\"delete\": {\"request_status\": true, \"status_code\": 204}, \"rate_limit\": { \"limit\": 5000, \"remaining\": 4998, \"reset\": \"2021-03-23T12:13:10+01\"}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ea",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/deleteKey.json b/integration-tests/digitalocean/src/test/resources/mappings/deleteKey.json
new file mode 100644
index 0000000..d9b330a
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/deleteKey.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ea",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/account/keys/512190",
+ "method": "DELETE"
+ },
+ "response": {
+ "status": 204,
+ "body" : "{\"delete\": {\"request_status\": true, \"status_code\": 204}, \"rate_limit\": { \"limit\": 5000, \"remaining\": 4998, \"reset\": \"2021-03-23T12:13:10+01\"}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ea",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/deleteSnapshot.json b/integration-tests/digitalocean/src/test/resources/mappings/deleteSnapshot.json
new file mode 100644
index 0000000..fb61437
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/deleteSnapshot.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ea",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/snapshots/6372321",
+ "method": "DELETE"
+ },
+ "response": {
+ "status": 204,
+ "body" : "{\"delete\": {\"request_status\": true, \"status_code\": 204}, \"rate_limit\": { \"limit\": 5000, \"remaining\": 4998, \"reset\": \"2021-03-23T12:13:10+01\"}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ea",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/deleteTag.json b/integration-tests/digitalocean/src/test/resources/mappings/deleteTag.json
new file mode 100644
index 0000000..83a8c0a
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/deleteTag.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ea",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/tags/awesome",
+ "method": "DELETE"
+ },
+ "response": {
+ "status": 204,
+ "body" : "{\"delete\": {\"request_status\": true, \"status_code\": 204}, \"rate_limit\": { \"limit\": 5000, \"remaining\": 4998, \"reset\": \"2021-03-23T12:13:10+01\"}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ea",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getAllActionsFloatingIp.json b/integration-tests/digitalocean/src/test/resources/mappings/getAllActionsFloatingIp.json
new file mode 100644
index 0000000..0649fc6
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getAllActionsFloatingIp.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/floating_ips/45.55.96.47/actions?page=1&per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"actions\":[{\"id\":68212773,\"status\":\"in-progress\",\"type\":\"unassign_ip\",\"started_at\":\"2015-10-15T17:46:15Z\",\"completed_at\":null,\"resource_id\":758603823,\"resource_type\":\"floating_ip\",\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"region_slug\":\"nyc3\"}],\"links\":{},\"meta\":{\"total\":1}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getAllBlockstorages.json b/integration-tests/digitalocean/src/test/resources/mappings/getAllBlockstorages.json
new file mode 100644
index 0000000..f16052e
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getAllBlockstorages.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/volumes?per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"volumes\":[{\"id\":\"506f78a4-e098-11e5-ad9f-000f53306ae1\",\"region\":{\"name\":\"Frankfurt 1\",\"slug\":\"fra1\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"droplet_ids\":[],\"name\":\"volume1\",\"description\":\"Block store for examples\",\"size_gigabytes\":10,\"created_at\":\"2016-03-02T17:00:49Z\",\"filesystem_type\":\"ext4\",\"filesystem_label\":\"example\",\"tags\":[\"aninterestingtag\"]}],\"links\":{},\"meta\":{\"total\":1}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getAllFloatingIps.json b/integration-tests/digitalocean/src/test/resources/mappings/getAllFloatingIps.json
new file mode 100644
index 0000000..d9a264b
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getAllFloatingIps.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/floating_ips?page=1&per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"floating_ips\":[{\"ip\":\"45.55.96.47\",\"droplet\":null,\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"locked\":false}],\"links\":{},\"meta\":{\"total\":1}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getAllKeys.json b/integration-tests/digitalocean/src/test/resources/mappings/getAllKeys.json
new file mode 100644
index 0000000..ab6b0e4
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getAllKeys.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/account/keys?page=1&per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"ssh_keys\":[{\"id\":512190,\"fingerprint\":\"3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa\",\"public_key\":\"ssh-rsa AEXAMPLEaC1yc2EAAAADAQABAAAAQQDDHr\/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example\",\"name\":\"updated_TestKey1\"}],\"links\":{},\"meta\":{\"total\":1}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getAllTags.json b/integration-tests/digitalocean/src/test/resources/mappings/getAllTags.json
new file mode 100644
index 0000000..5a83fdc
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getAllTags.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/tags?page=1&per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"tags\":[{\"name\":\"awesome\",\"resources\":{\"count\":5,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/images\/7555620\",\"droplets\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/droplets\/3164444\"},\"images\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/images\/7555620\"},\"volumes\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/volumes\/3d80cb72-342b-4aaa-b92e-4e4abb24a933\"},\"volume_snapshots\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/snapshots\/1f6f46e8-6b60-11e9-be4e-0a58ac144519\"},\"databases\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/databases\/b92438f6-ba03-416c-b642-e9236db91976\"}}}]}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getBlockStorage.json b/integration-tests/digitalocean/src/test/resources/mappings/getBlockStorage.json
new file mode 100644
index 0000000..72bac69
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getBlockStorage.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/volumes/506f78a4-e098-11e5-ad9f-000f53306ae1?per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"volume\":{\"id\":\"506f78a4-e098-11e5-ad9f-000f53306ae1\",\"region\":{\"name\":\"Frankfurt 1\",\"slug\":\"fra1\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"droplet_ids\":[],\"name\":\"volume1\",\"description\":\"Block store for examples\",\"size_gigabytes\":10,\"created_at\":\"2016-03-02T17:00:49Z\",\"filesystem_type\":\"ext4\",\"filesystem_label\":\"example\",\"tags\":[\"aninterestingtag\"]}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getDroplet.json b/integration-tests/digitalocean/src/test/resources/mappings/getDroplet.json
index 37e4745..ccc4691 100644
--- a/integration-tests/digitalocean/src/test/resources/mappings/getDroplet.json
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getDroplet.json
@@ -7,7 +7,7 @@
},
"response": {
"status": 200,
- "body": "{\n \"droplet\": {\n \"id\": 3164494,\n \"name\": \"example.com\",\n \"memory\": 1024,\n \"vcpus\": 1,\n \"disk\": 25,\n \"locked\": true,\n \"status\": \"active\",\n \"kernel\": {\n \"id\": 2233,\n \"name\": \"Ubuntu 14.04 x64 vmlinuz-3.13.0-37-generic\",\n \"version\": \"3.13.0-37-generic\"\n },\n \"created_at\": \"2014-11-14T16:36:31Z\",\n \"features\": [\n \"virtio\"\n ],\n \"backup_ids\": [\n \n ],\n \"snapshot_ids\": [\n \n ],\n \"image\": {\n },\n \"volume_ids\": [\n \n ],\n \"size\": {\n },\n \"size_slug\": \"s-1vcpu-1gb\",\n \"networks\": {\n },\n \"region\": {\n },\n \"tags\": [\n \"web\"\n ]\n },\n \"links\": {\n \"actions\": [\n {\n \"id\": 36805096,\n \"rel\": \"create\",\n \"href\": \"https://api.digitalocean.com/v2/actions/36805096\"\n }\n ]\n}\n }",
+ "body": "{\n \"droplet\": {\n \"id\": 3164494,\n \"name\": \"example.com\",\n \"memory\": 1024,\n \"vcpus\": 1,\n \"disk\": 25,\n \"locked\": true,\n \"status\": \"active\",\n \"kernel\": {\n \"id\": 2233,\n \"name\": \"Ubuntu 14.04 x64 vmlinuz-3.13.0-37-generic\",\n \"version\": \"3.13.0-37-generic\"\n },\n \"created_at\": \"2014-11-14T16:36:31Z\",\n \"features\": [\n \"virtio\"\n ],\n \"backup_ids\": [\n \n ],\n \"snapshot_ids\": [\n \n ],\n \"image\": {\n },\n \"volume_ids\": [\n \"506f78a4-e098-11e5-ad9f-000f53306ae1\" \n ],\n \"size\": {\n },\n \"size_slug\": \"s-1vcpu-1gb\",\n \"networks\": {\n },\n \"region\": {\n },\n \"tags\": [\n \"web\"\n ]\n },\n \"links\": {\n \"actions\": [\n {\n \"id\": 36805096,\n \"rel\": \"create\",\n \"href\": \"https://api.digitalocean.com/v2/actions/36805096\"\n }\n ]\n}\n }",
"headers": {
"Content-Type": "application/json; charset=UTF-8",
"Date": "Tue, 03 Nov 2020 09:39:11 GMT",
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getFloatingIp.json b/integration-tests/digitalocean/src/test/resources/mappings/getFloatingIp.json
new file mode 100644
index 0000000..fc3f1b5
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getFloatingIp.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/floating_ips/45.55.96.47?per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"floating_ip\":{\"ip\":\"45.55.96.47\",\"droplet\":null,\"region\":{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},\"locked\":false}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getKey.json b/integration-tests/digitalocean/src/test/resources/mappings/getKey.json
new file mode 100644
index 0000000..af913c6
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getKey.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/account/keys/512190?per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"ssh_key\":{\"id\":512190,\"fingerprint\":\"3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa\",\"public_key\":\"ssh-rsa AEXAMPLEaC1yc2EAAAADAQABAAAAQQDDHr\/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example\",\"name\":\"TestKey1\"}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/getTag.json b/integration-tests/digitalocean/src/test/resources/mappings/getTag.json
new file mode 100644
index 0000000..3beb657
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/getTag.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/tags/awesome?per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"tag\":{\"name\":\"awesome\",\"resources\":{\"count\":5,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/images\/7555620\",\"droplets\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/droplets\/3164444\"},\"images\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/images\/7555620\"},\"volumes\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/volumes\/3d80cb72-342b-4aaa-b92e-4e4abb24a933\"},\"volume_snapshots\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/snapshots\/1f6f46e8-6b60-11e9-be4e-0a58ac144519\"},\"databases\":{\"count\":1,\"last_tagged_uri\":\"https:\/\/api.digitalocean.com\/v2\/databases\/b92438f6-ba03-416c-b642-e9236db91976\"}}}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ec",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/imageById.json b/integration-tests/digitalocean/src/test/resources/mappings/imageById.json
new file mode 100644
index 0000000..ba610c7
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/imageById.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/images/7555620?per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"image\":{\"id\":7555620,\"name\":\"Nifty New Snapshot\",\"distribution\":\"Ubuntu\",\"slug\":null,\"public\":false,\"regions\":[\"nyc2\",\"nyc2\"],\"created_at\":\"2014-11-04T22:23:02Z\",\"min_disk_size\":20,\"size_gigabytes\":2.34,\"description\":\"\",\"tags\":[],\"status\":\"available\",\"error_message\":\"\"}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/images.json b/integration-tests/digitalocean/src/test/resources/mappings/images.json
new file mode 100644
index 0000000..62f99ca
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/images.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/images?page=1&per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body" : "{\"images\":[{\"id\":7555620,\"name\":\"Nifty New Snapshot\",\"distribution\":\"Ubuntu\",\"slug\":null,\"public\":false,\"regions\":[\"nyc2\",\"nyc2\"],\"created_at\":\"2014-11-04T22:23:02Z\",\"type\":\"snapshot\",\"min_disk_size\":20,\"size_gigabytes\":2.34,\"description\":\"\",\"tags\":[],\"status\":\"available\",\"error_message\":\"\"}],\"links\":{\"pages\":{\"last\":\"https:\/\/api.digitalocean.com\/v2\/images?page=56&per_page=1\",\"next\":\"https:\/\/api.digitalocean.com\/v2\/images?page=2&per_page=1\"}},\"meta\":{\"total\":56}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/images_private.json b/integration-tests/digitalocean/src/test/resources/mappings/images_private.json
new file mode 100644
index 0000000..f559e27
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/images_private.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/images?page=1&per_page=25&private=true",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body" : "{\"images\":[{\"id\":7555620,\"name\":\"Nifty New Snapshot\",\"distribution\":\"Ubuntu\",\"slug\":null,\"public\":false,\"regions\":[\"nyc2\",\"nyc2\"],\"created_at\":\"2014-11-04T22:23:02Z\",\"type\":\"snapshot\",\"min_disk_size\":20,\"size_gigabytes\":2.34,\"description\":\"\",\"tags\":[],\"status\":\"available\",\"error_message\":\"\"}],\"links\":{\"pages\":{\"last\":\"https:\/\/api.digitalocean.com\/v2\/images?page=56&per_page=1\",\"next\":\"https:\/\/api.digitalocean.com\/v2\/images?page=2&per_page=1\"}},\"meta\":{\"total\":56}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/regions.json b/integration-tests/digitalocean/src/test/resources/mappings/regions.json
new file mode 100644
index 0000000..6c2a435
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/regions.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/regions?page=1&per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"regions\":[{\"name\":\"New York 1\",\"slug\":\"nyc1\",\"sizes\":[],\"features\":[\"virtio\",\"backups\"],\"available\":false},{\"name\":\"Amsterdam 1\",\"slug\":\"ams1\",\"sizes\":[],\"features\":[\"virtio\",\"backups\"],\"available\":false},{\"name\":\"San Francisco 1\",\"slug\":\"sfo1\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"virtio\",\"backups\",\"metadata\"],\"available\":true},{\"name\":\"New York 2\",\"slug\":\"nyc2\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"virtio\",\"private_networking\",\"backups\"],\"available\":true},{\"name\":\"Amsterdam 2\",\"slug\":\"ams2\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"virtio\",\"private_networking\",\"backups\",\"metadata\"],\"available\":true},{\"name\":\"Singapore 1\",\"slug\":\"sgp1\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"virtio\",\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},{\"name\":\"London 1\",\"slug\":\"lon1\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"virtio\",\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},{\"name\":\"New York 3\",\"slug\":\"nyc3\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"virtio\",\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true},{\"name\":\"Amsterdam 3\",\"slug\":\"ams3\",\"sizes\":[\"s-1vcpu-1gb\",\"s-1vcpu-2gb\",\"s-1vcpu-3gb\",\"s-2vcpu-2gb\",\"s-3vcpu-1gb\",\"s-2vcpu-4gb\",\"s-4vcpu-8gb\",\"s-6vcpu-16gb\",\"s-8vcpu-32gb\",\"s-12vcpu-48gb\",\"s-16vcpu-64gb\",\"s-20vcpu-96gb\",\"s-24vcpu-128gb\",\"s-32vcpu-192gb\"],\"features\":[\"virtio\",\"private_networking\",\"backups\",\"ipv6\",\"metadata\"],\"available\":true}],\"links\":{},\"meta\":{\"total\":9}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/sizes.json b/integration-tests/digitalocean/src/test/resources/mappings/sizes.json
new file mode 100644
index 0000000..981a97a
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/sizes.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/sizes?page=1&per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"sizes\":[{\"slug\":\"s-1vcpu-1gb\",\"memory\":1024,\"vcpus\":1,\"disk\":25,\"transfer\":1,\"price_monthly\":5,\"price_hourly\":0.00744,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-3vcpu-1gb\",\"memory\":1024,\"vcpus\":3,\"disk\":60,\"transfer\":3,\"price_monthly\":15,\"price_hourly\":0.02232,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-1vcpu-2gb\",\"memory\":2048,\"vcpus\":1,\"disk\":50,\"transfer\":2,\"price_monthly\":10,\"price_hourly\":0.01488,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-2vcpu-2gb\",\"memory\":2048,\"vcpus\":2,\"disk\":60,\"transfer\":3,\"price_monthly\":15,\"price_hourly\":0.02232,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-1vcpu-3gb\",\"memory\":3072,\"vcpus\":1,\"disk\":20,\"transfer\":3,\"price_monthly\":15,\"price_hourly\":0.02232,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"c-2\",\"memory\":4096,\"vcpus\":2,\"disk\":25,\"transfer\":5,\"price_monthly\":40,\"price_hourly\":0.06,\"regions\":[\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc3\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-2vcpu-4gb\",\"memory\":4096,\"vcpus\":2,\"disk\":80,\"transfer\":4,\"price_monthly\":20,\"price_hourly\":0.02976,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-4vcpu-8gb\",\"memory\":8192,\"vcpus\":4,\"disk\":160,\"transfer\":5,\"price_monthly\":40,\"price_hourly\":0.05952,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"c-4\",\"memory\":8192,\"vcpus\":4,\"disk\":50,\"transfer\":5,\"price_monthly\":80,\"price_hourly\":0.119,\"regions\":[\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc3\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"c-8\",\"memory\":16384,\"vcpus\":8,\"disk\":100,\"transfer\":5,\"price_monthly\":160,\"price_hourly\":0.238,\"regions\":[\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc3\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-6vcpu-16gb\",\"memory\":16384,\"vcpus\":6,\"disk\":320,\"transfer\":6,\"price_monthly\":80,\"price_hourly\":0.11905,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-8vcpu-32gb\",\"memory\":32768,\"vcpus\":8,\"disk\":640,\"transfer\":7,\"price_monthly\":160,\"price_hourly\":0.2381,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"c-16\",\"memory\":32768,\"vcpus\":16,\"disk\":200,\"transfer\":5,\"price_monthly\":320,\"price_hourly\":0.476,\"regions\":[\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc3\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-12vcpu-48gb\",\"memory\":49152,\"vcpus\":12,\"disk\":960,\"transfer\":8,\"price_monthly\":240,\"price_hourly\":0.35714,\"regions\":[\"ams2\",\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo1\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-16vcpu-64gb\",\"memory\":65536,\"vcpus\":16,\"disk\":1280,\"transfer\":9,\"price_monthly\":320,\"price_hourly\":0.47619,\"regions\":[\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"c-32\",\"memory\":65536,\"vcpus\":32,\"disk\":400,\"transfer\":5,\"price_monthly\":640,\"price_hourly\":0.952,\"regions\":[\"fra1\"],\"available\":true},{\"slug\":\"c-48\",\"memory\":73728,\"vcpus\":48,\"disk\":20,\"transfer\":5,\"price_monthly\":960,\"price_hourly\":1.429,\"regions\":[],\"available\":true},{\"slug\":\"s-20vcpu-96gb\",\"memory\":98304,\"vcpus\":20,\"disk\":1920,\"transfer\":10,\"price_monthly\":480,\"price_hourly\":0.71429,\"regions\":[\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-24vcpu-128gb\",\"memory\":131072,\"vcpus\":24,\"disk\":2560,\"transfer\":11,\"price_monthly\":640,\"price_hourly\":0.95238,\"regions\":[\"ams3\",\"blr1\",\"fra1\",\"lon1\",\"nyc1\",\"nyc2\",\"nyc3\",\"sfo2\",\"sgp1\",\"tor1\"],\"available\":true},{\"slug\":\"s-32vcpu-192gb\",\"memory\":196608,\"vcpus\":24,\"disk\":3840,\"transfer\":12,\"price_monthly\":960,\"price_hourly\":1.42857,\"regions\":[],\"available\":true}],\"links\":{},\"meta\":{\"total\":20}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/snapshotById.json b/integration-tests/digitalocean/src/test/resources/mappings/snapshotById.json
new file mode 100644
index 0000000..0acf1a6
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/snapshotById.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/snapshots/6372321?per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"snapshot\":{\"id\":\"6372321\",\"name\":\"big-data-snapshot1475170902\",\"regions\":[\"nyc1\"],\"created_at\":\"2016-09-29T17:41:42Z\",\"resource_id\":\"fbcbc5c8-866b-11e6-96bf-000f53315a41\",\"resource_type\":\"volume\",\"min_disk_size\":10,\"size_gigabytes\":0,\"tags\":[\"aninterestingtag\"]}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/snapshots.json b/integration-tests/digitalocean/src/test/resources/mappings/snapshots.json
new file mode 100644
index 0000000..1e71ef1
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/snapshots.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/snapshots?page=1&per_page=25",
+ "method": "GET"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"snapshots\":[{\"id\":6372321,\"name\":\"5.10 x64\",\"regions\":[\"nyc1\",\"ams1\",\"sfo1\",\"nyc2\",\"ams2\",\"sgp1\",\"lon1\",\"nyc3\",\"ams3\",\"fra1\",\"tor1\"],\"created_at\":\"2014-09-26T16:40:18Z\",\"resource_id\":2713828,\"resource_type\":\"droplet\",\"min_disk_size\":20,\"size_gigabytes\":1.42,\"tags\":[]}],\"links\":{\"pages\":{\"last\":\"https:\/\/api.digitalocean.com\/v2\/snapshots?page=110&per_page=1\",\"next\":\"https:\/\/api.digitalocean.com\/v2\/snapshots?page=2&per_page=1\"}},\"meta\":{\"total\":110}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6ed",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/integration-tests/digitalocean/src/test/resources/mappings/updateKey.json b/integration-tests/digitalocean/src/test/resources/mappings/updateKey.json
new file mode 100644
index 0000000..a884264
--- /dev/null
+++ b/integration-tests/digitalocean/src/test/resources/mappings/updateKey.json
@@ -0,0 +1,28 @@
+{
+ "id": "09aa79df-8a19-41df-8655-e414d390d6eb",
+ "name": "digitalocean_api_json",
+ "request": {
+ "url": "/v2/account/keys/512190",
+ "method": "PUT"
+ },
+ "response": {
+ "status": 200,
+ "body": "{\"ssh_key\":{\"id\":512190,\"fingerprint\":\"3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa\",\"public_key\":\"ssh-rsa AEXAMPLEaC1yc2EAAAADAQABAAAAQQDDHr\/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example\",\"name\":\"updated_TestKey1\"}}",
+ "headers": {
+ "Content-Type": "application/json; charset=UTF-8",
+ "Date": "Tue, 03 Nov 2020 09:39:11 GMT",
+ "Pragma": "no-cache",
+ "Expires": "Fri, 01 Jan 1990 00:00:00 GMT",
+ "Cache-Control": "no-cache, must-revalidate",
+ "Vary": "Accept-Language",
+ "Server": "mafe",
+ "X-XSS-Protection": "0",
+ "X-Frame-Options": "SAMEORIGIN",
+ "Server-Timing": "gfet4t7; dur=263",
+ "Alt-Svc": "h3-Q050=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-T050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""
+ }
+ },
+ "uuid": "09aa79df-8a19-41df-8655-e414d390d6eb",
+ "persistent": true,
+ "insertionIndex": 2
+}
\ No newline at end of file