You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by an...@apache.org on 2018/09/12 04:25:21 UTC

[4/7] jclouds-labs git commit: [JCLOUDS-1430] Aliyun ECS

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/ECSTemplateBuilderLiveTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/ECSTemplateBuilderLiveTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/ECSTemplateBuilderLiveTest.java
new file mode 100644
index 0000000..6c0343b
--- /dev/null
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/ECSTemplateBuilderLiveTest.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.aliyun.ecs.compute;
+
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.compute.domain.OsFamily;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.internal.BaseTemplateBuilderLiveTest;
+import org.testng.annotations.Test;
+
+import java.util.Set;
+
+import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
+import static org.testng.Assert.assertEquals;
+
+@Test(groups = "live", testName = "ECSTemplateBuilderLiveTest")
+public class ECSTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
+
+   public ECSTemplateBuilderLiveTest() {
+      provider = "alibaba-ecs";
+   }
+
+   @Test
+   @Override
+   public void testDefaultTemplateBuilder() {
+      Template defaultTemplate = view.getComputeService().templateBuilder().build();
+      assert defaultTemplate.getImage().getOperatingSystem().getVersion().startsWith("7.") : defaultTemplate.getImage()
+            .getOperatingSystem().getVersion();
+      assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true);
+      assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.CENTOS);
+      assertEquals(getCores(defaultTemplate.getHardware()), 1.0d);
+   }
+
+   @Override
+   protected Set<String> getIso3166Codes() {
+      return ImmutableSet.of("US-CA", "US-VA", "DE", "JP", "ID-JK", "SG", "IN", "AU-NSW", "MY", "CN-HE", "CN-SH", "CN-ZJ", "CN-GD", "HK", "AE-DU");
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/ImageApiLiveTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/ImageApiLiveTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/ImageApiLiveTest.java
index 5fe5c3f..f9e0e66 100644
--- a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/ImageApiLiveTest.java
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/ImageApiLiveTest.java
@@ -20,14 +20,13 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.Iterables;
 import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiLiveTest;
 import org.jclouds.aliyun.ecs.domain.Image;
-import org.jclouds.aliyun.ecs.domain.internal.Regions;
+import org.jclouds.aliyun.ecs.domain.options.ListImagesOptions;
 import org.jclouds.aliyun.ecs.features.ImageApi;
 import org.testng.annotations.Test;
 
 import java.util.concurrent.atomic.AtomicInteger;
 
-import static org.jclouds.aliyun.ecs.domain.options.ListImagesOptions.Builder.imageIds;
-import static org.jclouds.aliyun.ecs.domain.options.PaginationOptions.Builder.pageNumber;
+import static org.jclouds.aliyun.ecs.domain.options.PaginationOptions.Builder.pageSize;
 import static org.testng.Assert.assertTrue;
 import static org.testng.util.Strings.isNullOrEmpty;
 
@@ -36,7 +35,7 @@ public class ImageApiLiveTest extends BaseECSComputeServiceApiLiveTest {
 
    public void testList() {
       final AtomicInteger found = new AtomicInteger(0);
-      assertTrue(Iterables.all(api().list(Regions.EU_CENTRAL_1.getName()).concat(), new Predicate<Image>() {
+      assertTrue(Iterables.all(api().list(TEST_REGION).concat(), new Predicate<Image>() {
          @Override
          public boolean apply(Image input) {
             found.incrementAndGet();
@@ -48,9 +47,9 @@ public class ImageApiLiveTest extends BaseECSComputeServiceApiLiveTest {
 
    public void testListWithOptions() {
       final AtomicInteger found = new AtomicInteger(0);
-      assertTrue(api().list(Regions.EU_CENTRAL_1.getName(),
-              imageIds("debian_8_09_64_20G_alibase_20170824.vhd")
-              .paginationOptions(pageNumber(3)))
+      assertTrue(api().list(TEST_REGION,
+              ListImagesOptions.Builder.imageName("debian_8_09_64_20G_alibase_20170824.vhd")
+              .paginationOptions(pageSize(1)))
               .firstMatch(new Predicate<Image>() {
                  @Override
                  public boolean apply(Image input) {

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/ImageApiMockTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/ImageApiMockTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/ImageApiMockTest.java
index e61b910..d206e8d 100644
--- a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/ImageApiMockTest.java
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/ImageApiMockTest.java
@@ -19,7 +19,6 @@ package org.jclouds.aliyun.ecs.compute.features;
 import com.google.common.collect.ImmutableMap;
 import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiMockTest;
 import org.jclouds.aliyun.ecs.domain.Image;
-import org.jclouds.aliyun.ecs.domain.internal.Regions;
 import org.testng.annotations.Test;
 
 import static com.google.common.collect.Iterables.isEmpty;
@@ -36,35 +35,35 @@ public class ImageApiMockTest extends BaseECSComputeServiceApiMockTest {
       server.enqueue(jsonResponse("/images-first.json"));
       server.enqueue(jsonResponse("/images-second.json"));
       server.enqueue(jsonResponse("/images-last.json"));
-      Iterable<Image> images = api.imageApi().list(Regions.EU_CENTRAL_1.getName()).concat();
+      Iterable<Image> images = api.imageApi().list(TEST_REGION).concat();
       assertEquals(size(images), 28); // Force the PagedIterable to advance
       assertEquals(server.getRequestCount(), 3);
-      assertSent(server, "GET", "DescribeImages", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()));
-      assertSent(server, "GET", "DescribeImages", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()), 2);
-      assertSent(server, "GET", "DescribeImages", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()), 3);
+      assertSent(server, "GET", "DescribeImages", ImmutableMap.of("RegionId", TEST_REGION));
+      assertSent(server, "GET", "DescribeImages", ImmutableMap.of("RegionId", TEST_REGION), 2);
+      assertSent(server, "GET", "DescribeImages", ImmutableMap.of("RegionId", TEST_REGION), 3);
    }
 
    public void testListImagesReturns404() {
       server.enqueue(response404());
-      Iterable<Image> images = api.imageApi().list(Regions.EU_CENTRAL_1.getName()).concat();
+      Iterable<Image> images = api.imageApi().list(TEST_REGION).concat();
       assertTrue(isEmpty(images));
       assertEquals(server.getRequestCount(), 1);
    }
 
    public void testListImagesWithOptions() throws InterruptedException {
       server.enqueue(jsonResponse("/images-first.json"));
-      Iterable<Image> images = api.imageApi().list(Regions.EU_CENTRAL_1.getName(), paginationOptions(pageNumber(1)));
+      Iterable<Image> images = api.imageApi().list(TEST_REGION, paginationOptions(pageNumber(1)));
       assertEquals(size(images), 10);
       assertEquals(server.getRequestCount(), 1);
-      assertSent(server, "GET", "DescribeImages", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()));
+      assertSent(server, "GET", "DescribeImages", ImmutableMap.of("RegionId", TEST_REGION));
    }
 
    public void testListImagesWithOptionsReturns404() throws InterruptedException {
       server.enqueue(response404());
-      Iterable<Image> images = api.imageApi().list(Regions.EU_CENTRAL_1.getName(), paginationOptions(pageNumber(2)));
+      Iterable<Image> images = api.imageApi().list(TEST_REGION, paginationOptions(pageNumber(2)));
       assertTrue(isEmpty(images));
       assertEquals(server.getRequestCount(), 1);
-      assertSent(server, "GET", "DescribeImages", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()), 2);
+      assertSent(server, "GET", "DescribeImages", ImmutableMap.of("RegionId", TEST_REGION), 2);
    }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/InstanceApiLiveTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/InstanceApiLiveTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/InstanceApiLiveTest.java
new file mode 100644
index 0000000..1b987fd
--- /dev/null
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/InstanceApiLiveTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.aliyun.ecs.compute.features;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.Uninterruptibles;
+import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiLiveTest;
+import org.jclouds.aliyun.ecs.domain.AvailableZone;
+import org.jclouds.aliyun.ecs.domain.Instance;
+import org.jclouds.aliyun.ecs.domain.InstanceRequest;
+import org.jclouds.aliyun.ecs.domain.InstanceStatus;
+import org.jclouds.aliyun.ecs.domain.InstanceType;
+import org.jclouds.aliyun.ecs.domain.SecurityGroupRequest;
+import org.jclouds.aliyun.ecs.domain.VPC;
+import org.jclouds.aliyun.ecs.domain.VPCRequest;
+import org.jclouds.aliyun.ecs.domain.VSwitch;
+import org.jclouds.aliyun.ecs.domain.VSwitchRequest;
+import org.jclouds.aliyun.ecs.domain.options.CreateInstanceOptions;
+import org.jclouds.aliyun.ecs.domain.options.CreateSecurityGroupOptions;
+import org.jclouds.aliyun.ecs.domain.options.ListInstancesOptions;
+import org.jclouds.aliyun.ecs.domain.options.ListVPCsOptions;
+import org.jclouds.aliyun.ecs.domain.options.ListVSwitchesOptions;
+import org.jclouds.aliyun.ecs.domain.regionscoped.RegionAndId;
+import org.jclouds.aliyun.ecs.features.InstanceApi;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.jclouds.aliyun.ecs.compute.strategy.CreateResourcesThenCreateNodes.DEFAULT_CIDR_BLOCK;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.util.Strings.isNullOrEmpty;
+
+@Test(groups = "live", testName = "InstanceApiLiveTest")
+public class InstanceApiLiveTest extends BaseECSComputeServiceApiLiveTest {
+
+   private String imageId = "ubuntu_16_0402_32_20G_alibase_20180409.vhd";
+   private String hostname = "jclouds-test";
+   private String instanceType = "ecs.t5-lc2m1.nano";
+   private String vpcId;
+   private String vSwitchId;
+   private String securityGroupId;
+   private String instanceId;
+   private String slashEncodedInstanceId;
+
+   @BeforeClass
+   public void setUp() {
+      VPCRequest vpcRequest = api.vpcApi().create(TEST_REGION);
+      vpcId = vpcRequest.getVpcId();
+      VPC vpc = api.vpcApi().list(TEST_REGION, ListVPCsOptions.Builder.vpcId(vpcId)).firstMatch(Predicates.notNull()).orNull();
+      while (vpc == null || vpc.status() == VPC.Status.PENDING) {
+         vpc = api.vpcApi().list(TEST_REGION, ListVPCsOptions.Builder.vpcId(vpcId)).firstMatch(Predicates.notNull()).orNull();
+         Uninterruptibles.sleepUninterruptibly(2, TimeUnit.SECONDS);
+      }
+
+      VSwitchRequest vSwitchRequest = api.vSwitchApi().create(TEST_ZONE, DEFAULT_CIDR_BLOCK, vpcId);
+      vSwitchId = vSwitchRequest.getVSwitchId();
+      VSwitch vSwitch = api.vSwitchApi().list(TEST_REGION, ListVSwitchesOptions.Builder.vSwitchId(vSwitchId)).firstMatch(Predicates.notNull()).orNull();
+      while (vSwitch == null || vSwitch.status() == VSwitch.Status.PENDING) {
+         vSwitch = api.vSwitchApi().list(TEST_REGION, ListVSwitchesOptions.Builder.vSwitchId(vSwitchId)).firstMatch(Predicates.notNull()).orNull();
+         Uninterruptibles.sleepUninterruptibly(2, TimeUnit.SECONDS);
+      }
+
+      SecurityGroupRequest request = api.securityGroupApi().create(TEST_REGION,
+              CreateSecurityGroupOptions.Builder
+                      .securityGroupName(InstanceApiLiveTest.class.getSimpleName())
+              .vpcId(vpcId)
+      );
+      securityGroupId = request.getSecurityGroupId();
+   }
+
+   @AfterClass(alwaysRun = true)
+   public void tearDown() {
+      if (instanceId != null) {
+         api().delete(instanceId);
+      }
+
+      if (securityGroupId != null) {
+         api.securityGroupApi().delete(TEST_REGION, securityGroupId);
+      }
+
+      if (vSwitchId != null) {
+         api.vSwitchApi().delete(TEST_REGION, vSwitchId);
+      }
+
+      if (vpcId != null) {
+         api.vpcApi().delete(TEST_REGION, vpcId);
+      }
+   }
+
+   public void testListInstanceTypeByAvailableZone() {
+      final AtomicInteger found = new AtomicInteger(0);
+      assertTrue(Iterables.all(api().listInstanceTypesByAvailableZone(TEST_REGION), new Predicate<AvailableZone>() {
+         @Override
+         public boolean apply(AvailableZone input) {
+            found.incrementAndGet();
+            return !input.availableResources().isEmpty();
+         }
+      }), "All available zones must have the 'id' field populated");
+      assertTrue(found.get() > 0, "Expected some instance type to be returned");
+   }
+
+   public void testListInstanceType() {
+      final AtomicInteger found = new AtomicInteger(0);
+      assertTrue(Iterables.all(api().listTypes(), new Predicate<InstanceType>() {
+         @Override
+         public boolean apply(InstanceType input) {
+            found.incrementAndGet();
+            return !isNullOrEmpty(input.id());
+         }
+      }), "All instance types must have the 'id' field populated");
+      assertTrue(found.get() > 0, "Expected some instance type to be returned");
+   }
+
+   @Test(groups = "live", dependsOnMethods = "testListInstanceType")
+   public void testListInstance() {
+      final AtomicInteger found = new AtomicInteger(0);
+      assertTrue(Iterables.all(api().list(TEST_REGION).concat(), new Predicate<Instance>() {
+         @Override
+         public boolean apply(Instance input) {
+            found.incrementAndGet();
+            return !isNullOrEmpty(input.id());
+         }
+      }), "All instances must have the 'id' field populated");
+   }
+
+   @Test(groups = "live")
+   public void testCreate() {
+      InstanceRequest instanceRequest = api().create(TEST_REGION, imageId, securityGroupId, hostname, instanceType,
+            CreateInstanceOptions.Builder.vSwitchId(vSwitchId));
+      instanceId = instanceRequest.getInstanceId();
+      slashEncodedInstanceId = RegionAndId.slashEncodeRegionAndId(TEST_REGION, instanceId);
+      assertNotNull(instanceId, "Instance id must not be null");
+   }
+
+   @Test(groups = "live", dependsOnMethods = "testCreate")
+   public void testGet() {
+      Instance instance = Iterables.getOnlyElement(api().list(TEST_REGION,
+              ListInstancesOptions.Builder.instanceIds(instanceId)));
+      assertNotNull(instance.id(), "Instance must not be null");
+   }
+
+   @Test(groups = "live", dependsOnMethods = "testCreate")
+   public void testListInstanceStatus() {
+      final AtomicInteger found = new AtomicInteger(0);
+      assertTrue(Iterables.all(api().listInstanceStatus(TEST_REGION).concat(), new Predicate<InstanceStatus>() {
+         @Override
+         public boolean apply(InstanceStatus input) {
+            found.incrementAndGet();
+            return !isNullOrEmpty(input.instanceId());
+         }
+      }), "All instance status must have the 'instance id' field populated");
+   }
+
+   @Test(groups = "live", dependsOnMethods = "testGet")
+   public void testStartInstance() {
+      api().powerOn(instanceId);
+      assertTrue(instanceRunningPredicate.apply(slashEncodedInstanceId));
+   }
+
+   @Test(groups = "live", dependsOnMethods = "testStartInstance")
+   public void testStopInstance() {
+      api().powerOff(instanceId);
+      assertTrue(instanceSuspendedPredicate.apply(slashEncodedInstanceId));
+   }
+
+   private InstanceApi api() {
+      return api.instanceApi();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/InstanceApiMockTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/InstanceApiMockTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/InstanceApiMockTest.java
new file mode 100644
index 0000000..95609b9
--- /dev/null
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/InstanceApiMockTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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.aliyun.ecs.compute.features;
+
+import com.google.common.collect.Iterables;
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiMockTest;
+import org.jclouds.aliyun.ecs.domain.AvailableZone;
+import org.jclouds.aliyun.ecs.domain.Instance;
+import org.jclouds.aliyun.ecs.domain.InstanceStatus;
+import org.jclouds.aliyun.ecs.domain.InstanceType;
+import org.jclouds.aliyun.ecs.domain.options.CreateInstanceOptions;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+import static com.google.common.collect.Iterables.isEmpty;
+import static com.google.common.collect.Iterables.size;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+@Test(groups = "unit", testName = "InstanceApiMockTest", singleThreaded = true)
+public class InstanceApiMockTest extends BaseECSComputeServiceApiMockTest {
+
+   public void testListInstances() throws InterruptedException {
+      server.enqueue(jsonResponse("/instances-first.json"));
+      server.enqueue(jsonResponse("/instances-last.json"));
+
+      Iterable<Instance> instances = api.instanceApi().list(TEST_REGION).concat();
+      assertEquals(size(instances), 20); // Force the PagedIterable to advance
+      assertEquals(server.getRequestCount(), 2);
+      assertSent(server, "GET", "DescribeInstances");
+      assertSent(server, "GET", "DescribeInstances", 2);
+   }
+
+   public void testListInstancesReturns404() throws InterruptedException {
+      server.enqueue(response404());
+      Iterable<Instance> instances = api.instanceApi().list(TEST_REGION).concat();
+      assertTrue(isEmpty(instances));
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "DescribeInstances");
+   }
+
+   public void testListInstanceTypes() throws InterruptedException {
+      server.enqueue(jsonResponse("/instanceTypes.json"));
+
+      List<InstanceType> instanceTypes = api.instanceApi().listTypes();
+      assertEquals(size(instanceTypes), 308);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "DescribeInstanceTypes");
+   }
+
+   public void testListInstanceTypesReturns404() throws InterruptedException {
+      server.enqueue(response404());
+      List<InstanceType> instanceTypes = api.instanceApi().listTypes();
+      assertTrue(isEmpty(instanceTypes));
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "DescribeInstanceTypes");
+   }
+
+   public void testListInstanceTypesByAvailableZone() throws InterruptedException {
+      server.enqueue(jsonResponse("/availableZones.json"));
+
+      List<AvailableZone> availableZones = api.instanceApi().listInstanceTypesByAvailableZone(TEST_REGION);
+      assertEquals(size(availableZones), 2);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "DescribeAvailableResource");
+   }
+
+   public void testListInstanceTypesByAvailableZoneReturns404() throws InterruptedException {
+      server.enqueue(response404());
+      List<AvailableZone> availableZones = api.instanceApi().listInstanceTypesByAvailableZone(TEST_REGION);
+      assertTrue(isEmpty(availableZones));
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "DescribeAvailableResource");
+   }
+
+   public void testCreateInstance() throws InterruptedException {
+      server.enqueue(new MockResponse().setResponseCode(200).setBody(
+                      "{" +
+                      "    \"RequestId\": \"04F0F334-1335-436C-A1D7-6C044FE73368\"," +
+                      "    \"InstanceId\": \"i-instance1\"" +
+                      "}"));
+      api.instanceApi().create(TEST_REGION,
+              "test",
+              "SecurityGroupId",
+              "Hostname",
+              "InstanceType"
+      );
+      assertSent(server, "POST", "CreateInstance");
+   }
+
+   public void testCreateInstanceWithInstanceName() throws InterruptedException {
+      server.enqueue(new MockResponse().setResponseCode(200).setBody(
+                      "{" +
+                      "    \"RequestId\": \"04F0F334-1335-436C-A1D7-6C044FE73368\"," +
+                      "    \"InstanceId\": \"i-instance1\"" +
+                      "}"));
+      api.instanceApi().create(TEST_REGION,
+              "test",
+              "SecurityGroupId",
+              "Hostname",
+              "InstanceType",
+              CreateInstanceOptions.Builder.instanceName("jclouds")
+      );
+      assertSent(server, "POST", "CreateInstance");
+   }
+
+   public void testAllocatePublicIpAddress() throws InterruptedException {
+      server.enqueue(new MockResponse().setResponseCode(200).setBody(
+                      "{" +
+                      "    \"RequestId\": \"F2EF6A3B-E345-46B9-931E-0EA094818567\"," +
+                      "    \"IpAddress\": \"10.1.149.159\"" +
+                      "}"));
+      api.instanceApi().create(TEST_REGION,
+              "test",
+              "SecurityGroupId",
+              "Hostname",
+              "InstanceType"
+      );
+      assertSent(server, "POST", "CreateInstance");
+   }
+
+   public void testGetStatus() throws Exception {
+      server.enqueue(jsonResponse("/instanceStatus.json"));
+      Iterable<InstanceStatus> instanceStatuses = api.instanceApi().listInstanceStatus("12345").concat();
+      assertSent(server, "GET", "DescribeInstanceStatus");
+      assertNotNull(instanceStatuses);
+   }
+
+   public void testGetStatusReturns404() throws InterruptedException {
+      server.enqueue(response404());
+      Iterable<InstanceStatus> instanceStatuses = api.instanceApi().listInstanceStatus("12345").concat();
+      assertTrue(Iterables.isEmpty(instanceStatuses));
+      assertSent(server, "GET", "DescribeInstanceStatus");
+   }
+
+   public void testDeleteInstance() throws Exception {
+      server.enqueue(new MockResponse().setResponseCode(200).setBody(
+              "{" +
+              "    \"RequestId\": \"928E2273-5715-46B9-A730-238DC996A533\"" +
+              "}"));
+      api.instanceApi().delete("instanceId");
+      assertSent(server, "POST", "DeleteInstance");
+   }
+
+   public void testDeleteInstanceReturns404() throws Exception {
+      server.enqueue(response404());
+      api.instanceApi().delete("instanceId");
+      assertSent(server, "POST", "DeleteInstance");
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/RegionAndZoneApiMockTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/RegionAndZoneApiMockTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/RegionAndZoneApiMockTest.java
index e116845..46badaf 100644
--- a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/RegionAndZoneApiMockTest.java
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/RegionAndZoneApiMockTest.java
@@ -19,7 +19,6 @@ package org.jclouds.aliyun.ecs.compute.features;
 import com.google.common.collect.ImmutableMap;
 import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiMockTest;
 import org.jclouds.aliyun.ecs.domain.Region;
-import org.jclouds.aliyun.ecs.domain.internal.Regions;
 import org.jclouds.aliyun.ecs.domain.Zone;
 import org.testng.annotations.Test;
 
@@ -51,18 +50,18 @@ public class RegionAndZoneApiMockTest extends BaseECSComputeServiceApiMockTest {
 
    public void testListZones() throws InterruptedException {
       server.enqueue(jsonResponse("/zones.json"));
-      List<Zone> zones = api.regionAndZoneApi().describeZones(Regions.EU_CENTRAL_1.getName());
+      List<Zone> zones = api.regionAndZoneApi().describeZones(TEST_REGION);
       assertEquals(size(zones), 2);
       assertEquals(server.getRequestCount(), 1);
-      assertSent(server, "GET", "DescribeZones", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()));
+      assertSent(server, "GET", "DescribeZones", ImmutableMap.of("RegionId", TEST_REGION));
    }
 
    public void testListZonesReturns404() throws InterruptedException {
       server.enqueue(response404());
-      List<Zone> zones = api.regionAndZoneApi().describeZones(Regions.EU_CENTRAL_1.getName());
+      List<Zone> zones = api.regionAndZoneApi().describeZones(TEST_REGION);
       assertTrue(isEmpty(zones));
       assertEquals(server.getRequestCount(), 1);
-      assertSent(server, "GET", "DescribeZones", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()));
+      assertSent(server, "GET", "DescribeZones", ImmutableMap.of("RegionId", TEST_REGION));
    }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SecurityGroupApiLiveTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SecurityGroupApiLiveTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SecurityGroupApiLiveTest.java
index 5c76fc5..6fde29e 100644
--- a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SecurityGroupApiLiveTest.java
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SecurityGroupApiLiveTest.java
@@ -21,7 +21,6 @@ import com.google.common.collect.Iterables;
 import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiLiveTest;
 import org.jclouds.aliyun.ecs.domain.IpProtocol;
 import org.jclouds.aliyun.ecs.domain.Permission;
-import org.jclouds.aliyun.ecs.domain.internal.Regions;
 import org.jclouds.aliyun.ecs.domain.SecurityGroup;
 import org.jclouds.aliyun.ecs.domain.SecurityGroupRequest;
 import org.jclouds.aliyun.ecs.domain.options.CreateSecurityGroupOptions;
@@ -46,7 +45,7 @@ public class SecurityGroupApiLiveTest extends BaseECSComputeServiceApiLiveTest {
 
    @BeforeClass
    public void setUp() {
-      SecurityGroupRequest request = api().create(Regions.EU_CENTRAL_1.getName(),
+      SecurityGroupRequest request = api().create(TEST_REGION,
             CreateSecurityGroupOptions.Builder
                   .securityGroupName("jclouds-test")
       );
@@ -56,24 +55,24 @@ public class SecurityGroupApiLiveTest extends BaseECSComputeServiceApiLiveTest {
    @AfterClass
    public void tearDown() {
       if (securityGroupId != null) {
-         api().delete(Regions.EU_CENTRAL_1.getName(), securityGroupId);
+         api().delete(TEST_REGION, securityGroupId);
       }
    }
 
    public void testAddRules() {
-      api().addInboundRule(Regions.EU_CENTRAL_1.getName(), securityGroupId, IpProtocol.TCP, TEST_PORT_RANGE, INTERNET);
+      api().addInboundRule(TEST_REGION, securityGroupId, IpProtocol.TCP, TEST_PORT_RANGE, INTERNET);
    }
 
    @Test(groups = "live", dependsOnMethods = "testAddRules")
    public void testGet() {
-      Permission permission = Iterables.getOnlyElement(api().get(Regions.EU_CENTRAL_1.getName(), securityGroupId));
+      Permission permission = Iterables.getOnlyElement(api().get(TEST_REGION, securityGroupId));
       checkPermission(permission);
    }
 
    @Test(groups = "live", dependsOnMethods = "testGet")
    public void testList() {
       final AtomicInteger found = new AtomicInteger(0);
-      assertTrue(Iterables.all(api().list(Regions.EU_CENTRAL_1.getName()).concat(), new Predicate<SecurityGroup>() {
+      assertTrue(Iterables.all(api().list(TEST_REGION).concat(), new Predicate<SecurityGroup>() {
          @Override
          public boolean apply(SecurityGroup input) {
             found.incrementAndGet();

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SecurityGroupApiMockTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SecurityGroupApiMockTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SecurityGroupApiMockTest.java
index 46aa76b..a7999a3 100644
--- a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SecurityGroupApiMockTest.java
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SecurityGroupApiMockTest.java
@@ -18,7 +18,6 @@ package org.jclouds.aliyun.ecs.compute.features;
 
 import com.google.common.collect.ImmutableMap;
 import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiMockTest;
-import org.jclouds.aliyun.ecs.domain.internal.Regions;
 import org.jclouds.aliyun.ecs.domain.SecurityGroup;
 import org.testng.annotations.Test;
 
@@ -35,35 +34,35 @@ public class SecurityGroupApiMockTest extends BaseECSComputeServiceApiMockTest {
    public void testListSecurityGroups() throws InterruptedException {
       server.enqueue(jsonResponse("/securitygroups-first.json"));
       server.enqueue(jsonResponse("/securitygroups-last.json"));
-      Iterable<SecurityGroup> securitygroups = api.securityGroupApi().list(Regions.EU_CENTRAL_1.getName()).concat();
+      Iterable<SecurityGroup> securitygroups = api.securityGroupApi().list(TEST_REGION).concat();
       assertEquals(size(securitygroups), 7); // Force the PagedIterable to advance
       assertEquals(server.getRequestCount(), 2);
-      assertSent(server, "GET", "DescribeSecurityGroups", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()));
-      assertSent(server, "GET", "DescribeSecurityGroups", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()), 2);
+      assertSent(server, "GET", "DescribeSecurityGroups", ImmutableMap.of("RegionId", TEST_REGION));
+      assertSent(server, "GET", "DescribeSecurityGroups", ImmutableMap.of("RegionId", TEST_REGION), 2);
    }
 
    public void testListSecurityGroupsReturns404() throws InterruptedException {
       server.enqueue(response404());
-      Iterable<SecurityGroup> securitygroups = api.securityGroupApi().list(Regions.EU_CENTRAL_1.getName()).concat();
+      Iterable<SecurityGroup> securitygroups = api.securityGroupApi().list(TEST_REGION).concat();
       assertTrue(isEmpty(securitygroups));
       assertEquals(server.getRequestCount(), 1);
-      assertSent(server, "GET", "DescribeSecurityGroups", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()));
+      assertSent(server, "GET", "DescribeSecurityGroups", ImmutableMap.of("RegionId", TEST_REGION));
    }
 
    public void testListSecurityGroupsWithOptions() throws InterruptedException {
       server.enqueue(jsonResponse("/securitygroups-first.json"));
-      Iterable<SecurityGroup> securitygroups = api.securityGroupApi().list(Regions.EU_CENTRAL_1.getName(), paginationOptions(pageNumber(1).pageSize(5)));
+      Iterable<SecurityGroup> securitygroups = api.securityGroupApi().list(TEST_REGION, paginationOptions(pageNumber(1).pageSize(5)));
       assertEquals(size(securitygroups), 5);
       assertEquals(server.getRequestCount(), 1);
-      assertSent(server, "GET", "DescribeSecurityGroups", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()), 1);
+      assertSent(server, "GET", "DescribeSecurityGroups", ImmutableMap.of("RegionId", TEST_REGION), 1);
    }
 
    public void testListSecurityGroupsWithOptionsReturns404() throws InterruptedException {
       server.enqueue(response404());
-      Iterable<SecurityGroup> securitygroups = api.securityGroupApi().list(Regions.EU_CENTRAL_1.getName(), paginationOptions(pageNumber(2)));
+      Iterable<SecurityGroup> securitygroups = api.securityGroupApi().list(TEST_REGION, paginationOptions(pageNumber(2)));
       assertTrue(isEmpty(securitygroups));
       assertEquals(server.getRequestCount(), 1);
-      assertSent(server, "GET", "DescribeSecurityGroups", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()), 2);
+      assertSent(server, "GET", "DescribeSecurityGroups", ImmutableMap.of("RegionId", TEST_REGION), 2);
    }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SshKeyPairApiLiveTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SshKeyPairApiLiveTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SshKeyPairApiLiveTest.java
index 85ceee5..632e06e 100644
--- a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SshKeyPairApiLiveTest.java
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SshKeyPairApiLiveTest.java
@@ -21,9 +21,8 @@ import com.google.common.collect.Iterables;
 import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiLiveTest;
 import org.jclouds.aliyun.ecs.domain.KeyPair;
 import org.jclouds.aliyun.ecs.domain.KeyPairRequest;
-import org.jclouds.aliyun.ecs.domain.internal.Regions;
 import org.jclouds.aliyun.ecs.features.SshKeyPairApi;
-import org.jclouds.ssh.SshKeys;
+import org.jclouds.compute.ComputeTestUtils;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -43,22 +42,22 @@ public class SshKeyPairApiLiveTest extends BaseECSComputeServiceApiLiveTest {
 
    @BeforeClass
    public void setUp() {
-      KeyPairRequest request = api().create(Regions.EU_CENTRAL_1.getName(), keyPairName);
+      KeyPairRequest request = api().create(TEST_REGION, keyPairName);
       assertNotNull(request.getRequestId());
    }
 
    @AfterClass
    public void tearDown() {
       if (keyPairName != null) {
-         api().delete(Regions.EU_CENTRAL_1.getName(), keyPairName);
+         api().delete(TEST_REGION, keyPairName);
       }
    }
 
    public void testImport() {
       String importedKeyPairName = keyPairName  + new Random().nextInt(1024);
       KeyPair imported = api().importKeyPair(
-              Regions.EU_CENTRAL_1.getName(),
-              SshKeys.generate().get("public"),
+              TEST_REGION,
+              ComputeTestUtils.setupKeyPair().get("public"), //SshKeys.generate().get("public"),
               importedKeyPairName);
       assertEquals(imported.name(), importedKeyPairName);
       assertNotNull(imported.privateKeyBody());
@@ -67,7 +66,7 @@ public class SshKeyPairApiLiveTest extends BaseECSComputeServiceApiLiveTest {
 
    public void testList() {
       final AtomicInteger found = new AtomicInteger(0);
-      assertTrue(Iterables.all(api().list(Regions.EU_CENTRAL_1.getName()).concat(), new Predicate<KeyPair>() {
+      assertTrue(Iterables.all(api().list(TEST_REGION).concat(), new Predicate<KeyPair>() {
          @Override
          public boolean apply(KeyPair input) {
             found.incrementAndGet();

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SshKeyPairApiMockTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SshKeyPairApiMockTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SshKeyPairApiMockTest.java
index 23c21ad..78f5a39 100644
--- a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SshKeyPairApiMockTest.java
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/SshKeyPairApiMockTest.java
@@ -20,7 +20,6 @@ import com.google.common.collect.ImmutableMap;
 import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiMockTest;
 import org.jclouds.aliyun.ecs.domain.KeyPair;
 import org.jclouds.aliyun.ecs.domain.KeyPairRequest;
-import org.jclouds.aliyun.ecs.domain.internal.Regions;
 import org.jclouds.aliyun.ecs.domain.Request;
 import org.jclouds.aliyun.ecs.domain.options.ListKeyPairsOptions;
 import org.jclouds.aliyun.ecs.domain.options.PaginationOptions;
@@ -37,37 +36,37 @@ public class SshKeyPairApiMockTest extends BaseECSComputeServiceApiMockTest {
 
    public void testCreateSshKey() throws InterruptedException {
       server.enqueue(jsonResponse("/keypair-create-res.json"));
-      KeyPairRequest keyPairRequest = api.sshKeyPairApi().create(Regions.EU_CENTRAL_1.getName(), "jclouds");
+      KeyPairRequest keyPairRequest = api.sshKeyPairApi().create(TEST_REGION, "jclouds");
       assertEquals(keyPairRequest, objectFromResource("/keypair-create-res.json", KeyPairRequest.class));
       assertEquals(server.getRequestCount(), 1);
-      assertSent(server, "POST", "CreateKeyPair", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()));
+      assertSent(server, "POST", "CreateKeyPair", ImmutableMap.of("RegionId", TEST_REGION));
    }
 
    public void testDeleteSshKey() throws InterruptedException {
       server.enqueue(jsonResponse("/keypair-delete-res.json"));
-      Request delete = api.sshKeyPairApi().delete(Regions.EU_CENTRAL_1.getName());
+      Request delete = api.sshKeyPairApi().delete(TEST_REGION);
       assertEquals(delete, objectFromResource("/keypair-delete-res.json", Request.class));
       assertEquals(server.getRequestCount(), 1);
-      assertSent(server, "POST", "DeleteKeyPairs", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()));
+      assertSent(server, "POST", "DeleteKeyPairs", ImmutableMap.of("RegionId", TEST_REGION));
    }
 
    public void testImportSshKey() throws InterruptedException {
       server.enqueue(jsonResponse("/keypair-import-res.json"));
       KeyPair keyPair = api.sshKeyPairApi().importKeyPair(
-              Regions.EU_CENTRAL_1.getName(),
+              TEST_REGION,
                             "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCdgcoNzH4hCc0j3b4MuG503L/J54uyFvwCAOu8vSsYuLpJ4AEyEOv+T0SfdF605fK6GYXA16Rxk3lrPt7mfKGNtXR0Ripbv7Zc6PvCRorwgj/cjh/45miozjrkXAiHD1GFZycfbi4YsoWAqZj7W4mwtctmhrYM0FPdya2XoRpVy89N+A5Xo4Xtd6EZn6JGEKQM5+kF2aL3ggy0od/DqjuEVYwZoyTe1RgUTXZSU/Woh7WMhsRHbqd3eYz4s6ac8n8IJPGKtUaQeqUtH7OK6NRYXVypUrkqNlwdNYZAwrjXg/x5T3D+bo11LENASRt9OJ2OkmRSTqRxBeDkhnVauWK/",
               "jclouds"
       );
       assertEquals(keyPair, objectFromResource("/keypair-import-res.json", KeyPair.class));
       assertEquals(server.getRequestCount(), 1);
-      assertSent(server, "POST", "ImportKeyPair", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()));
+      assertSent(server, "POST", "ImportKeyPair", ImmutableMap.of("RegionId", TEST_REGION));
    }
 
    public void testListImages() throws InterruptedException {
       server.enqueue(jsonResponse("/keypairs-first.json"));
       server.enqueue(jsonResponse("/keypairs-last.json"));
 
-      Iterable<KeyPair> keypairs = api.sshKeyPairApi().list(Regions.EU_CENTRAL_1.getName()).concat();
+      Iterable<KeyPair> keypairs = api.sshKeyPairApi().list(TEST_REGION).concat();
       assertEquals(size(keypairs), 12);
       assertEquals(server.getRequestCount(), 2);
       assertSent(server, "GET", "DescribeKeyPairs");
@@ -76,7 +75,7 @@ public class SshKeyPairApiMockTest extends BaseECSComputeServiceApiMockTest {
 
    public void testListKeyPairsReturns404() {
       server.enqueue(response404());
-      Iterable<KeyPair> keypairs = api.sshKeyPairApi().list(Regions.EU_CENTRAL_1.getName()).concat();
+      Iterable<KeyPair> keypairs = api.sshKeyPairApi().list(TEST_REGION).concat();
       assertTrue(isEmpty(keypairs));
       assertEquals(server.getRequestCount(), 1);
    }
@@ -84,7 +83,7 @@ public class SshKeyPairApiMockTest extends BaseECSComputeServiceApiMockTest {
    public void testListKeyPairsWithOptions() throws InterruptedException {
       server.enqueue(jsonResponse("/keypairs-first.json"));
 
-      IterableWithMarker<KeyPair> keypairs = api.sshKeyPairApi().list(Regions.EU_CENTRAL_1.getName(), ListKeyPairsOptions.Builder
+      IterableWithMarker<KeyPair> keypairs = api.sshKeyPairApi().list(TEST_REGION, ListKeyPairsOptions.Builder
               .paginationOptions(PaginationOptions.Builder.pageNumber(1)));
 
       assertEquals(size(keypairs), 10);
@@ -96,7 +95,7 @@ public class SshKeyPairApiMockTest extends BaseECSComputeServiceApiMockTest {
    public void testListKeyPairsWithOptionsReturns404() throws InterruptedException {
       server.enqueue(response404());
 
-      IterableWithMarker<KeyPair> keypairs = api.sshKeyPairApi().list(Regions.EU_CENTRAL_1.getName(), ListKeyPairsOptions.Builder
+      IterableWithMarker<KeyPair> keypairs = api.sshKeyPairApi().list(TEST_REGION, ListKeyPairsOptions.Builder
               .paginationOptions(PaginationOptions.Builder.pageNumber(2)));
 
       assertTrue(isEmpty(keypairs));

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/TagApiLiveTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/TagApiLiveTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/TagApiLiveTest.java
index 854b494..cd07ae2 100644
--- a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/TagApiLiveTest.java
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/TagApiLiveTest.java
@@ -18,7 +18,6 @@ package org.jclouds.aliyun.ecs.compute.features;
 
 import com.google.common.base.Predicate;
 import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiLiveTest;
-import org.jclouds.aliyun.ecs.domain.internal.Regions;
 import org.jclouds.aliyun.ecs.domain.Request;
 import org.jclouds.aliyun.ecs.domain.SecurityGroupRequest;
 import org.jclouds.aliyun.ecs.domain.Tag;
@@ -32,6 +31,7 @@ import org.testng.annotations.Test;
 
 import java.util.concurrent.atomic.AtomicInteger;
 
+import static org.jclouds.aliyun.ecs.domain.ResourceType.SECURITYGROUP;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
@@ -40,38 +40,36 @@ import static org.testng.util.Strings.isNullOrEmpty;
 @Test(groups = "live", testName = "TagApiLiveTest")
 public class TagApiLiveTest extends BaseECSComputeServiceApiLiveTest {
 
-   public static final String RESOURCE_TYPE = "securitygroup";
-
    private String securityGroupName = "pre-test-security";
    private String securityGroupId;
 
    @BeforeClass
    public void setUp() {
-      SecurityGroupRequest preRequisite = api.securityGroupApi().create(Regions.EU_CENTRAL_1.getName(),
+      SecurityGroupRequest preRequisite = api.securityGroupApi().create(TEST_REGION,
               CreateSecurityGroupOptions.Builder.securityGroupName(securityGroupName)
       );
       securityGroupId = preRequisite.getSecurityGroupId();
-      Request request = api().add(Regions.EU_CENTRAL_1.getName(), securityGroupId, RESOURCE_TYPE,
+      Request request = api().add(TEST_REGION, securityGroupId, SECURITYGROUP,
               TagOptions.Builder.tag(1, "owner"));
       assertNotNull(request.getRequestId());
    }
 
    @AfterClass
    public void tearDown() {
-      api().remove(Regions.EU_CENTRAL_1.getName(), securityGroupId, RESOURCE_TYPE);
+      api().remove(TEST_REGION, securityGroupId, SECURITYGROUP);
       if (securityGroupId != null) {
-         api.securityGroupApi().delete(Regions.EU_CENTRAL_1.getName(), securityGroupId);
+         api.securityGroupApi().delete(TEST_REGION, securityGroupId);
       }
    }
 
    public void testList() {
       final AtomicInteger found = new AtomicInteger(0);
-      assertFalse(api().list(Regions.EU_CENTRAL_1.getName(), ListTagsOptions.Builder.resourceId(securityGroupId))
+      assertFalse(api().list(TEST_REGION, ListTagsOptions.Builder.resourceId(securityGroupId))
               .filter(new Predicate<Tag>() {
                  @Override
                  public boolean apply(Tag input) {
                     found.incrementAndGet();
-                    return !isNullOrEmpty(input.tagKey());
+                    return !isNullOrEmpty(input.key());
                  }
               }).isEmpty(), "All tags must have the 'key' field populated");
       assertTrue(found.get() > 0, "Expected some tags to be returned");

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/TagApiMockTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/TagApiMockTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/TagApiMockTest.java
index deb492d..350a218 100644
--- a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/TagApiMockTest.java
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/TagApiMockTest.java
@@ -18,7 +18,6 @@ package org.jclouds.aliyun.ecs.compute.features;
 
 import com.google.common.collect.ImmutableMap;
 import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiMockTest;
-import org.jclouds.aliyun.ecs.domain.internal.Regions;
 import org.jclouds.aliyun.ecs.domain.Tag;
 import org.testng.annotations.Test;
 
@@ -35,35 +34,35 @@ public class TagApiMockTest extends BaseECSComputeServiceApiMockTest {
    public void testListTags() throws InterruptedException {
       server.enqueue(jsonResponse("/tags-first.json"));
       server.enqueue(jsonResponse("/tags-last.json"));
-      Iterable<Tag> tags = api.tagApi().list(Regions.EU_CENTRAL_1.getName()).concat();
+      Iterable<Tag> tags = api.tagApi().list(TEST_REGION).concat();
       assertEquals(size(tags), 10); // Force the PagedIterable to advance
       assertEquals(server.getRequestCount(), 2);
-      assertSent(server, "GET", "DescribeTags", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()));
-      assertSent(server, "GET", "DescribeTags", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()), 2);
+      assertSent(server, "GET", "DescribeTags", ImmutableMap.of("RegionId", TEST_REGION));
+      assertSent(server, "GET", "DescribeTags", ImmutableMap.of("RegionId", TEST_REGION), 2);
    }
 
    public void testListTagsReturns404() throws InterruptedException {
       server.enqueue(response404());
-      Iterable<Tag> tags = api.tagApi().list(Regions.EU_CENTRAL_1.getName()).concat();
+      Iterable<Tag> tags = api.tagApi().list(TEST_REGION).concat();
       assertTrue(isEmpty(tags));
       assertEquals(server.getRequestCount(), 1);
-      assertSent(server, "GET", "DescribeTags", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()));
+      assertSent(server, "GET", "DescribeTags", ImmutableMap.of("RegionId", TEST_REGION));
    }
 
    public void testListTagsWithOptions() throws InterruptedException {
       server.enqueue(jsonResponse("/tags-first.json"));
-      Iterable<Tag> tags = api.tagApi().list(Regions.EU_CENTRAL_1.getName(), paginationOptions(pageNumber(1).pageSize(5)));
+      Iterable<Tag> tags = api.tagApi().list(TEST_REGION, paginationOptions(pageNumber(1).pageSize(5)));
       assertEquals(size(tags), 8);
       assertEquals(server.getRequestCount(), 1);
-      assertSent(server, "GET", "DescribeTags", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()), 1);
+      assertSent(server, "GET", "DescribeTags", ImmutableMap.of("RegionId", TEST_REGION), 1);
    }
 
    public void testListTagsWithOptionsReturns404() throws InterruptedException {
       server.enqueue(response404());
-      Iterable<Tag> tags = api.tagApi().list(Regions.EU_CENTRAL_1.getName(), paginationOptions(pageNumber(2)));
+      Iterable<Tag> tags = api.tagApi().list(TEST_REGION, paginationOptions(pageNumber(2)));
       assertTrue(isEmpty(tags));
       assertEquals(server.getRequestCount(), 1);
-      assertSent(server, "GET", "DescribeTags", ImmutableMap.of("RegionId", Regions.EU_CENTRAL_1.getName()), 2);
+      assertSent(server, "GET", "DescribeTags", ImmutableMap.of("RegionId", TEST_REGION), 2);
    }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VPCApiLiveTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VPCApiLiveTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VPCApiLiveTest.java
new file mode 100644
index 0000000..8d2639e
--- /dev/null
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VPCApiLiveTest.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.aliyun.ecs.compute.features;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiLiveTest;
+import org.jclouds.aliyun.ecs.domain.VPC;
+import org.jclouds.aliyun.ecs.domain.VPCRequest;
+import org.jclouds.aliyun.ecs.domain.options.CreateVPCOptions;
+import org.jclouds.aliyun.ecs.domain.options.ListVPCsOptions;
+import org.jclouds.aliyun.ecs.features.VPCApi;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.jclouds.aliyun.ecs.domain.options.PaginationOptions.Builder.pageSize;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.util.Strings.isNullOrEmpty;
+
+@Test(groups = "live", testName = "VPCApiLiveTest")
+public class VPCApiLiveTest extends BaseECSComputeServiceApiLiveTest {
+
+   public static final String VPC_NAME = "jclouds-vpc";
+
+   private String vpcId;
+
+   @BeforeClass
+   public void setUp() {
+      VPCRequest vpcRequest = api().create(TEST_REGION, CreateVPCOptions.Builder.vpcName(VPC_NAME));
+      assertNotNull(vpcRequest.getRequestId());
+      assertNotNull(vpcRequest.getVpcId());
+      vpcId = vpcRequest.getVpcId();
+   }
+
+   @AfterClass(alwaysRun = true)
+   public void tearDown() {
+      if (vpcId != null) {
+         assertNotNull(api().delete(TEST_REGION, vpcId));
+      }
+   }
+
+   public void testList() {
+      final AtomicInteger found = new AtomicInteger(0);
+      assertTrue(Iterables.all(api().list(TEST_REGION).concat(), new Predicate<VPC>() {
+         @Override
+         public boolean apply(VPC input) {
+            found.incrementAndGet();
+            return !isNullOrEmpty(input.id());
+         }
+      }), "All vpcs must have at least the 'id' field populated");
+      assertTrue(found.get() > 0, "Expected some vpc to be returned");
+   }
+
+   public void testListWithOptions() {
+      final AtomicInteger found = new AtomicInteger(0);
+      assertTrue(api().list(TEST_REGION, ListVPCsOptions.Builder.vpcId(vpcId)
+                  .paginationOptions(pageSize(50)))
+            .firstMatch(new Predicate<VPC>() {
+               @Override
+               public boolean apply(VPC input) {
+                  found.incrementAndGet();
+                  return !isNullOrEmpty(input.id());
+               }
+            }).isPresent(), "All vpcs must have the 'id' field populated");
+      assertTrue(found.get() > 0, "Expected some image to be returned");
+   }
+
+   private VPCApi api() {
+      return api.vpcApi();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VPCApiMockTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VPCApiMockTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VPCApiMockTest.java
new file mode 100644
index 0000000..80de7f3
--- /dev/null
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VPCApiMockTest.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.aliyun.ecs.compute.features;
+
+import com.google.common.collect.ImmutableMap;
+import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiMockTest;
+import org.jclouds.aliyun.ecs.domain.Request;
+import org.jclouds.aliyun.ecs.domain.VPC;
+import org.jclouds.aliyun.ecs.domain.VPCRequest;
+import org.jclouds.collect.IterableWithMarker;
+import org.testng.annotations.Test;
+
+import static com.google.common.collect.Iterables.isEmpty;
+import static com.google.common.collect.Iterables.size;
+import static org.jclouds.aliyun.ecs.domain.options.ListVPCsOptions.Builder.paginationOptions;
+import static org.jclouds.aliyun.ecs.domain.options.PaginationOptions.Builder.pageNumber;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+@Test(groups = "unit", testName = "VPCApiMockTest", singleThreaded = true)
+public class VPCApiMockTest extends BaseECSComputeServiceApiMockTest {
+
+   public void testListVPCs() throws InterruptedException {
+      server.enqueue(jsonResponse("/vpcs-first.json"));
+      server.enqueue(jsonResponse("/vpcs-last.json"));
+      Iterable<VPC> vpcs = api.vpcApi().list(TEST_REGION).concat();
+      assertEquals(size(vpcs), 2); // Force the PagedIterable to advance
+      assertEquals(server.getRequestCount(), 2);
+      assertSent(server, "GET", "DescribeVpcs", ImmutableMap.of("RegionId", TEST_REGION));
+      assertSent(server, "GET", "DescribeVpcs", ImmutableMap.of("RegionId", TEST_REGION), 2);
+   }
+
+   public void testListVPCsReturns404() throws InterruptedException {
+      server.enqueue(response404());
+      Iterable<VPC> vpcs = api.vpcApi().list(TEST_REGION).concat();
+      assertTrue(isEmpty(vpcs));
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "DescribeVpcs", ImmutableMap.of("RegionId", TEST_REGION));
+   }
+
+   public void testListVPCsWithOptions() throws InterruptedException {
+      server.enqueue(jsonResponse("/vpcs-first.json"));
+      IterableWithMarker<VPC> vpcs = api.vpcApi().list(TEST_REGION, paginationOptions(pageNumber(1).pageSize(5)));
+      assertEquals(size(vpcs), 1);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "DescribeVpcs", ImmutableMap.of("RegionId", TEST_REGION), 1);
+   }
+
+   public void testListVPCsWithOptionsReturns404() throws InterruptedException {
+      server.enqueue(response404());
+      Iterable<VPC> vpcs = api.vpcApi().list(TEST_REGION, paginationOptions(pageNumber(2)));
+      assertTrue(isEmpty(vpcs));
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "DescribeVpcs", ImmutableMap.of("RegionId", TEST_REGION), 2);
+   }
+
+   public void testCreateVPC() throws InterruptedException {
+      server.enqueue(jsonResponse("/vpc-create-res.json"));
+      VPCRequest vpcRequest = api.vpcApi().create(TEST_REGION);
+      assertEquals(vpcRequest, objectFromResource("/vpc-create-res.json", VPCRequest.class));
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "POST", "CreateVpc", ImmutableMap.of("RegionId", TEST_REGION));
+   }
+
+   public void testDeleteVPC() throws InterruptedException {
+      server.enqueue(jsonResponse("/vpc-delete-res.json"));
+      Request delete = api.vpcApi().delete(TEST_REGION, "vpc-123456789");
+      assertEquals(delete, objectFromResource("/vpc-delete-res.json", Request.class));
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "POST", "DeleteVpc", ImmutableMap.of("RegionId", TEST_REGION, "VpcId", "vpc-123456789"));
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VSwitchApiLiveTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VSwitchApiLiveTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VSwitchApiLiveTest.java
new file mode 100644
index 0000000..c7abc40
--- /dev/null
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VSwitchApiLiveTest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.aliyun.ecs.compute.features;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiLiveTest;
+import org.jclouds.aliyun.ecs.domain.VPCRequest;
+import org.jclouds.aliyun.ecs.domain.VSwitch;
+import org.jclouds.aliyun.ecs.domain.VSwitchRequest;
+import org.jclouds.aliyun.ecs.domain.options.CreateVSwitchOptions;
+import org.jclouds.aliyun.ecs.domain.options.ListVSwitchesOptions;
+import org.jclouds.aliyun.ecs.features.VSwitchApi;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.jclouds.aliyun.ecs.domain.options.PaginationOptions.Builder.pageSize;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.util.Strings.isNullOrEmpty;
+
+@Test(groups = "live", testName = "VSwitchApiLiveTest")
+public class VSwitchApiLiveTest extends BaseECSComputeServiceApiLiveTest {
+
+   public static final String VSWITCH_NAME = "jclouds-vswitch";
+   public static final String DEFAULT_CIDR_BLOCK = "172.16.1.0/24";
+   private String vpcId;
+   private String vSwitchId;
+
+   @BeforeClass
+   public void setUp() {
+      VPCRequest preRequisite = api.vpcApi().create(TEST_REGION);
+      vpcId = preRequisite.getVpcId();
+      VSwitchRequest vpcRequest = api().create(
+              TEST_ZONE,
+              DEFAULT_CIDR_BLOCK,
+              vpcId,
+              CreateVSwitchOptions.Builder.vSwitchName(VSWITCH_NAME));
+      assertNotNull(vpcRequest.getRequestId());
+      assertNotNull(vpcRequest.getVSwitchId());
+      vSwitchId = vpcRequest.getVSwitchId();
+   }
+
+   @AfterClass(alwaysRun = true)
+   public void tearDown() {
+      if (vSwitchId != null) {
+         assertNotNull(api().delete(TEST_REGION, vSwitchId));
+      }
+      if (vpcId != null) {
+         assertNotNull(api.vpcApi().delete(TEST_REGION, vpcId));
+      }
+   }
+
+   public void testList() {
+      final AtomicInteger found = new AtomicInteger(0);
+      assertTrue(Iterables.all(api().list(TEST_REGION).concat(), new Predicate<VSwitch>() {
+         @Override
+         public boolean apply(VSwitch input) {
+            found.incrementAndGet();
+            return !isNullOrEmpty(input.id());
+         }
+      }), "All vSwitches must have at least the 'id' field populated");
+      assertTrue(found.get() > 0, "Expected some vSwitch to be returned");
+   }
+
+   public void testListWithOptions() {
+      final AtomicInteger found = new AtomicInteger(0);
+      assertTrue(api().list(TEST_REGION, ListVSwitchesOptions.Builder.vSwitchId(vSwitchId)
+            .paginationOptions(pageSize(50)))
+            .firstMatch(new Predicate<VSwitch>() {
+               @Override
+               public boolean apply(VSwitch input) {
+                  found.incrementAndGet();
+                  return !isNullOrEmpty(input.id());
+               }
+            }).isPresent(), "All vSwitches must have at least the 'id' field populated");
+      assertTrue(found.get() > 0, "Expected some vSwitch to be returned");
+   }
+
+   private VSwitchApi api() {
+      return api.vSwitchApi();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VSwitchApiMockTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VSwitchApiMockTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VSwitchApiMockTest.java
new file mode 100644
index 0000000..b80111d
--- /dev/null
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/features/VSwitchApiMockTest.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.aliyun.ecs.compute.features;
+
+import com.google.common.collect.ImmutableMap;
+import org.jclouds.aliyun.ecs.compute.internal.BaseECSComputeServiceApiMockTest;
+import org.jclouds.aliyun.ecs.domain.Request;
+import org.jclouds.aliyun.ecs.domain.VSwitch;
+import org.jclouds.aliyun.ecs.domain.VSwitchRequest;
+import org.jclouds.collect.IterableWithMarker;
+import org.testng.annotations.Test;
+
+import static com.google.common.collect.Iterables.isEmpty;
+import static com.google.common.collect.Iterables.size;
+import static org.jclouds.aliyun.ecs.domain.options.ListVSwitchesOptions.Builder.paginationOptions;
+import static org.jclouds.aliyun.ecs.domain.options.PaginationOptions.Builder.pageNumber;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+@Test(groups = "unit", testName = "VSwitchApiMockTest", singleThreaded = true)
+public class VSwitchApiMockTest extends BaseECSComputeServiceApiMockTest {
+
+   public void testListVSwitches() throws InterruptedException {
+      server.enqueue(jsonResponse("/vswitches-first.json"));
+      server.enqueue(jsonResponse("/vswitches-last.json"));
+      Iterable<VSwitch> vSwitches = api.vSwitchApi().list(TEST_REGION).concat();
+      assertEquals(size(vSwitches), 2); // Force the PagedIterable to advance
+      assertEquals(server.getRequestCount(), 2);
+      assertSent(server, "GET", "DescribeVSwitches", ImmutableMap.of("RegionId", TEST_REGION));
+      assertSent(server, "GET", "DescribeVSwitches", ImmutableMap.of("RegionId", TEST_REGION), 2);
+   }
+
+   public void testListVSwitchesReturns404() throws InterruptedException {
+      server.enqueue(response404());
+      Iterable<VSwitch> vSwitches = api.vSwitchApi().list(TEST_REGION).concat();
+      assertTrue(isEmpty(vSwitches));
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "DescribeVSwitches", ImmutableMap.of("RegionId", TEST_REGION));
+   }
+
+   public void testListVSwitchesWithOptions() throws InterruptedException {
+      server.enqueue(jsonResponse("/vswitches-first.json"));
+      IterableWithMarker<VSwitch> vSwitches = api.vSwitchApi().list(TEST_REGION, paginationOptions(pageNumber(1).pageSize(5)));
+      assertEquals(size(vSwitches), 1);
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "DescribeVSwitches", ImmutableMap.of("RegionId", TEST_REGION), 1);
+   }
+
+   public void testListVSwitchesWithOptionsReturns404() throws InterruptedException {
+      server.enqueue(response404());
+      IterableWithMarker<VSwitch> vSwitches = api.vSwitchApi().list(TEST_REGION, paginationOptions(pageNumber(2)));
+      assertTrue(isEmpty(vSwitches));
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "GET", "DescribeVSwitches", ImmutableMap.of("RegionId", TEST_REGION), 2);
+   }
+
+   public void testCreateVSwitch() throws InterruptedException {
+      server.enqueue(jsonResponse("/vswitch-create-res.json"));
+      VSwitchRequest vSwitchRequest = api.vSwitchApi().create(TEST_ZONE, "192.168.1.0/24", "vsw-25naue4gz");
+      assertEquals(vSwitchRequest, objectFromResource("/vswitch-create-res.json", VSwitchRequest.class));
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "POST", "CreateVSwitch", ImmutableMap.of("ZoneId", TEST_ZONE, "CidrBlock", "192.168.1.0/24", "VpcId", "vsw-25naue4gz"));
+   }
+
+   public void testDeletVSwitch() throws InterruptedException {
+      server.enqueue(jsonResponse("/vswitch-delete-res.json"));
+      Request delete = api.vSwitchApi().delete(TEST_REGION, "vsw-123456789");
+      assertEquals(delete, objectFromResource("/vswitch-delete-res.json", Request.class));
+      assertEquals(server.getRequestCount(), 1);
+      assertSent(server, "POST", "DeleteVSwitch", ImmutableMap.of("RegionId", TEST_REGION, "VSwitchId", "vsw-123456789"));
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/functions/ImageInRegionToImageTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/functions/ImageInRegionToImageTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/functions/ImageInRegionToImageTest.java
new file mode 100644
index 0000000..c9cf1ab
--- /dev/null
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/functions/ImageInRegionToImageTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.aliyun.ecs.compute.functions;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.aliyun.ecs.domain.DiskDeviceMapping;
+import org.jclouds.aliyun.ecs.domain.Tag;
+import org.jclouds.aliyun.ecs.domain.internal.Regions;
+import org.jclouds.aliyun.ecs.domain.regionscoped.ImageInRegion;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.domain.Location;
+import org.jclouds.domain.LocationBuilder;
+import org.jclouds.domain.LocationScope;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.xml.bind.DatatypeConverter;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import static org.jclouds.aliyun.ecs.domain.Image.Status.AVAILABLE;
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertTrue;
+
+@Test(groups = "unit", testName = "ImageInRegionToImageTest")
+public class ImageInRegionToImageTest {
+
+   private final Location region = new LocationBuilder()
+           .id(Regions.EU_CENTRAL_1.getName())
+           .description(Regions.EU_CENTRAL_1.getDescription())
+           .scope(LocationScope.REGION).build();
+   private final Supplier<Set<? extends Location>> locations = Suppliers.<Set<? extends Location>> ofInstance(ImmutableSet.of(region));
+
+   private ImageInRegionToImage imageInRegionToImage;
+
+   @BeforeMethod
+   public void setUp() {
+      imageInRegionToImage = new ImageInRegionToImage(locations);
+   }
+
+   @Test
+   public void testOsImageToImage() {
+      final org.jclouds.aliyun.ecs.domain.Image ecsImage = org.jclouds.aliyun.ecs.domain.Image.builder()
+              .id("centos_6_09_64_20G_alibase_20180326.vhd")
+              .description("")
+              .productCode("")
+              .osType("linux")
+              .architecture("x86_64")
+              .osName("CentOS  6.9 64位")
+              .imageOwnerAlias("system")
+              .progress("100%")
+              .isSupportCloudinit(true)
+              .usage("instance")
+              .creationTime(parseDate("2018-05-10T12:40:55Z"))
+              .imageVersion("")
+              .status(AVAILABLE)
+              .name("centos_6_09_64_20G_alibase_20180326.vhd")
+              .isSupportIoOptimizeds(true)
+              .isCopied(false)
+              .isSubscribed(false)
+              .isSelfShared(false)
+              .platform("CentOS")
+              .size(20)
+              .diskDeviceMappings(ImmutableMap.<String, List<DiskDeviceMapping>>of())
+              .tags(ImmutableMap.<String, List<Tag>>of())
+              .build();
+
+      final Image image = imageInRegionToImage.apply(ImageInRegion.create(Regions.EU_CENTRAL_1.getName(), ecsImage));
+      assertEquals(ecsImage.id(), image.getProviderId());
+      assertEquals(ecsImage.name(), image.getName());
+      assertEquals(Image.Status.AVAILABLE, image.getStatus());
+      final org.jclouds.compute.domain.OperatingSystem operatingSystem = image.getOperatingSystem();
+
+      assertEquals(ecsImage.osName(), operatingSystem.getName());
+      assertEquals(ecsImage.description(), operatingSystem.getDescription());
+      assertTrue(operatingSystem.is64Bit());
+      assertEquals(region, image.getLocation());
+   }
+
+   @Test
+   public void testOsImageFromOtherOSMapToImage() {
+      final org.jclouds.aliyun.ecs.domain.Image ecsImage = org.jclouds.aliyun.ecs.domain.Image.builder()
+              .id("alinux_17_01_64_20G_cloudinit_20171222.vhd")
+              .description("")
+              .productCode("")
+              .osType("linux")
+              .architecture("x86_64")
+              .osName("Aliyun Linux  17.1 64位")
+              .imageOwnerAlias("system")
+              .progress("100%")
+              .isSupportCloudinit(true)
+              .usage("instance")
+              .creationTime(parseDate("2017-12-22T05:56:16Z"))
+              .imageVersion("")
+              .status(AVAILABLE)
+              .name("alinux_17_01_64_20G_cloudinit_20171222.vhd")
+              .isSupportIoOptimizeds(true)
+              .isCopied(false)
+              .isSubscribed(false)
+              .isSelfShared(false)
+              .platform("Aliyun")
+              .size(20)
+              .diskDeviceMappings(ImmutableMap.<String, List<DiskDeviceMapping>>of())
+              .tags(ImmutableMap.<String, List<Tag>>of())
+              .build();
+
+      final Image image = imageInRegionToImage.apply(ImageInRegion.create(Regions.EU_CENTRAL_1.getName(), ecsImage));
+      assertEquals(ecsImage.id(), image.getProviderId());
+      assertEquals(ecsImage.name(), image.getName());
+      assertEquals(Image.Status.AVAILABLE, image.getStatus());
+      final org.jclouds.compute.domain.OperatingSystem operatingSystem = image.getOperatingSystem();
+
+      assertEquals(ecsImage.osName(), operatingSystem.getName());
+      assertEquals(ecsImage.description(), operatingSystem.getDescription());
+      assertTrue(operatingSystem.is64Bit());
+      assertEquals(region, image.getLocation());
+   }
+
+   Date parseDate(final String dateString) {
+      return DatatypeConverter.parseDateTime(dateString).getTime();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/functions/InstanceStatusToStatusTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/functions/InstanceStatusToStatusTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/functions/InstanceStatusToStatusTest.java
new file mode 100644
index 0000000..62f22e5
--- /dev/null
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/functions/InstanceStatusToStatusTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.aliyun.ecs.compute.functions;
+
+import org.jclouds.aliyun.ecs.domain.Instance;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * Unit tests for the {@link InstanceStatusToStatus} class.
+ */
+@Test(groups = "unit", testName = "InstanceStatusToStatusTest")
+public class InstanceStatusToStatusTest {
+   private InstanceStatusToStatus function;
+
+   @BeforeMethod
+   public void setup() {
+      function = new InstanceStatusToStatus();
+   }
+
+   public void testStatusRunningToStatusRunning() {
+      NodeMetadata.Status status = function.apply(Instance.Status.RUNNING);
+      assertEquals(status, NodeMetadata.Status.RUNNING);
+   }
+
+   public void testStatusStartingToStatusPending() {
+      NodeMetadata.Status status = function.apply(Instance.Status.STARTING);
+      assertEquals(status, NodeMetadata.Status.PENDING);
+   }
+
+   public void testStatusStoppingToStatusPending() {
+      NodeMetadata.Status status = function.apply(Instance.Status.STOPPING);
+      assertEquals(status, NodeMetadata.Status.PENDING);
+   }
+
+   public void testStatusStoppedToStatusSuspended() {
+      NodeMetadata.Status status = function.apply(Instance.Status.STOPPED);
+      assertEquals(status, NodeMetadata.Status.SUSPENDED);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2c7db7e8/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/functions/InstanceToHardwareTest.java
----------------------------------------------------------------------
diff --git a/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/functions/InstanceToHardwareTest.java b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/functions/InstanceToHardwareTest.java
new file mode 100644
index 0000000..910703c
--- /dev/null
+++ b/aliyun-ecs/src/test/java/org/jclouds/aliyun/ecs/compute/functions/InstanceToHardwareTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.aliyun.ecs.compute.functions;
+
+import org.jclouds.aliyun.ecs.domain.InstanceType;
+import org.jclouds.compute.domain.Hardware;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.testng.AssertJUnit.assertEquals;
+
+@Test(groups = "unit", testName = "InstanceToHardwareTest")
+public class InstanceToHardwareTest {
+
+   private InstanceTypeToHardware instanceTypeToHardware;
+
+   @BeforeMethod
+   public void setUp() {
+      instanceTypeToHardware = new InstanceTypeToHardware();
+   }
+
+   @Test
+   public void testApplyServer() {
+      final InstanceType instanceType = InstanceType.builder()
+              .id("ecs.t1.small")
+              .cpuCoreCount(1)
+              .instanceTypeFamily("ecs.t1")
+              .eniQuantity(1)
+              .memorySize(1.0)
+              .gpuAmount(0d)
+              .localStorageCategory("")
+              .gpuSpec("")
+              .build();
+      applyAndAssert(instanceType);
+   }
+
+   private void applyAndAssert(InstanceType instanceType) {
+      final Hardware hardware = instanceTypeToHardware.apply(instanceType);
+      assertEquals(instanceType.memorySize().intValue() * 1024, hardware.getRam());
+      assertEquals(instanceType.id(), hardware.getId());
+      assertEquals(instanceType.id(), hardware.getProviderId());
+      assertEquals(instanceType.id(), hardware.getName());
+      assertEquals(instanceType.cpuCoreCount().intValue(), hardware.getProcessors().size());
+      assertEquals(Double.valueOf(instanceType.cpuCoreCount().intValue()), hardware.getProcessors().get(0).getCores());
+   }
+
+}