You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by za...@apache.org on 2013/12/13 00:38:19 UTC

[3/4] Moving trove to jclouds from jclouds-openstack-labs https://issues.apache.org/jira/browse/JCLOUDS-102

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParseDatabaseListForUser.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParseDatabaseListForUser.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParseDatabaseListForUser.java
new file mode 100644
index 0000000..e357d11
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParseDatabaseListForUser.java
@@ -0,0 +1,54 @@
+/*
+ * 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.jclouds.openstack.trove.v1.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import java.util.List;
+import java.util.Map;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseJson;
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+
+/**
+ * This parses the list of databases
+ * 
+ * @author Zack Shoylev
+ */
+public class ParseDatabaseListForUser implements Function<HttpResponse, FluentIterable<String>> {
+
+   private final ParseJson<Map<String, List<Map<String, String>>>> json;
+
+   @Inject
+   ParseDatabaseListForUser(ParseJson<Map<String, List<Map<String, String>>>> json) {
+      this.json = checkNotNull(json, "json");
+   }
+
+   /**
+    * Parses the database list from the json response
+    */
+   public FluentIterable<String> apply(HttpResponse from) {
+      List<String> resultDatabases = Lists.newArrayList();
+      Map<String, List<Map<String, String>>> result = json.apply(from);
+      for(Map<String, String> database : result.get("databases")) {
+         resultDatabases.add(database.get("name"));
+      }
+      return FluentIterable.from(resultDatabases);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParsePasswordFromRootedInstance.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParsePasswordFromRootedInstance.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParsePasswordFromRootedInstance.java
new file mode 100644
index 0000000..582b01f
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/functions/ParsePasswordFromRootedInstance.java
@@ -0,0 +1,49 @@
+/*
+ * 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.jclouds.openstack.trove.v1.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import java.util.Map;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseJson;
+import com.google.common.base.Function;
+import com.google.inject.Inject;
+
+/**
+ * This parses the password
+ * 
+ * @author Zack Shoylev
+ */
+public class ParsePasswordFromRootedInstance implements Function<HttpResponse, String> {
+
+   private final ParseJson<Map<String, Map<String, String>>> json;
+
+   @Inject
+   ParsePasswordFromRootedInstance(ParseJson<Map<String, Map<String, String>>> json) {
+      this.json = checkNotNull(json, "json");
+   }
+
+   /**
+    * Extracts the user password from the json response
+    */
+   public String apply(HttpResponse from) {
+      Map<String, Map<String, String>> result = json.apply(from);
+      if(result.get("user") == null) 
+         return null;
+      return result.get("user").get("password");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/handlers/TroveErrorHandler.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/handlers/TroveErrorHandler.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/handlers/TroveErrorHandler.java
new file mode 100644
index 0000000..887c541
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/handlers/TroveErrorHandler.java
@@ -0,0 +1,69 @@
+/*
+ * 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.jclouds.openstack.trove.v1.handlers;
+
+import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.InsufficientResourcesException;
+import org.jclouds.rest.ResourceNotFoundException;
+
+/**
+ * This will parse and set an appropriate exception on the command object.
+ * 
+ * @author Zack Shoylev
+ * 
+ */
+@Singleton
+public class TroveErrorHandler implements HttpErrorHandler {
+
+   public void handleError(HttpCommand command, HttpResponse response) {
+      // it is important to always read fully and close streams
+      byte[] data = closeClientButKeepContentStream(response);
+      String message = data != null ? new String(data) : null;
+
+      Exception exception = message != null ? new HttpResponseException(command, response, message)
+               : new HttpResponseException(command, response);
+      message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
+               response.getStatusLine());
+      switch (response.getStatusCode()) {
+         case 400:
+            if (message.contains("quota exceeded"))
+               exception = new InsufficientResourcesException(message, exception);
+            break;
+         case 401:
+         case 403:
+            exception = new AuthorizationException(message, exception);
+            break;
+         case 404:
+            if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
+               exception = new ResourceNotFoundException(message, exception);
+            }
+            break;
+         case 413:
+            exception = new InsufficientResourcesException(message, exception);
+            break;
+      }
+      command.setException(exception);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/internal/Volume.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/internal/Volume.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/internal/Volume.java
new file mode 100644
index 0000000..74c16cf
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/internal/Volume.java
@@ -0,0 +1,32 @@
+/*
+ * 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.jclouds.openstack.trove.v1.internal;
+
+public class Volume{
+   private final int size;
+   
+   public Volume(int size){
+      this.size = size;
+   }
+
+   /**
+    * @return the size
+    */
+   public int getSize() {
+      return size;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/predicates/InstancePredicates.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/predicates/InstancePredicates.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/predicates/InstancePredicates.java
new file mode 100644
index 0000000..6149eff
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/predicates/InstancePredicates.java
@@ -0,0 +1,144 @@
+/*
+ * 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.jclouds.openstack.trove.v1.predicates;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.jclouds.util.Predicates2.retry;
+import org.jclouds.openstack.trove.v1.domain.Instance;
+import org.jclouds.openstack.trove.v1.domain.Instance.Status;
+import org.jclouds.openstack.trove.v1.features.InstanceApi;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Tests to see if instance has reached status. This class is most useful when paired with a RetryablePredicate as
+ * in the code below. This class can be used to block execution until the Instance status has reached a desired state.
+ * This is useful when your Instance needs to be 100% ready before you can continue with execution.
+ *
+ * <pre>
+ * {@code
+ * Instance instance = instanceApi.create(100);
+ * 
+ * RetryablePredicate<String> awaitAvailable = RetryablePredicate.create(
+ *    InstancePredicates.available(instanceApi), 600, 10, 10, TimeUnit.SECONDS);
+ * 
+ * if (!awaitAvailable.apply(instance.getId())) {
+ *    throw new TimeoutException("Timeout on instance: " + instance); 
+ * }    
+ * }
+ * </pre>
+ * 
+ * You can also use the static convenience methods as follows.
+ * 
+ * <pre>
+ * {@code
+ * Instance instance = instanceApi.create(100);
+ * 
+ * if (!InstancePredicates.awaitAvailable(instanceApi).apply(instance.getId())) {
+ *    throw new TimeoutException("Timeout on instance: " + instance);     
+ * }
+ * }
+ * </pre>
+ * 
+ * @author Zack Shoylev
+ */
+public class InstancePredicates {
+   /**
+    * Wait until an Instance is Available.
+    * 
+    * @param instanceApi The InstanceApi in the zone where your Instance resides.
+    * @return RetryablePredicate That will check the status every 5 seconds for a maxiumum of 10 minutes.
+    */
+   public static Predicate<Instance> awaitAvailable(InstanceApi instanceApi) {
+      StatusUpdatedPredicate statusPredicate = new StatusUpdatedPredicate(instanceApi, Instance.Status.ACTIVE);
+      return retry(statusPredicate, 600, 5, 5, SECONDS);
+   }
+
+   /**
+    * Wait until an Instance no longer exists.
+    * 
+    * @param instanceApi The InstanceApi in the zone where your Instance resides.
+    * @return RetryablePredicate That will check whether the Instance exists.
+    * every 5 seconds for a maxiumum of 10 minutes.
+    */
+   public static Predicate<Instance> awaitDeleted(InstanceApi instanceApi) {
+      DeletedPredicate deletedPredicate = new DeletedPredicate(instanceApi);
+      return retry(deletedPredicate, 600, 5, 5, SECONDS);
+   }
+   
+   /**
+    * Wait until instance is in the status specified.
+    * 
+    * @param instanceApi The InstanceApi in the zone where your Instance resides.
+    * @param status Wait until instance in in this status.
+    * @param maxWaitInSec Maximum time to wait.
+    * @param periodInSec Interval between retries.
+    * @return RetryablePredicate That will check whether the Instance exists.
+    */
+   public static Predicate<Instance> awaitStatus(
+         InstanceApi instanceApi, Instance.Status status, long maxWaitInSec, long periodInSec) {
+      StatusUpdatedPredicate statusPredicate = new StatusUpdatedPredicate(instanceApi, status);
+      return retry(statusPredicate, maxWaitInSec, periodInSec, periodInSec, SECONDS);
+   }
+   
+   private static class StatusUpdatedPredicate implements Predicate<Instance> {
+      private InstanceApi instanceApi;
+      private Status status;
+
+      public StatusUpdatedPredicate(InstanceApi instanceApi, Instance.Status status) {
+         this.instanceApi = checkNotNull(instanceApi, "instanceApi must be defined");
+         this.status = checkNotNull(status, "status must be defined");
+      }
+
+      /**
+       * @return boolean Return true when the instance reaches status, false otherwise.
+       */
+      @Override
+      public boolean apply(Instance instance) {
+         checkNotNull(instance, "instance must be defined");
+         
+         if (status.equals(instance.getStatus())) {
+            return true;
+         }
+         else {
+            Instance instanceUpdated = instanceApi.get(instance.getId());
+            checkNotNull(instanceUpdated, "Instance %s not found.", instance.getId());
+            
+            return status.equals(instanceUpdated.getStatus());
+         }
+      }
+   }
+
+   private static class DeletedPredicate implements Predicate<Instance> {
+      private InstanceApi instanceApi;
+
+      public DeletedPredicate(InstanceApi instanceApi) {
+         this.instanceApi = checkNotNull(instanceApi, "instanceApi must be defined");
+      }
+
+      /**
+       * @return boolean Return true when the snapshot is deleted, false otherwise.
+       */
+      @Override
+      public boolean apply(Instance instance) {
+         checkNotNull(instance, "instance must be defined");
+
+         return instanceApi.get(instance.getId()) == null;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/utils/TroveUtils.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/utils/TroveUtils.java b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/utils/TroveUtils.java
new file mode 100644
index 0000000..dbc17f2
--- /dev/null
+++ b/apis/openstack-trove/src/main/java/org/jclouds/openstack/trove/v1/utils/TroveUtils.java
@@ -0,0 +1,107 @@
+/*
+ * 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.jclouds.openstack.trove.v1.utils;
+
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Resource;
+
+import org.jclouds.openstack.trove.v1.TroveApi;
+import org.jclouds.openstack.trove.v1.domain.Instance;
+import org.jclouds.openstack.trove.v1.features.InstanceApi;
+import org.jclouds.openstack.trove.v1.predicates.InstancePredicates;
+import org.jclouds.logging.Logger;
+
+import com.google.common.util.concurrent.Uninterruptibles;
+
+/**
+ * @author Zack Shoylev
+ * 
+ * Helper methods for dealing with instances that get created with errors.
+ */
+public class TroveUtils {
+   private final TroveApi api;
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   public TroveUtils(TroveApi api) {
+      this.api = api;
+   }
+
+   /**
+    * Create an ACTIVE operational instance.
+    * 
+    * @see InstanceApi#create(String, int, String)
+    * 
+    * @param zone
+    *           The instance zone or region.
+    * @param name
+    *           Instance name.
+    * @param flavorId
+    *           Id of the flavor to be used when creating the instance.
+    * @param size
+    *           Size of the instance.
+    * @return Instance object in active state or NULL.
+    */
+   public Instance getWorkingInstance(String zone, String name, String flavorId, int size) {
+      InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+      for (int retries = 0; retries < 10; retries++) {
+         Instance instance = null;
+         try {
+            instance = instanceApi.create(flavorId, size, name);
+         } catch (Exception e) {
+
+            Uninterruptibles.sleepUninterruptibly(15, TimeUnit.SECONDS);
+
+            logger.error(e.getStackTrace().toString());
+            continue;
+         }
+
+         Instance updatedInstance = awaitAvailable(instance, instanceApi);
+         if (updatedInstance != null) {
+            return updatedInstance;
+         }
+         instanceApi.delete(instance.getId());
+         InstancePredicates.awaitDeleted(instanceApi).apply(instance);
+         
+      }
+      return null;
+   }
+
+   /**
+    * This will return a small working instance.
+    * 
+    * @param zone The zone where the instance should be created.
+    * @return A working database instance.
+    */
+   public Instance getWorkingInstance(String zone) {
+      return getWorkingInstance(zone, UUID.randomUUID().toString(), "1", 1);
+   }
+
+   private Instance awaitAvailable(Instance instance, InstanceApi iapi) {
+      for (int n = 0; n < 100; n = n + 1) {
+         Instance updatedInstance = iapi.get(instance.getId());
+         if (updatedInstance.getStatus() == Instance.Status.ACTIVE)
+            return updatedInstance;
+         if (updatedInstance.getStatus() == Instance.Status.UNRECOGNIZED)
+            return null; // fast fail
+         Uninterruptibles.sleepUninterruptibly(15, TimeUnit.SECONDS);
+      }
+      return null;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/apis/openstack-trove/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
new file mode 100644
index 0000000..558658c
--- /dev/null
+++ b/apis/openstack-trove/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.jclouds.openstack.trove.v1.TroveApiMetadata

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/FlavorTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/FlavorTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/FlavorTest.java
new file mode 100644
index 0000000..0b9d1b1
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/FlavorTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.jclouds.openstack.trove.v1.domain;
+
+import org.jclouds.http.Uris;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.Link.Relation;
+import org.testng.annotations.Test;
+import com.google.common.collect.ImmutableList;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+@Test(groups = "unit", testName = "FlavorTest")
+public class FlavorTest {
+   public void testFlavorForId() {
+      Flavor flavor1 = forId(1);
+      Flavor flavor2 = forId(2);
+      assertEquals(flavor1.getId(), 1);
+      assertEquals(flavor1.getName(), "small");
+      assertFalse(flavor1.equals(flavor2));
+   }
+   
+   /**
+    * Creates a dummy Flavor when you need a Flavor with just the flavorId. 
+    * 
+    * 1. name  = small
+    * 2. ram   = 512
+    * 3. links = self, bookmark
+    */
+   public static Flavor forId(int flavorId) {       
+       return Flavor.builder()
+               .id(flavorId)
+               .name("small")
+               .ram(512)
+               .links( 
+                       ImmutableList.of(
+                               Link.create(Relation.SELF, Uris.uriBuilder("http://test1").build() ),
+                               Link.create(Relation.BOOKMARK, Uris.uriBuilder("http://test2").build() )
+                               ) ).build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/InstanceTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/InstanceTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/InstanceTest.java
new file mode 100644
index 0000000..d0cf6f2
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/InstanceTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.jclouds.openstack.trove.v1.domain;
+
+import org.jclouds.http.Uris;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.Link.Relation;
+import org.testng.annotations.Test;
+import com.google.common.collect.ImmutableList;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+@Test(groups = "unit", testName = "InstanceTest")
+public class InstanceTest {
+   public void testInstanceForId() {
+      Instance instance1 = forId("1");
+      Instance instance2 = forId("2");
+      assertEquals(instance1.getId(), "1");
+      assertEquals(instance1.getName(), "json");
+      assertFalse(instance1.equals(instance2));
+   }
+   
+   /**
+    * Creates a dummy Instance when you need an Instance with just the instanceId.
+    */
+   public static Instance forId(String instanceId) {       
+       return Instance.builder()
+               .id(instanceId)
+               .name("json")
+               .status(Instance.Status.ACTIVE)
+               .size(2)
+               .flavor( FlavorTest.forId(1) )
+               .links( 
+                       ImmutableList.of(
+                               Link.create(Relation.SELF, Uris.uriBuilder("http://test1").build() ),
+                               Link.create(Relation.BOOKMARK, Uris.uriBuilder("http://test2").build() )
+                               ) ).build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/UserTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/UserTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/UserTest.java
new file mode 100644
index 0000000..9edd6f8
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/domain/UserTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.jclouds.openstack.trove.v1.domain;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import org.testng.annotations.Test;
+import com.google.common.collect.ImmutableSet;
+
+@Test(groups = "unit", testName = "UserTest")
+public class UserTest {
+   public void testUserForName() {
+      User user1 = forName("1");
+      User user2 = forName("2");
+      assertEquals(user1.getName(), "1");
+      assertEquals(user2.getName(), "2");
+      assertFalse(user1.equals(user2));
+   }
+   
+   /**
+    * Creates a dummy User when you need an User with just the userName.
+    */
+   public static User forName(String userName) {       
+       return User.builder()
+               .name(userName)
+               .password("password")
+               .databases( 
+                       ImmutableSet.of(
+                               "db1",
+                               "db2"
+                               ) ).build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiExpectTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiExpectTest.java
new file mode 100644
index 0000000..d422e60
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiExpectTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.jclouds.openstack.trove.v1.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Set;
+
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiExpectTest;
+import org.testng.annotations.Test;
+
+/**
+ * Tests DatabaseApi Guice wiring and parsing
+ *
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "DatabaseApiExpectTest")
+public class DatabaseApiExpectTest extends BaseTroveApiExpectTest {
+
+   public void testCreateDatabaseSimple() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint)
+            .method("POST")
+            .payload(payloadFromResourceWithContentType("/database_create_simple_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(202).build() // response
+            ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.create("testingdb");
+      assertTrue(result);
+   }
+
+   public void testCreateDatabaseSimpleFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint)
+            .method("POST")
+            .payload(payloadFromResourceWithContentType("/database_create_simple_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(404).build() // response
+            ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.create("testingdb");
+      assertFalse(result);
+   }
+
+   public void testCreateDatabase() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint)
+            .method("POST")
+            .payload(payloadFromResourceWithContentType("/database_create_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(202).build() // response
+            ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.create("testingdb", "utf8", "utf8_general_ci");
+      assertTrue(result);
+   }
+
+   public void testCreateDatabaseFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint)
+            .method("POST")
+            .payload(payloadFromResourceWithContentType("/database_create_request.json", MediaType.APPLICATION_JSON))
+            .build(),
+            HttpResponse.builder().statusCode(404).build() // response
+            ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.create("testingdb", "utf8", "utf8_general_ci");
+      assertFalse(result);
+   }
+   
+   public void testDeleteDatabase() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases/db1");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) 
+            .method("DELETE")
+            .build(),
+            HttpResponse.builder().statusCode(202).build() // response
+            ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.delete("db1");
+      assertTrue(result);
+   }
+   
+   public void testDeleteDatabaseFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases/db1");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint) 
+            .method("DELETE")
+            .build(),
+            HttpResponse.builder().statusCode(404).build() // response
+            ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      boolean result = api.delete("db1");
+      assertFalse(result);
+   }
+   
+   public void testListDatabases() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/database_list.json")).build()
+      ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      List<String> databases = api.list().toList();
+      assertEquals(databases.size(), 5);
+      assertEquals(databases.iterator().next(), "anotherdb");
+   }
+   
+   public void testListDatabasesFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/instanceId-1234-5678/databases");
+      DatabaseApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).payload(payloadFromResource("/database_list.json")).build()
+      ).getDatabaseApiForZoneAndInstance("RegionOne", "instanceId-1234-5678");
+
+      Set<String> databases = api.list().toSet();
+      assertTrue(databases.isEmpty());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiLiveTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiLiveTest.java
new file mode 100644
index 0000000..c60ee7c
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/DatabaseApiLiveTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.jclouds.openstack.trove.v1.features;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jclouds.openstack.trove.v1.domain.Instance;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiLiveTest;
+import org.jclouds.openstack.trove.v1.utils.TroveUtils;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "live", testName = "DatabaseApiLiveTest")
+public class DatabaseApiLiveTest extends BaseTroveApiLiveTest {
+
+   // zone to instance
+   private static Map<String,List<Instance>> instancesToDelete = Maps.newHashMap();
+   // not deleting databases. they will be deleted when instances are deleted
+
+   @Override
+   @BeforeClass(groups = { "integration", "live" })
+   public void setup() {
+      super.setup();
+      TroveUtils utils = new TroveUtils(api);
+      for (String zone : api.getConfiguredZones()) {
+         // create instances
+         List<Instance> instanceList = Lists.newArrayList();
+         Instance first = utils.getWorkingInstance(zone, "first_database_testing_" + zone, "1", 1);
+         Instance second = utils.getWorkingInstance(zone, "second_database_testing_" + zone, "1", 1);
+         instanceList.add(first);
+         instanceList.add(second);
+         instancesToDelete.put(zone, instanceList);
+
+         DatabaseApi databaseApiFirst = api.getDatabaseApiForZoneAndInstance(zone, first.getId());
+         DatabaseApi databaseApiSecond = api.getDatabaseApiForZoneAndInstance(zone, second.getId());
+         databaseApiFirst.create("livetest_db1");
+         databaseApiFirst.create("livetest_db2");
+         databaseApiSecond.create("livetest_db3");
+      }
+   }
+
+   @Override
+   @AfterClass(groups = { "integration", "live" })
+   public void tearDown(){
+      for (String zone : api.getConfiguredZones()) {
+         InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+         for(Instance instance : instancesToDelete.get(zone)){
+            if( !instanceApi.delete(instance.getId() ) )
+               throw new RuntimeException("Could not delete a database instance after tests!");
+         }
+      }
+      super.tearDown();
+   }
+
+   @Test
+   public void testListDatabases() {
+      for (String zone : api.getConfiguredZones()) {
+         InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+         assertTrue(instanceApi.list().size() >= 2);
+         for(Instance instance : instancesToDelete.get(zone)) {
+            DatabaseApi databaseApi = api.getDatabaseApiForZoneAndInstance(zone, instance.getId());
+            if(!instance.getName().contains("database_testing"))continue;
+            assertTrue(databaseApi.list().size() >=1);
+            for(String database : databaseApi.list()){
+               assertNotNull(database);      
+            }
+         }  
+      }   
+   }
+
+   @Test
+   public void testDeleteDatabases() {
+      for (String zone : api.getConfiguredZones()) {
+         InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+         assertTrue(instanceApi.list().size() >= 2);
+         for(Instance instance : instancesToDelete.get(zone)) {
+            DatabaseApi databaseApi = api.getDatabaseApiForZoneAndInstance(zone, instance.getId());
+            if(!instance.getName().contains("database_testing"))continue;
+            assertTrue(databaseApi.list().size() >=1);
+            for(String database : databaseApi.list()){
+               assertNotNull(database);
+               assertTrue(database.equals("livetest_db1") || database.equals("livetest_db2") || database.equals("livetest_db3") );
+               assertTrue(databaseApi.delete(database));
+               assertTrue(databaseApi.create(database));
+            }
+         }  
+      }   
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiExpectTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiExpectTest.java
new file mode 100644
index 0000000..30c4b98
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiExpectTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.jclouds.openstack.trove.v1.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.net.URI;
+import java.util.Set;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.trove.v1.TroveApi;
+import org.jclouds.openstack.trove.v1.domain.Flavor;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiExpectTest;
+import org.testng.annotations.Test;
+
+/**
+ * Tests FlavorApi Guice wiring and parsing
+ *
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "FlavorApiExpectTest")
+public class FlavorApiExpectTest extends BaseTroveApiExpectTest {
+
+   public void testListFlavors() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/flavors");
+      FlavorApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/flavor_list.json")).build()
+      ).getFlavorApiForZone("RegionOne");
+
+      Set<? extends Flavor> flavors = api.list().toSet();
+      assertEquals(flavors.size(),6);
+      assertEquals(flavors.iterator().next().getRam(), 512);
+   }
+
+   public void testListFlavorsFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/flavors");
+      FlavorApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).build()
+      ).getFlavorApiForZone("RegionOne");
+
+      Set<? extends Flavor> flavors = api.list().toSet();
+      assertTrue(flavors.isEmpty());
+   }   
+
+   public void testGetFlavor() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/flavors/1");
+      FlavorApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/flavor_get.json")).build()
+      ).getFlavorApiForZone("RegionOne");
+
+      Flavor flavor = api.get(1);
+      assertEquals(flavor.getName(), "512MB Instance");
+      assertEquals(flavor.getId(), 1);
+      assertEquals(flavor.getRam(), 512);
+      assertEquals(flavor.getLinks().size(), 2);
+   }
+   
+   public void testGetFlavorByAccountId() {
+	      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/flavors/40806637803162");
+	      TroveApi redDwarfApi = requestsSendResponses(
+               keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess,
+               authenticatedGET().endpoint(endpoint).build(),
+               HttpResponse.builder().statusCode(200).payload(payloadFromResource("/flavor_list.json")).build() ); 
+	      FlavorApi api = redDwarfApi.getFlavorApiForZone("RegionOne");
+
+	      Set<? extends Flavor> flavors = api.list( redDwarfApi.getCurrentTenantId().get().getId() ).toSet();
+	      Flavor flavor = flavors.iterator().next();
+	      assertEquals(flavor.getName(), "512MB Instance");
+	      assertEquals(flavor.getId(), 1);
+	      assertEquals(flavor.getRam(), 512);
+	      assertEquals(flavor.getLinks().size(), 2);
+	   }
+
+   public void testGetFlavorFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/flavors/12312");
+      FlavorApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).build()
+      ).getFlavorApiForZone("RegionOne");
+
+      assertNull(api.get(12312));
+   }   
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiLiveTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiLiveTest.java
new file mode 100644
index 0000000..7d0eebe
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/FlavorApiLiveTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.jclouds.openstack.trove.v1.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import org.jclouds.openstack.trove.v1.domain.Flavor;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiLiveTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import com.google.common.collect.FluentIterable;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "live", testName = "FlavorApiLiveTest")
+public class FlavorApiLiveTest extends BaseTroveApiLiveTest {
+
+    @Override
+    @BeforeClass(groups = { "integration", "live" })
+    public void setup() {
+        super.setup();
+    }
+
+    private void checkFlavor(Flavor flavor) {
+        assertNotNull(flavor.getId(), "Id cannot be null for " + flavor);
+        assertNotNull(flavor.getName(), "Name cannot be null for " + flavor);
+    }
+
+    @Test
+    public void testListFlavorsByAccount() {
+        for (String zone : api.getConfiguredZones()) {
+            FlavorApi flavorApi = api.getFlavorApiForZone(zone);
+
+            FluentIterable<Flavor> response = flavorApi.list( api.getCurrentTenantId().get().getId() ); // tenant id, but referred to as account id. 
+            for (Flavor flavor : response) {
+                checkFlavor(flavor);
+            }  
+        }   
+    }
+
+    @Test
+    public void testListFlavorsByAccountWhenAccountIdNotFound() {
+        for (String zone : api.getConfiguredZones()) {
+            FlavorApi flavorApi = api.getFlavorApiForZone(zone);
+            assertTrue(flavorApi.list("9999").isEmpty());
+        }
+    }
+
+    @Test
+    public void testGetFlavor() {
+        for (String zone : api.getConfiguredZones()) {
+            FlavorApi flavorApi = api.getFlavorApiForZone(zone);           
+            for (Flavor flavor : flavorApi.list()) {
+                Flavor flavorFromGet = flavorApi.get(flavor.getId());
+                assertEquals(flavorFromGet.getId(), flavor.getId());
+                assertEquals(flavorFromGet.getRam(), flavor.getRam());
+                assertEquals(flavorFromGet.getName(), flavor.getName());
+                assertEquals(flavorFromGet.getLinks(), flavor.getLinks());
+            }
+        }
+    }
+
+    @Test
+    public void testGetFlavorWhenNotFound() {
+        for (String zone : api.getConfiguredZones()) {
+            FlavorApi flavorApi = api.getFlavorApiForZone(zone);
+            assertNull(flavorApi.get(9999));
+        }
+    }   
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiExpectTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiExpectTest.java
new file mode 100644
index 0000000..369c469
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiExpectTest.java
@@ -0,0 +1,217 @@
+/*
+ * 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.jclouds.openstack.trove.v1.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import java.net.URI;
+import java.util.Set;
+import javax.ws.rs.core.MediaType;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.trove.v1.domain.Instance;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiExpectTest;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+/**
+ * Tests InstanceApi Guice wiring and parsing
+ *
+ * @author Zack Shoylev
+ */
+@Test(groups = "unit", testName = "InstanceApiExpectTest")
+public class InstanceApiExpectTest extends BaseTroveApiExpectTest {
+    
+    public void testCreateInstance() {
+        URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances");
+        InstanceApi api = requestsSendResponses(
+                keystoneAuthWithUsernameAndPasswordAndTenantName,
+                responseWithKeystoneAccess,
+                authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+                .method("POST")
+                .payload(payloadFromResourceWithContentType("/instance_create_request.json", MediaType.APPLICATION_JSON))
+                .build(),
+                HttpResponse.builder().statusCode(200).payload(payloadFromResource("/instance_create.json")).build() // response
+                ).getInstanceApiForZone("RegionOne");
+
+        Instance instance = api.create("1", 2, "json_rack_instance");
+        assertEquals(instance.getSize(),2);
+        assertEquals(instance.getName(), "json_rack_instance");  
+    }
+    
+    @Test(expectedExceptions = ResourceNotFoundException.class)
+    public void testCreateInstanceFail() {
+        URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances");
+        InstanceApi api = requestsSendResponses(
+                keystoneAuthWithUsernameAndPasswordAndTenantName,
+                responseWithKeystoneAccess,
+                authenticatedGET().endpoint(endpoint) // bad naming convention, you should not be able to change the method to POST
+                .method("POST")
+                .payload(payloadFromResourceWithContentType("/instance_create_request.json", MediaType.APPLICATION_JSON))
+                .build(),
+                HttpResponse.builder().statusCode(404).payload(payloadFromResource("/instance_create.json")).build() // response
+                ).getInstanceApiForZone("RegionOne");
+
+        api.create("1", 2, "json_rack_instance");
+    }
+    
+    public void testDeleteInstance() {
+        URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/098653ba-218b-47ce-936a-e0b749101f81");
+        InstanceApi api = requestsSendResponses(
+                keystoneAuthWithUsernameAndPasswordAndTenantName,
+                responseWithKeystoneAccess,
+                authenticatedGET().endpoint(endpoint).method("DELETE").build(),
+                HttpResponse.builder().statusCode(202).build() // response
+                ).getInstanceApiForZone("RegionOne");
+
+        assertTrue( api.delete("098653ba-218b-47ce-936a-e0b749101f81") );
+    }
+    
+    public void testDeleteInstanceFail() {
+        URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/098653ba-218b-47ce-936a-e0b749101f81");
+        InstanceApi api = requestsSendResponses(
+                keystoneAuthWithUsernameAndPasswordAndTenantName,
+                responseWithKeystoneAccess,
+                authenticatedGET().endpoint(endpoint).method("DELETE").build(),
+                HttpResponse.builder().statusCode(404).build() // response
+                ).getInstanceApiForZone("RegionOne");
+
+        assertTrue( !api.delete("098653ba-218b-47ce-936a-e0b749101f81") );
+    }
+
+   
+   public void testListInstances() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances");
+      InstanceApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/instance_list.json")).build()
+      ).getInstanceApiForZone("RegionOne");
+
+      Set<? extends Instance> instances = api.list().toSet();
+      assertEquals(instances.size(),2);
+      assertEquals(instances.iterator().next().getSize(), 2);
+   }
+
+   public void testListInstancesFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances");
+      InstanceApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).build()
+      ).getInstanceApiForZone("RegionOne");
+
+      Set<? extends Instance> instances = api.list().toSet();
+      assertTrue(instances.isEmpty());
+   }   
+
+   public void testGetInstance() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/44b277eb-39be-4921-be31-3d61b43651d7");
+      InstanceApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/instance_get.json")).build()
+      ).getInstanceApiForZone("RegionOne");
+
+      Instance instance = api.get("44b277eb-39be-4921-be31-3d61b43651d7");
+      assertEquals(instance.getName(), "json_rack_instance");
+      assertEquals(instance.getId(), "44b277eb-39be-4921-be31-3d61b43651d7");
+      assertEquals(instance.getLinks().size(), 2);
+      assertEquals(instance.getHostname(), "e09ad9a3f73309469cf1f43d11e79549caf9acf2.rackspaceclouddb.com");
+   }
+   
+   public void testGetInstanceFail() {
+      URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/12312");
+      InstanceApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPasswordAndTenantName,
+            responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint).build(),
+            HttpResponse.builder().statusCode(404).build()
+      ).getInstanceApiForZone("RegionOne");
+
+      assertNull(api.get("12312"));
+   }  
+   
+   public void testEnableRootOnInstance() {
+       URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/44b277eb-39be-4921-be31-3d61b43651d7/root");
+       InstanceApi api = requestsSendResponses(
+             keystoneAuthWithUsernameAndPasswordAndTenantName,
+             responseWithKeystoneAccess,
+             authenticatedGET().method("POST").endpoint(endpoint).build(),
+             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/instance_root.json")).build()
+       ).getInstanceApiForZone("RegionOne");
+
+       String password = api.enableRoot("44b277eb-39be-4921-be31-3d61b43651d7");
+       assertEquals(password, "12345");
+    }
+   
+   public void testEnableRootOnInstanceFail() {
+       URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/44b277eb-39be-4921-be31-3d61b43651d7/root");
+       InstanceApi api = requestsSendResponses(
+             keystoneAuthWithUsernameAndPasswordAndTenantName,
+             responseWithKeystoneAccess,
+             authenticatedGET().method("POST").endpoint(endpoint).build(),
+             HttpResponse.builder().statusCode(404).payload(payloadFromResource("/instance_root.json")).build()
+       ).getInstanceApiForZone("RegionOne");
+
+       String password = api.enableRoot("44b277eb-39be-4921-be31-3d61b43651d7");
+       assertEquals(password, null);
+    }
+   
+   public void testIsRootInstance() {
+       URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/44b277eb-39be-4921-be31-3d61b43651d7/root");
+       InstanceApi api = requestsSendResponses(
+             keystoneAuthWithUsernameAndPasswordAndTenantName,
+             responseWithKeystoneAccess,
+             authenticatedGET().endpoint(endpoint).build(),
+             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/instance_is_rooted.json")).build()
+       ).getInstanceApiForZone("RegionOne");
+
+       boolean rooted = api.isRooted("44b277eb-39be-4921-be31-3d61b43651d7");
+       assertEquals(rooted, true);
+    }
+   
+   public void testIsRootInstanceFalse() {
+       URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/44b277eb-39be-4921-be31-3d61b43651d7/root");
+       InstanceApi api = requestsSendResponses(
+             keystoneAuthWithUsernameAndPasswordAndTenantName,
+             responseWithKeystoneAccess,
+             authenticatedGET().endpoint(endpoint).build(),
+             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/instance_is_rooted_false.json")).build()
+       ).getInstanceApiForZone("RegionOne");
+
+       Boolean rooted = api.isRooted("44b277eb-39be-4921-be31-3d61b43651d7");
+       assertEquals(rooted.booleanValue(), false);
+    }
+   
+   @Test(expectedExceptions = ResourceNotFoundException.class)  
+   public void testIsRootInstanceFail() {
+       URI endpoint = URI.create("http://172.16.0.1:8776/v1/3456/instances/44b277eb-39be-4921-be31-3d61b43651d7/root");
+       InstanceApi api = requestsSendResponses(
+             keystoneAuthWithUsernameAndPasswordAndTenantName,
+             responseWithKeystoneAccess,
+             authenticatedGET().endpoint(endpoint).build(),
+             HttpResponse.builder().statusCode(404).payload(payloadFromResource("/instance_is_rooted.json")).build()
+       ).getInstanceApiForZone("RegionOne");
+
+       Boolean rooted = api.isRooted("44b277eb-39be-4921-be31-3d61b43651d7");
+       assertNull(rooted);
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/6de84cb0/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiLiveTest.java b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiLiveTest.java
new file mode 100644
index 0000000..6de832a
--- /dev/null
+++ b/apis/openstack-trove/src/test/java/org/jclouds/openstack/trove/v1/features/InstanceApiLiveTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.jclouds.openstack.trove.v1.features;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.jclouds.openstack.trove.v1.domain.Instance;
+import org.jclouds.openstack.trove.v1.internal.BaseTroveApiLiveTest;
+import org.jclouds.openstack.trove.v1.utils.TroveUtils;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+/**
+ * @author Zack Shoylev
+ */
+@Test(groups = "live", testName = "InstanceApiLiveTest")
+public class InstanceApiLiveTest extends BaseTroveApiLiveTest {
+
+    private static Map<String,List<Instance>> created = Maps.newHashMap();
+    
+    @Override
+    @BeforeClass(groups = { "integration", "live" })
+    public void setup() {
+        super.setup();
+        TroveUtils utils= new TroveUtils(api);
+        for (String zone : api.getConfiguredZones()) {
+            List<Instance> zoneList = Lists.newArrayList();
+            InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+            zoneList.add(utils.getWorkingInstance(zone, "first_instance_testing_" + zone, "1", 1));
+            Instance second = utils.getWorkingInstance(zone, "second_instance_testing_" + zone, "1", 1);
+            instanceApi.enableRoot(second.getId());
+            zoneList.add(second);            
+            created.put(zone, zoneList);
+        }
+    }
+    
+    @Override
+    @AfterClass(groups = { "integration", "live" })
+    public void tearDown(){
+        for (String zone : api.getConfiguredZones()) {
+            InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+            for(Instance instance : created.get(zone)){
+                if( !instanceApi.delete(instance.getId() ) )
+                    throw new RuntimeException("Could not delete a database instance after tests!");
+            }
+        }
+        super.tearDown();
+    }
+
+    private void checkInstance(Instance instance) {
+        assertNotNull(instance.getId(), "Id cannot be null for " + instance);
+        checkArgument(instance.getSize() > 0, "Size must not be 0");
+    }
+
+    @Test
+    public void testListInstances() {
+        for (String zone : api.getConfiguredZones()) {
+            InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+            FluentIterable<Instance> response = instanceApi.list(); 
+            assertFalse(response.isEmpty());
+            for (Instance instance : response) {
+                checkInstance(instance);
+            }  
+        }   
+    }    
+
+    @Test
+    public void testGetInstance() {
+        for (String zone : api.getConfiguredZones()) {
+            InstanceApi instanceApi = api.getInstanceApiForZone(zone);           
+            for (Instance instance : instanceApi.list()) {
+                Instance instanceFromGet = instanceApi.get(instance.getId());
+                assertNotNull(instanceFromGet.getHostname());
+                assertNull(instance.getHostname());
+                assertEquals(instanceFromGet.getId(), instance.getId());
+                assertEquals(instanceFromGet.getName(), instance.getName());
+                assertEquals(instanceFromGet.getStatus(), instance.getStatus());
+                assertEquals(instanceFromGet.getFlavor(), instance.getFlavor());
+                assertEquals(instanceFromGet.getSize(), instance.getSize());
+                assertEquals(instanceFromGet.getLinks(), instance.getLinks());
+            }
+        }
+    }
+
+    @Test
+    public void testGetInstanceWhenNotFound() {
+        for (String zone : api.getConfiguredZones()) {
+            InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+            assertNull(instanceApi.get("9999"));
+        }
+    }   
+    
+    @Test
+    public void testGetRootStatus() {
+        for (String zone : api.getConfiguredZones()) {
+            InstanceApi instanceApi = api.getInstanceApiForZone(zone);
+            Iterator<Instance> iterator = instanceApi.list().iterator();
+            Instance first;
+            Instance second;
+            do {
+               first = iterator.next(); 
+            } while(!first.getName().contains("instance_testing"));
+            do {
+               second = iterator.next(); 
+            } while(!second.getName().contains("instance_testing"));
+            assertTrue(instanceApi.isRooted(first.getId()) || instanceApi.isRooted(second.getId()));
+        }
+    }
+}