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()));
+ }
+ }
+}