You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by an...@apache.org on 2018/07/10 11:30:37 UTC

jclouds-labs git commit: –JCLOUDS-1425 1&1 Block Storage and SSH keys API

Repository: jclouds-labs
Updated Branches:
  refs/heads/master f38f80453 -> 4a9536b8c


–JCLOUDS-1425 1&1 Block Storage and SSH keys API


Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs/commit/4a9536b8
Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs/tree/4a9536b8
Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs/diff/4a9536b8

Branch: refs/heads/master
Commit: 4a9536b8c8ca28e56471ea1e1b108f1766fa260b
Parents: f38f804
Author: Ali Bazlamit <al...@hotmail.com>
Authored: Tue Jul 10 13:02:58 2018 +0200
Committer: andreaturli <an...@gmail.com>
Committed: Tue Jul 10 13:15:21 2018 +0200

----------------------------------------------------------------------
 .../jclouds/oneandone/rest/OneAndOneApi.java    |   9 +
 .../oneandone/rest/domain/BlockStorage.java     | 155 ++++++++++++++++
 .../jclouds/oneandone/rest/domain/SshKey.java   | 100 ++++++++++
 .../rest/features/BlockStorageApi.java          |  90 +++++++++
 .../oneandone/rest/features/SshKeyApi.java      |  77 ++++++++
 .../rest/features/BlockStorageApiLiveTest.java  | 120 ++++++++++++
 .../rest/features/BlockStorageApiMockTest.java  | 185 +++++++++++++++++++
 .../rest/features/SshKeyApiLiveTest.java        |  89 +++++++++
 .../rest/features/SshKeyApiMockTest.java        | 155 ++++++++++++++++
 .../rest/internal/BaseOneAndOneLiveTest.java    |  17 +-
 .../src/test/resources/blockstorage/get.json    |  18 ++
 .../src/test/resources/blockstorage/list.json   |  52 ++++++
 oneandone/src/test/resources/sshkeys/get.json   |  13 ++
 oneandone/src/test/resources/sshkeys/list.json  |  28 +++
 14 files changed, 1107 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/4a9536b8/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/OneAndOneApi.java
----------------------------------------------------------------------
diff --git a/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/OneAndOneApi.java b/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/OneAndOneApi.java
index 388e5f9..510eb13 100644
--- a/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/OneAndOneApi.java
+++ b/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/OneAndOneApi.java
@@ -17,6 +17,7 @@
 package org.apache.jclouds.oneandone.rest;
 
 import java.io.Closeable;
+import org.apache.jclouds.oneandone.rest.features.BlockStorageApi;
 import org.apache.jclouds.oneandone.rest.features.DataCenterApi;
 import org.apache.jclouds.oneandone.rest.features.FirewallPolicyApi;
 import org.apache.jclouds.oneandone.rest.features.ImageApi;
@@ -28,7 +29,9 @@ import org.apache.jclouds.oneandone.rest.features.PublicIpApi;
 import org.apache.jclouds.oneandone.rest.features.ServerApi;
 import org.apache.jclouds.oneandone.rest.features.ServerApplianceApi;
 import org.apache.jclouds.oneandone.rest.features.SharedStorageApi;
+import org.apache.jclouds.oneandone.rest.features.SshKeyApi;
 import org.apache.jclouds.oneandone.rest.features.VpnApi;
+
 import org.jclouds.rest.annotations.Delegate;
 
 public interface OneAndOneApi extends Closeable {
@@ -68,4 +71,10 @@ public interface OneAndOneApi extends Closeable {
 
    @Delegate
    ServerApplianceApi serverApplianceApi();
+
+   @Delegate
+   BlockStorageApi blockStorageApi();
+
+   @Delegate
+   SshKeyApi sshKeyApi();
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/4a9536b8/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/domain/BlockStorage.java
----------------------------------------------------------------------
diff --git a/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/domain/BlockStorage.java b/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/domain/BlockStorage.java
new file mode 100644
index 0000000..7d635d8
--- /dev/null
+++ b/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/domain/BlockStorage.java
@@ -0,0 +1,155 @@
+/*
+ * 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.jclouds.oneandone.rest.domain;
+
+import com.google.auto.value.AutoValue;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+@AutoValue
+public abstract class BlockStorage {
+
+   public abstract String id();
+
+   public abstract int size();
+
+   @Nullable
+   public abstract String state();
+
+   @Nullable
+   public abstract String description();
+
+   @Nullable
+   public abstract Datacenter datacenter();
+
+   public abstract String name();
+
+   @Nullable
+   public abstract String creationDate();
+
+   @Nullable
+   public abstract Server server();
+
+   @SerializedNames({"id", "size", "state", "description", "datacenter", "name", "creation_date", "server"})
+   public static BlockStorage create(String id, int size, String state, String description, Datacenter datacenter, String name, String creationDate, Server server) {
+      return new AutoValue_BlockStorage(id, size, state, description, datacenter, name, creationDate, server);
+   }
+
+   @AutoValue
+   public abstract static class CreateBlockStorage {
+
+      public abstract String name();
+
+      public abstract int size();
+
+      @Nullable
+      public abstract String description();
+
+      @Nullable
+      public abstract String datacenterId();
+
+      @Nullable
+      public abstract String server();
+
+      @SerializedNames({"name", "size", "description", "datacenter_id", "server"})
+      public static CreateBlockStorage create(final String name, final int size, final String description,
+              final String datacenterId, final String server) {
+         return builder()
+                 .name(name)
+                 .size(size)
+                 .description(description)
+                 .datacenterId(datacenterId)
+                 .server(server)
+                 .build();
+      }
+
+      public static Builder builder() {
+         return new AutoValue_BlockStorage_CreateBlockStorage.Builder();
+      }
+
+      @AutoValue.Builder
+      public abstract static class Builder {
+
+         public abstract Builder name(String name);
+
+         public abstract Builder description(String description);
+
+         public abstract Builder size(int size);
+
+         public abstract Builder datacenterId(String datacenterId);
+
+         public abstract Builder server(String server);
+
+         public abstract CreateBlockStorage build();
+      }
+   }
+
+   @AutoValue
+   public abstract static class UpdateBlockStorage {
+
+      @Nullable
+      public abstract String name();
+
+      @Nullable
+      public abstract String description();
+
+      @SerializedNames({"name", "description"})
+      public static UpdateBlockStorage create(final String name, final String description) {
+         return new AutoValue_BlockStorage_UpdateBlockStorage(name, description);
+      }
+   }
+
+   @AutoValue
+   public abstract static class Datacenter {
+
+      public abstract String id();
+
+      public abstract String location();
+
+      public abstract String countryCode();
+
+      @SerializedNames({"id", "location", "country_code"})
+      public static Datacenter create(String id, String location, String countryCode) {
+         return new AutoValue_BlockStorage_Datacenter(id, location, countryCode);
+      }
+   }
+
+   @AutoValue
+   public abstract static class Server {
+
+      public abstract String id();
+
+      public abstract String name();
+
+      @SerializedNames({"id", "name"})
+      public static Server create(String id, String name) {
+         return new AutoValue_BlockStorage_Server(id, name);
+      }
+
+      @AutoValue
+      public abstract static class AttachServer {
+
+         public abstract String serverId();
+
+         @SerializedNames({"server_id"})
+         public static AttachServer create(final String serverId) {
+            return new AutoValue_BlockStorage_Server_AttachServer(serverId);
+         }
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/4a9536b8/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/domain/SshKey.java
----------------------------------------------------------------------
diff --git a/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/domain/SshKey.java b/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/domain/SshKey.java
new file mode 100644
index 0000000..97f69c4
--- /dev/null
+++ b/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/domain/SshKey.java
@@ -0,0 +1,100 @@
+/*
+ * 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.jclouds.oneandone.rest.domain;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+import org.apache.jclouds.oneandone.rest.domain.Types.GenericState;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+import java.util.List;
+
+@AutoValue
+public abstract class SshKey {
+
+   public abstract String id();
+
+   public abstract String name();
+
+   @Nullable
+   public abstract String description();
+
+   @Nullable
+   public abstract GenericState state();
+
+   @Nullable
+   public abstract List<Server> servers();
+
+   @Nullable
+   public abstract String md5();
+
+   @Nullable
+   public abstract String publicKey();
+
+   @Nullable
+   public abstract String creationDate();
+
+   @SerializedNames({"id", "name", "description", "state", "servers", "md5", "public_key", "creation_date"})
+   public static SshKey create(String id, String name, String description, GenericState state, List<Server> servers, String md5, String publicKey, String creationDate) {
+      return new AutoValue_SshKey(id, name, description, state, servers == null ? ImmutableList.<Server>of() : ImmutableList.copyOf(servers), md5, publicKey, creationDate);
+   }
+
+   @AutoValue
+   public abstract static class CreateSshKey {
+
+      public abstract String name();
+
+      @Nullable
+      public abstract String description();
+
+      @Nullable
+      public abstract String publicKey();
+
+      @SerializedNames({"name", "description", "public_key"})
+      public static CreateSshKey create(String name, String description, String publicKey) {
+         return new AutoValue_SshKey_CreateSshKey(name, description, publicKey);
+      }
+   }
+
+   @AutoValue
+   public abstract static class UpdateSshKey {
+
+      public abstract String name();
+
+      @Nullable
+      public abstract String description();
+
+      @SerializedNames({"name", "description"})
+      public static UpdateSshKey create(String name, String description) {
+         return new AutoValue_SshKey_UpdateSshKey(name, description);
+      }
+   }
+
+   @AutoValue
+   public abstract static class Server {
+
+      public abstract String id();
+
+      public abstract String name();
+
+      @SerializedNames({"id", "name"})
+      public static Server create(String id, String name) {
+         return new AutoValue_SshKey_Server(id, name);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/4a9536b8/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/features/BlockStorageApi.java
----------------------------------------------------------------------
diff --git a/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/features/BlockStorageApi.java b/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/features/BlockStorageApi.java
new file mode 100644
index 0000000..c192ccb
--- /dev/null
+++ b/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/features/BlockStorageApi.java
@@ -0,0 +1,90 @@
+/*
+ * 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.jclouds.oneandone.rest.features;
+
+import org.apache.jclouds.oneandone.rest.domain.BlockStorage;
+import org.apache.jclouds.oneandone.rest.domain.BlockStorage.Server;
+import org.apache.jclouds.oneandone.rest.domain.options.GenericQueryOptions;
+import org.apache.jclouds.oneandone.rest.filters.AuthenticateRequest;
+import org.jclouds.Fallbacks;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import javax.inject.Named;
+import java.io.Closeable;
+import java.util.List;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.PUT;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+
+@Path("/block_storages")
+@Produces("application/json")
+@Consumes("application/json")
+@RequestFilters(AuthenticateRequest.class)
+public interface BlockStorageApi extends Closeable {
+
+   @Named("blockstorages:list")
+   @GET
+   @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class)
+   List<BlockStorage> list();
+
+   @Named("blockstorages:list")
+   @GET
+   @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class)
+   List<BlockStorage> list(GenericQueryOptions options);
+
+   @Named("blockstorages:get")
+   @GET
+   @Path("/{blockStorageId}")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   BlockStorage get(@PathParam("blockStorageId") String blockStorageId);
+
+   @Named("blockstorages:create")
+   @POST
+   BlockStorage create(@BinderParam(BindToJsonPayload.class) BlockStorage.CreateBlockStorage blockStorage);
+
+   @Named("blockstorages:update")
+   @PUT
+   @Path("/{blockStorageId}")
+   BlockStorage update(@PathParam("blockStorageId") String blockStorageId, @BinderParam(BindToJsonPayload.class) BlockStorage.UpdateBlockStorage blockStorage);
+
+   @Named("blockstorages:delete")
+   @DELETE
+   @Path("/{blockStorageId}")
+   @MapBinder(BindToJsonPayload.class)
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   void delete(@PathParam("blockStorageId") String blockStorageId);
+
+   @Named("blockstorages:attachServer")
+   @POST
+   @Path("/{blockStorageId}/server")
+   BlockStorage attachServer(@PathParam("blockStorageId") String blockStorageId, @BinderParam(BindToJsonPayload.class) Server.AttachServer server);
+
+   @Named("blockstorages:detachServer")
+   @DELETE
+   @Path("/{blockStorageId}/server")
+   @MapBinder(BindToJsonPayload.class)
+   BlockStorage detachServer(@PathParam("blockStorageId") String blockStorageId);
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/4a9536b8/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/features/SshKeyApi.java
----------------------------------------------------------------------
diff --git a/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/features/SshKeyApi.java b/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/features/SshKeyApi.java
new file mode 100644
index 0000000..4dce7dd
--- /dev/null
+++ b/oneandone/src/main/java/org/apache/jclouds/oneandone/rest/features/SshKeyApi.java
@@ -0,0 +1,77 @@
+/*
+ * 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.jclouds.oneandone.rest.features;
+
+import org.apache.jclouds.oneandone.rest.domain.SshKey;
+import org.apache.jclouds.oneandone.rest.domain.options.GenericQueryOptions;
+import org.apache.jclouds.oneandone.rest.filters.AuthenticateRequest;
+import org.jclouds.Fallbacks;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import javax.inject.Named;
+import java.util.List;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.PUT;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.RequestFilters;
+
+@Path("/ssh_keys")
+@Produces("application/json")
+@Consumes("application/json")
+@RequestFilters(AuthenticateRequest.class)
+public interface SshKeyApi {
+
+   @Named("sshkeys:list")
+   @GET
+   @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class)
+   List<SshKey> list();
+
+   @Named("sshkeys:list")
+   @GET
+   @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class)
+   List<SshKey> list(GenericQueryOptions options);
+
+   @Named("sshkeys:get")
+   @GET
+   @Path("/{sshKeyId}")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   SshKey get(@PathParam("sshKeyId") String sshKeyId);
+
+   @Named("sshkeys:create")
+   @POST
+   SshKey create(@BinderParam(BindToJsonPayload.class) SshKey.CreateSshKey sshKey);
+
+   @Named("sshkeys:update")
+   @PUT
+   @Path("/{sshKeyId}")
+   SshKey update(@PathParam("sshKeyId") String sshKeyId, @BinderParam(BindToJsonPayload.class) SshKey.UpdateSshKey sshKey);
+
+   @Named("sshkeys:delete")
+   @DELETE
+   @Path("/{sshKeyId}")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @MapBinder(BindToJsonPayload.class)
+   SshKey delete(@PathParam("sshKeyId") String sshKeyId);
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/4a9536b8/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/BlockStorageApiLiveTest.java
----------------------------------------------------------------------
diff --git a/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/BlockStorageApiLiveTest.java b/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/BlockStorageApiLiveTest.java
new file mode 100644
index 0000000..452cc9b
--- /dev/null
+++ b/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/BlockStorageApiLiveTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.jclouds.oneandone.rest.features;
+
+import org.apache.jclouds.oneandone.rest.domain.Server;
+import org.apache.jclouds.oneandone.rest.domain.BlockStorage;
+import org.apache.jclouds.oneandone.rest.domain.options.GenericQueryOptions;
+import org.apache.jclouds.oneandone.rest.internal.BaseOneAndOneLiveTest;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.util.List;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+
+@Test(groups = "live", testName = "BlockStorageApiLiveTest")
+public class BlockStorageApiLiveTest extends BaseOneAndOneLiveTest {
+
+   private BlockStorage currentBlockStorage;
+   private Server currentServer;
+   private List<BlockStorage> blockStorages;
+
+   private BlockStorageApi blockStorageApi() {
+
+      return api.blockStorageApi();
+   }
+
+   @BeforeClass
+   public void setupTest() {
+      currentServer = createServer("blockstorage jclouds server2");
+      assertNodeAvailable(currentServer);
+      currentBlockStorage = blockStorageApi().create(BlockStorage.CreateBlockStorage.builder()
+              .name("jcloudsBlockStorage2")
+              .description("description")
+              .size(20)
+              .datacenterId("908DC2072407C94C8054610AD5A53B8C")
+              .build());
+      assertNotNull(currentBlockStorage);
+   }
+
+   @Test
+   public void testList() {
+      blockStorages = blockStorageApi().list();
+
+      assertNotNull(blockStorages);
+      Assert.assertTrue(blockStorages.size() > 0);
+   }
+
+   public void testListWithOption() {
+      GenericQueryOptions options = new GenericQueryOptions();
+      options.options(0, 0, null, "jcloudsBlockStorage", null);
+      List<BlockStorage> blockStoragesWithQuery = blockStorageApi().list(options);
+
+      assertNotNull(blockStoragesWithQuery);
+      Assert.assertTrue(blockStoragesWithQuery.size() > 0);
+   }
+
+   public void testGet() {
+      BlockStorage result = blockStorageApi().get(currentBlockStorage.id());
+
+      assertNotNull(result);
+      assertEquals(result.id(), currentBlockStorage.id());
+   }
+
+   @Test
+   public void testUpdate() throws InterruptedException {
+      String updatedName = "jcloudsBlockStorage";
+
+      BlockStorage updateResult = blockStorageApi().update(currentBlockStorage.id(), BlockStorage.UpdateBlockStorage.create(updatedName, "desc"));
+
+      assertNotNull(updateResult);
+      assertEquals(updateResult.name(), updatedName);
+
+   }
+
+   @Test(dependsOnMethods = "testUpdate")
+   public void testAttachBlockStorage() throws InterruptedException {
+      BlockStorage.Server.AttachServer attachServer = BlockStorage.Server.AttachServer.create(currentServer.id());
+      BlockStorage attachResult = blockStorageApi().attachServer(currentBlockStorage.id(), attachServer);
+
+      assertNotNull(attachResult);
+   }
+
+   @Test(dependsOnMethods = "testAttachBlockStorage")
+   public void testDetachServer() {
+      assertNodeAvailable(currentServer);
+      assertBlockStorageAvailable(currentBlockStorage);
+      BlockStorage result = blockStorageApi().detachServer(currentBlockStorage.id());
+
+      assertNotNull(result);
+      assertEquals(result.id(), currentBlockStorage.id());
+   }
+
+   @AfterClass(alwaysRun = true)
+   public void teardownTest() {
+      assertNodeAvailable(currentServer);
+      assertBlockStorageAvailable(currentBlockStorage);
+      blockStorageApi().delete(currentBlockStorage.id());
+      assertNodeAvailable(currentServer);
+      deleteServer(currentServer.id());
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/4a9536b8/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/BlockStorageApiMockTest.java
----------------------------------------------------------------------
diff --git a/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/BlockStorageApiMockTest.java b/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/BlockStorageApiMockTest.java
new file mode 100644
index 0000000..f97a8c7
--- /dev/null
+++ b/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/BlockStorageApiMockTest.java
@@ -0,0 +1,185 @@
+/*
+ * 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.jclouds.oneandone.rest.features;
+
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import org.apache.jclouds.oneandone.rest.domain.BlockStorage;
+import org.apache.jclouds.oneandone.rest.domain.options.GenericQueryOptions;
+import org.apache.jclouds.oneandone.rest.internal.BaseOneAndOneApiMockTest;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+@Test(groups = "unit", testName = "BlockStorageApiMockTest", singleThreaded = true)
+public class BlockStorageApiMockTest extends BaseOneAndOneApiMockTest {
+
+   private BlockStorageApi blockStorageApi() {
+      return api.blockStorageApi();
+   }
+
+   public void testList() throws InterruptedException {
+      server.enqueue(
+            new MockResponse().setBody(stringFromResource("/blockstorage/list.json"))
+      );
+
+      List<BlockStorage> blockStorages = blockStorageApi().list();
+
+      assertNotNull(blockStorages);
+      assertEquals(blockStorages.size(), 3);
+
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "/block_storages");
+   }
+
+   public void testList404() throws InterruptedException {
+      server.enqueue(
+            new MockResponse().setResponseCode(404));
+
+      List<BlockStorage> blockStorages = blockStorageApi().list();
+
+      assertNotNull(blockStorages);
+      assertEquals(blockStorages.size(), 0);
+
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "/block_storages");
+   }
+
+   public void testListWithOption() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setBody(stringFromResource("/blockstorage/list.json"))
+      );
+      GenericQueryOptions options = new GenericQueryOptions();
+      options.options(0, 0, null, "New", null);
+      List<BlockStorage> blockStorages = blockStorageApi().list(options);
+
+      assertNotNull(blockStorages);
+      assertEquals(blockStorages.size(), 3);
+
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "/block_storages?q=New");
+   }
+
+   public void testListWithOption404() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setResponseCode(404)
+      );
+      GenericQueryOptions options = new GenericQueryOptions();
+      options.options(0, 0, null, "test", null);
+      List<BlockStorage> blockStorages = blockStorageApi().list(options);
+
+      assertNotNull(blockStorages);
+      assertEquals(blockStorages.size(), 0);
+
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "/block_storages?q=test");
+   }
+
+   public void testGet() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setBody(stringFromResource("/blockstorage/get.json"))
+      );
+      BlockStorage result = blockStorageApi().get("blockStorageId");
+
+      assertNotNull(result);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "/block_storages/blockStorageId");
+   }
+
+   public void testGet404() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setResponseCode(404)
+      );
+      BlockStorage result = blockStorageApi().get("blockStorageId");
+
+      assertEquals(result, null);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "/block_storages/blockStorageId");
+   }
+
+   public void testCreate() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setBody(stringFromResource("/blockstorage/get.json"))
+      );
+      BlockStorage response = blockStorageApi().create(BlockStorage.CreateBlockStorage.builder()
+              .name("name")
+              .description("desc")
+              .size(20)
+              .datacenterId("datacenter-id")
+              .build());
+
+      assertNotNull(response);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "POST", "/block_storages", "{\"name\":\"name\",\"description\":\"desc\",\"size\":20,\"datacenter_id\":\"datacenter-id\"}");
+   }
+
+   public void testUpdate() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setBody(stringFromResource("/blockstorage/get.json"))
+      );
+      BlockStorage response = blockStorageApi().update("blockStorageId", BlockStorage.UpdateBlockStorage.create("name", "desc"));
+      assertNotNull(response);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "PUT", "/block_storages/blockStorageId", "{\"name\":\"name\",\"description\":\"desc\"}");
+   }
+
+   public void testDelete() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setBody(stringFromResource("/blockstorage/get.json"))
+      );
+      blockStorageApi().delete("blockStorageId");
+
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "DELETE", "/block_storages/blockStorageId");
+   }
+
+   public void testDelete404() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setResponseCode(404));
+      blockStorageApi().delete("blockStorageId");
+
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "DELETE", "/block_storages/blockStorageId");
+   }
+
+   public void testAttachServer() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setBody(stringFromResource("/blockstorage/get.json"))
+      );
+
+      BlockStorage.Server.AttachServer attachServer = BlockStorage.Server.AttachServer.create("serverId");
+      BlockStorage response = blockStorageApi().attachServer("blockStorageId", attachServer);
+
+      assertNotNull(response);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "POST", "/block_storages/blockStorageId/server", "{\"server_id\":\"serverId\"}");
+   }
+
+   public void testDetachServer() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setBody(stringFromResource("/blockstorage/get.json"))
+      );
+      BlockStorage response = blockStorageApi().detachServer("blockStorageId");
+
+      assertNotNull(response);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "DELETE", "/block_storages/blockStorageId/server");
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/4a9536b8/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/SshKeyApiLiveTest.java
----------------------------------------------------------------------
diff --git a/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/SshKeyApiLiveTest.java b/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/SshKeyApiLiveTest.java
new file mode 100644
index 0000000..e1afb9f
--- /dev/null
+++ b/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/SshKeyApiLiveTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.jclouds.oneandone.rest.features;
+
+import org.apache.jclouds.oneandone.rest.domain.SshKey;
+import java.util.List;
+import org.apache.jclouds.oneandone.rest.domain.options.GenericQueryOptions;
+import org.apache.jclouds.oneandone.rest.internal.BaseOneAndOneLiveTest;
+import org.testng.Assert;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "SshKeyApiLiveTest")
+public class SshKeyApiLiveTest extends BaseOneAndOneLiveTest {
+
+   private SshKey currentSshKey;
+   private List<SshKey> sshKeys;
+
+   private SshKeyApi sshKeyApi() {
+      return api.sshKeyApi();
+   }
+
+   @BeforeClass
+   public void setupTest() {
+      currentSshKey = sshKeyApi().create(SshKey.CreateSshKey.create("jclouds sshKey", "description", null));
+   }
+
+   @Test
+   public void testList() {
+      sshKeys = sshKeyApi().list();
+
+      assertNotNull(sshKeys);
+      assertFalse(sshKeys.isEmpty());
+      Assert.assertTrue(sshKeys.size() > 0);
+   }
+
+   @Test
+   public void testListWithOption() {
+      GenericQueryOptions options = new GenericQueryOptions();
+      options.options(0, 0, null, "jclouds", null);
+      List<SshKey> resultWithQuery = sshKeyApi().list(options);
+
+      assertNotNull(resultWithQuery);
+      assertFalse(resultWithQuery.isEmpty());
+      Assert.assertTrue(resultWithQuery.size() > 0);
+   }
+
+   @Test
+   public void testGet() {
+      SshKey result = sshKeyApi().get(currentSshKey.id());
+
+      assertNotNull(result);
+      assertEquals(result.id(), currentSshKey.id());
+   }
+
+   @Test(dependsOnMethods = "testGet")
+   public void testUpdate() throws InterruptedException {
+      String updatedName = "updatejclouds SSH Key";
+
+      SshKey updateResult = sshKeyApi().update(currentSshKey.id(), SshKey.UpdateSshKey.create(updatedName, "desc"));
+
+      assertNotNull(updateResult);
+      assertEquals(updateResult.name(), updatedName);
+
+   }
+
+   @AfterClass(alwaysRun = true)
+   public void teardownTest() throws InterruptedException {
+      sshKeyApi().delete(currentSshKey.id());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/4a9536b8/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/SshKeyApiMockTest.java
----------------------------------------------------------------------
diff --git a/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/SshKeyApiMockTest.java b/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/SshKeyApiMockTest.java
new file mode 100644
index 0000000..0edfa6f
--- /dev/null
+++ b/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/features/SshKeyApiMockTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.jclouds.oneandone.rest.features;
+
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import org.apache.jclouds.oneandone.rest.domain.SshKey;
+import org.apache.jclouds.oneandone.rest.domain.options.GenericQueryOptions;
+import org.apache.jclouds.oneandone.rest.internal.BaseOneAndOneApiMockTest;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+@Test(groups = "unit", testName = "SshKeyApiMockTest", singleThreaded = true)
+public class SshKeyApiMockTest extends BaseOneAndOneApiMockTest {
+
+   private SshKeyApi sshKeyApi() {
+      return api.sshKeyApi();
+   }
+
+   public void testList() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setBody(stringFromResource("/sshkeys/list.json"))
+      );
+
+      List<SshKey> sshKeys = sshKeyApi().list();
+
+      assertNotNull(sshKeys);
+      assertEquals(sshKeys.size(), 2);
+
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "/ssh_keys");
+   }
+
+   public void testList404() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setResponseCode(404));
+
+      List<SshKey> sshKeys = sshKeyApi().list();
+
+      assertEquals(sshKeys.size(), 0);
+
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "/ssh_keys");
+   }
+
+   public void testListWithOption() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setBody(stringFromResource("/sshkeys/list.json"))
+      );
+      GenericQueryOptions options = new GenericQueryOptions();
+      options.options(0, 0, null, "New", null);
+      List<SshKey> sshKeys = sshKeyApi().list(options);
+
+      assertNotNull(sshKeys);
+      assertEquals(sshKeys.size(), 2);
+
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "/ssh_keys?q=New");
+   }
+
+   public void testListWithOption404() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setResponseCode(404));
+      GenericQueryOptions options = new GenericQueryOptions();
+      options.options(0, 0, null, "New", null);
+      List<SshKey> sshKeys = sshKeyApi().list(options);
+
+      assertEquals(sshKeys.size(), 0);
+
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "/ssh_keys?q=New");
+   }
+
+   public void testGet() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setBody(stringFromResource("/sshkeys/get.json"))
+      );
+      SshKey result = sshKeyApi().get("sshKeyId");
+
+      assertNotNull(result);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "/ssh_keys/sshKeyId");
+   }
+
+   public void testGet404() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setResponseCode(404));
+      SshKey result = sshKeyApi().get("sshKeyId");
+
+      assertEquals(result, null);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "/ssh_keys/sshKeyId");
+   }
+
+   public void testCreate() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setBody(stringFromResource("/sshkeys/get.json"))
+      );
+
+      SshKey response = sshKeyApi().create(SshKey.CreateSshKey.create("name", "desc", null));
+
+      assertNotNull(response);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "POST", "/ssh_keys", "{\"name\":\"name\",\"description\":\"desc\"}");
+   }
+
+   public void testUpdate() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setBody(stringFromResource("/sshkeys/get.json"))
+      );
+      SshKey response = sshKeyApi().update("sshKeyId", SshKey.UpdateSshKey.create("name", "desc"));
+
+      assertNotNull(response);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "PUT", "/ssh_keys/sshKeyId", "{\"name\":\"name\",\"description\":\"desc\"}");
+   }
+
+   public void testDelete() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setBody(stringFromResource("/sshkeys/get.json"))
+      );
+      SshKey response = sshKeyApi().delete("sshKeyId");
+
+      assertNotNull(response);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "DELETE", "/ssh_keys/sshKeyId");
+   }
+
+   public void testDelete404() throws InterruptedException {
+      server.enqueue(
+              new MockResponse().setResponseCode(404));
+      SshKey response = sshKeyApi().delete("sshKeyId");
+
+      assertEquals(response, null);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "DELETE", "/ssh_keys/sshKeyId");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/4a9536b8/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/internal/BaseOneAndOneLiveTest.java
----------------------------------------------------------------------
diff --git a/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/internal/BaseOneAndOneLiveTest.java b/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/internal/BaseOneAndOneLiveTest.java
index bd472c4..0666426 100644
--- a/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/internal/BaseOneAndOneLiveTest.java
+++ b/oneandone/src/test/java/org/apache/jclouds/oneandone/rest/internal/BaseOneAndOneLiveTest.java
@@ -25,6 +25,7 @@ import java.util.Properties;
 import java.util.concurrent.TimeUnit;
 import org.apache.jclouds.oneandone.rest.OneAndOneApi;
 import org.apache.jclouds.oneandone.rest.OneAndOneProviderMetadata;
+import org.apache.jclouds.oneandone.rest.domain.BlockStorage;
 import org.apache.jclouds.oneandone.rest.domain.Hardware;
 import org.apache.jclouds.oneandone.rest.domain.Hdd;
 import org.apache.jclouds.oneandone.rest.domain.PrivateNetwork;
@@ -43,6 +44,7 @@ public class BaseOneAndOneLiveTest extends BaseApiLiveTest<OneAndOneApi> {
    Predicate<Server> waitUntilServerReady;
    Predicate<ServerPrivateNetworkRef> waitUntilPrivateNetworkReady;
    Predicate<Vpn> waitUntilVPNReady;
+   Predicate<BlockStorage> waitUntilBlockStorageReady;
    Timeouts timeouts;
    PollPeriod pollPeriod;
    private static final OneAndOneProviderMetadata METADATA = new OneAndOneProviderMetadata();
@@ -86,9 +88,18 @@ public class BaseOneAndOneLiveTest extends BaseApiLiveTest<OneAndOneApi> {
             return result.state() == Types.GenericState.ACTIVE;
          }
       };
+      
+      Predicate<BlockStorage> bsAvailableCheck = new Predicate<BlockStorage>() {
+         @Override
+         public boolean apply(BlockStorage bs) {
+            BlockStorage result = api.blockStorageApi().get(bs.id());
+            return "POWERED_ON".equals(result.state());
+         }
+      };
       waitUntilVPNReady = Predicates2.retry(vpnAvailableCheck, timeouts.nodeRunning, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod, TimeUnit.SECONDS);
       waitUntilPrivateNetworkReady = Predicates2.retry(privateNetworkAvailableCheck, timeouts.nodeRunning, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod, TimeUnit.SECONDS);
       waitUntilServerReady = Predicates2.retry(serverAvailableCheck, timeouts.nodeRunning, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod, TimeUnit.SECONDS);
+      waitUntilBlockStorageReady = Predicates2.retry(bsAvailableCheck, timeouts.nodeRunning, pollPeriod.pollInitialPeriod, pollPeriod.pollMaxPeriod, TimeUnit.SECONDS);
 
       return injector.getInstance(OneAndOneApi.class);
    }
@@ -103,7 +114,7 @@ public class BaseOneAndOneLiveTest extends BaseApiLiveTest<OneAndOneApi> {
               .name(serverName)
               .description("testing with jclouds")
               .hardware(hardware)
-              .applianceId("81504C620D98BCEBAA5202D145203B4B")
+              .applianceId("753E3C1F859874AA74EB63B3302601F5")
               .dataCenterId("908DC2072407C94C8054610AD5A53B8C")
               .password("Test123!")
               .powerOn(Boolean.TRUE).build());
@@ -118,6 +129,10 @@ public class BaseOneAndOneLiveTest extends BaseApiLiveTest<OneAndOneApi> {
    protected void assertNodeAvailable(Server server) {
       assertTrue(waitUntilServerReady.apply(server), String.format("Server %s is not Ready", server));
    }
+   
+    protected void assertBlockStorageAvailable(BlockStorage bs) {
+      assertTrue(waitUntilBlockStorageReady.apply(bs), String.format("BlockStorage %s is not Ready", bs));
+   }
 
    protected void assertPrivateNetworkAvailable(ServerPrivateNetworkRef ref) {
       assertTrue(waitUntilPrivateNetworkReady.apply(ref), String.format("ServerPrivateNetworkRef %s is not Ready", ref));

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/4a9536b8/oneandone/src/test/resources/blockstorage/get.json
----------------------------------------------------------------------
diff --git a/oneandone/src/test/resources/blockstorage/get.json b/oneandone/src/test/resources/blockstorage/get.json
new file mode 100644
index 0000000..07021e3
--- /dev/null
+++ b/oneandone/src/test/resources/blockstorage/get.json
@@ -0,0 +1,18 @@
+{
+  "id": "6AD2F180B7B666539EF75A02FE227084",
+  "size": 200,
+  "state": "ACTIVE",
+  "description": "My block storage for containers",
+  "datacenter": {
+    "id": "D0F6D8C8ED29D3036F94C27BBB7BAD36",
+    "location": "USA",
+    "country_code": "US"
+  },
+  "name": "My block storage 1",
+  "creation_date": "2015-05-06T08:33:25+00:00",
+  "server":
+  {
+    "id": "638ED28205B1AFD7ADEF569C725DD85F",
+    "name": "My server 1"
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/4a9536b8/oneandone/src/test/resources/blockstorage/list.json
----------------------------------------------------------------------
diff --git a/oneandone/src/test/resources/blockstorage/list.json b/oneandone/src/test/resources/blockstorage/list.json
new file mode 100644
index 0000000..c5f4a3e
--- /dev/null
+++ b/oneandone/src/test/resources/blockstorage/list.json
@@ -0,0 +1,52 @@
+[
+{
+  "id": "6AD2F180B7B666539EF75A02FE227084",
+  "size": 200,
+  "state": "ACTIVE",
+  "description": "My block storage for containers",
+  "datacenter": {
+    "id": "D0F6D8C8ED29D3036F94C27BBB7BAD36",
+    "location": "USA",
+    "country_code": "US"
+  },
+  "name": "My block storage 1",
+  "creation_date": "2015-05-06T08:33:25+00:00",
+  "server":
+  {
+    "id": "638ED28205B1AFD7ADEF569C725DD85F",
+    "name": "My server 1"
+  }
+},
+{
+  "id": "4406CE4723BB441C7956E25C51CE8C1B",
+  "size": 50,
+  "state": "ACTIVE",
+  "description": "My block storage description",
+  "datacenter": {
+    "id": "D0F6D8C8ED29D3036F94C27BBB7BAD36",
+    "location": "USA",
+    "country_code": "US"
+  },
+  "name": "My block storage 3",
+  "creation_date": "2015-03-17T11:57:48+00:00",
+  "server": null
+},
+{
+  "id": "1A5418172DD3BD39F8010A6633F1018A",
+  "size": 250,
+  "state": "ACTIVE",
+  "description": "",
+  "datacenter": {
+    "id": "D0F6D8C8ED29D3036F94C27BBB7BAD36",
+    "location": "USA",
+    "country_code": "US"
+  },
+  "name": "My block storage 2",
+  "creation_date": "2015-05-05T09:36:31+00:00",
+  "server":
+  {
+    "id": "748ED28205B1AFD7ADEF569C725DD85E",
+    "name": "My server 2"
+  }
+}
+]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/4a9536b8/oneandone/src/test/resources/sshkeys/get.json
----------------------------------------------------------------------
diff --git a/oneandone/src/test/resources/sshkeys/get.json b/oneandone/src/test/resources/sshkeys/get.json
new file mode 100644
index 0000000..d42e47a
--- /dev/null
+++ b/oneandone/src/test/resources/sshkeys/get.json
@@ -0,0 +1,13 @@
+{
+  "id": "39AA65F5D5B02FA02D58173094EBAF95",
+  "name": "My SSH key 1",
+  "description": "My SSH key description",
+  "state": "ACTIVE",
+  "servers": [
+	{"id": "D0F6D8C8ED29D3036F94C27BBB789536","name": "Server 1"},
+	{"id": "E0F6D8C8ED29D3036F94C27BBB789537","name": "Server 2"}
+  ],
+  "md5": "5df9f63916ebf8528697b629022993e8",
+  "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQAB",
+  "creation_date": "30-06-2015T 14:52:35+00.00"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/4a9536b8/oneandone/src/test/resources/sshkeys/list.json
----------------------------------------------------------------------
diff --git a/oneandone/src/test/resources/sshkeys/list.json b/oneandone/src/test/resources/sshkeys/list.json
new file mode 100644
index 0000000..c20efc4
--- /dev/null
+++ b/oneandone/src/test/resources/sshkeys/list.json
@@ -0,0 +1,28 @@
+[
+{
+  "id": "39AA65F5D5B02FA02D58173094EBAF95",
+  "name": "My SSH key 1",
+  "description": "My SSH key description",
+  "state": "ACTIVE",
+  "servers": [
+	{"id": "D0F6D8C8ED29D3036F94C27BBB789536","name": "Server 1"},
+	{"id": "E0F6D8C8ED29D3036F94C27BBB789537","name": "Server 2"}
+  ],
+  "md5": "5df9f63916ebf8528697b629022993e8",
+  "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQAB",
+  "creation_date": "30-06-2015T 14:52:35+00.00"
+},
+{
+  "id": "39AA65F5D5B02FA02D58173094EBAF96",
+  "name": "My SSH key 2",
+  "description": "My SSH key description",
+  "state": "ACTIVE",
+  "servers": [
+	{"id": "D0F6D8C8ED29D3036F94C27BBB789536","name": "Server 1"},
+	{"id": "E0F6D8C8ED29D3036F94C27BBB789537","name": "Server 2"}
+  ],
+  "md5": "5df9f63916ebf8528697b629022993e3",
+  "public_key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQAC",
+  "creation_date": "31-08-2017T 14:52:35+00.00"
+}
+]
\ No newline at end of file