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 2014/10/02 23:53:06 UTC

[02/11] JCLOUDS-664 Updating Azure compute provider

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/main/java/org/jclouds/azurecompute/xml/OperationHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/OperationHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/OperationHandler.java
new file mode 100644
index 0000000..e0a6912
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/OperationHandler.java
@@ -0,0 +1,97 @@
+/*
+ * 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.azurecompute.xml;
+
+import javax.inject.Inject;
+import org.jclouds.azurecompute.domain.Operation;
+import org.jclouds.azurecompute.domain.Operation.Builder;
+import org.jclouds.azurecompute.domain.Operation.Status;
+import org.jclouds.http.functions.ParseSax;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import static org.jclouds.util.SaxUtils.currentOrNull;
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+/**
+ * @see <a href="http://msdn.microsoft.com/en-us/library/ee460783" >api</a>
+ */
+public class OperationHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Operation> {
+
+   private final ErrorHandler errorHandler;
+
+   @Inject
+   private OperationHandler(ErrorHandler errorHandler) {
+      this.errorHandler = errorHandler;
+   }
+
+   private StringBuilder currentText = new StringBuilder();
+   private Operation.Builder builder = builder();
+
+   private Builder builder() {
+      return Operation.builder();
+   }
+
+   private boolean inError;
+
+   @Override
+   public Operation getResult() {
+      try {
+         return builder.build();
+      } finally {
+         builder = builder();
+      }
+   }
+
+   @Override
+   public void startElement(String url, String name, String qName, Attributes attributes) throws SAXException {
+      if (equalsOrSuffix(qName, "Error")) {
+         inError = true;
+      }
+      if (inError) {
+         errorHandler.startElement(url, name, qName, attributes);
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) throws SAXException {
+      if (equalsOrSuffix(qName, "Error")) {
+         builder.error(errorHandler.getResult());
+         inError = false;
+      } else if (inError) {
+         errorHandler.endElement(uri, name, qName);
+      } else if (equalsOrSuffix(qName, "ID")) {
+         builder.id(currentOrNull(currentText));
+      } else if (qName.equals("Status")) {
+         String rawStatus = currentOrNull(currentText);
+         builder.rawStatus(rawStatus);
+         builder.status(Status.fromValue(rawStatus));
+      } else if (equalsOrSuffix(qName, "HttpStatusCode")) {
+         builder.httpStatusCode(Integer.parseInt(currentOrNull(currentText)));
+      }
+      currentText.setLength(0);
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      if (inError) {
+         errorHandler.characters(ch, start, length);
+      } else {
+         currentText.append(ch, start, length);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata b/azurecompute/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
new file mode 100644
index 0000000..05b8f1f
--- /dev/null
+++ b/azurecompute/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
@@ -0,0 +1 @@
+org.jclouds.azurecompute.AzureComputeProviderMetadata

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/AzureComputeProviderMetadataTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/AzureComputeProviderMetadataTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/AzureComputeProviderMetadataTest.java
new file mode 100644
index 0000000..a7e7eb7
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/AzureComputeProviderMetadataTest.java
@@ -0,0 +1,28 @@
+/*
+ * 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.azurecompute;
+
+import org.jclouds.providers.internal.BaseProviderMetadataTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "unit", testName = "AzureManagementProviderMetadataTest")
+public class AzureComputeProviderMetadataTest extends BaseProviderMetadataTest {
+
+   public AzureComputeProviderMetadataTest() {
+      super(new AzureComputeProviderMetadata(), new AzureManagementApiMetadata());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/features/DeploymentApiMockTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/features/DeploymentApiMockTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/features/DeploymentApiMockTest.java
new file mode 100644
index 0000000..e0bd956
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/features/DeploymentApiMockTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.azurecompute.features;
+
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import org.jclouds.azurecompute.domain.DeploymentParams;
+import org.jclouds.azurecompute.domain.OSType;
+import org.jclouds.azurecompute.domain.RoleSize;
+import org.jclouds.azurecompute.internal.BaseAzureComputeApiMockTest;
+import org.jclouds.azurecompute.parse.GetDeploymentTest;
+import org.testng.annotations.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Test(groups = "unit", testName = "DeploymentApiMockTest")
+public class DeploymentApiMockTest extends BaseAzureComputeApiMockTest {
+
+   public void create() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(requestIdResponse("request-1"));
+
+      try {
+         DeploymentApi api = api(server.getUrl("/")).getDeploymentApiForService("myservice");
+
+         DeploymentParams params = DeploymentParams.builder().osType(OSType.LINUX).name("mydeployment")
+               .username("username").password("testpwd").size(RoleSize.MEDIUM)
+               .sourceImageName("OpenLogic__OpenLogic-CentOS-62-20120531-en-us-30GB.vhd")
+               .storageAccount("portalvhds0g7xhnq2x7t21").build();
+
+         assertThat(api.create(params)).isEqualTo("request-1");
+
+         assertSent(server, "POST", "/services/hostedservices/myservice/deployments", "/deploymentparams.xml");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void getWhenFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(xmlResponse("/deployment.xml"));
+
+      try {
+         DeploymentApi api = api(server.getUrl("/")).getDeploymentApiForService("myservice");
+
+         assertThat(api.get("mydeployment")).isEqualTo(GetDeploymentTest.expected());
+
+         assertSent(server, "GET", "/services/hostedservices/myservice/deployments/mydeployment");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void getWhenNotFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(new MockResponse().setResponseCode(404));
+
+      try {
+         DeploymentApi api = api(server.getUrl("/")).getDeploymentApiForService("myservice");
+
+         assertThat(api.get("mydeployment")).isNull();
+
+         assertSent(server, "GET", "/services/hostedservices/myservice/deployments/mydeployment");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void deleteWhenFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(requestIdResponse("request-1"));
+
+      try {
+         DeploymentApi api = api(server.getUrl("/")).getDeploymentApiForService("myservice");
+
+         assertThat(api.delete("mydeployment")).isEqualTo("request-1");
+
+         assertSent(server, "DELETE", "/services/hostedservices/myservice/deployments/mydeployment");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void deleteWhenNotFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(new MockResponse().setResponseCode(404));
+
+      try {
+         DeploymentApi api = api(server.getUrl("/")).getDeploymentApiForService("myservice");
+
+         assertThat(api.delete("mydeployment")).isNull();
+
+         assertSent(server, "DELETE", "/services/hostedservices/myservice/deployments/mydeployment");
+      } finally {
+         server.shutdown();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/features/DiskApiLiveTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/features/DiskApiLiveTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/features/DiskApiLiveTest.java
new file mode 100644
index 0000000..eb16847
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/features/DiskApiLiveTest.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.azurecompute.features;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableSet;
+import java.util.List;
+import org.jclouds.azurecompute.domain.Disk;
+import org.jclouds.azurecompute.domain.Image;
+import org.jclouds.azurecompute.domain.Location;
+import org.jclouds.azurecompute.domain.OSType;
+import org.jclouds.azurecompute.internal.BaseAzureComputeApiLiveTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.transform;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+
+@Test(groups = "live", testName = "DiskApiLiveTest")
+public class DiskApiLiveTest extends BaseAzureComputeApiLiveTest {
+
+   private ImmutableSet<String> locations;
+   private ImmutableSet<String> images;
+
+   @BeforeClass(groups = { "integration", "live" })
+   public void setup() {
+      super.setup();
+
+      locations = ImmutableSet.copyOf(transform(api.getLocationApi().list(),
+               new Function<Location, String>() {
+                  @Override
+                  public String apply(Location in) {
+                     return in.getName();
+                  }
+               }));
+      images = ImmutableSet.copyOf(transform(api.getImageApi().list(), new Function<Image, String>() {
+         @Override
+         public String apply(Image in) {
+            return in.getName();
+         }
+      }));
+   }
+
+   @Test
+   protected void testList() {
+      List<Disk> response = api().list();
+
+      for (Disk disk : response) {
+         checkDisk(disk);
+      }
+   }
+
+   private void checkDisk(Disk disk) {
+      checkNotNull(disk.getName(), "Name cannot be null for Disk %s", disk.getLabel());
+      checkNotNull(disk.getOS(), "OS cannot be null for Disk: %s", disk);
+      assertNotEquals(disk.getOS(), OSType.UNRECOGNIZED, "Status cannot be UNRECOGNIZED for Disk: " + disk);
+
+      checkNotNull(disk.getAttachedTo(), "While AttachedTo can be null for Disk, its Optional wrapper cannot: %s", disk);
+      if (disk.getAttachedTo().isPresent()) {
+         // TODO: verify you can lookup the role
+      }
+
+      checkNotNull(disk.getLogicalSizeInGB(),
+               "While LogicalSizeInGB can be null for Disk, its Optional wrapper cannot: %s", disk);
+
+      if (disk.getLogicalSizeInGB().isPresent())
+         assertTrue(disk.getLogicalSizeInGB().get() > 0, "LogicalSizeInGB should be positive, if set" + disk.toString());
+
+      checkNotNull(disk.getMediaLink(), "While MediaLink can be null for Disk, its Optional wrapper cannot: %s", disk);
+
+      if (disk.getMediaLink().isPresent())
+         assertTrue(ImmutableSet.of("http", "https").contains(disk.getMediaLink().get().getScheme()),
+                  "MediaLink should be an http(s) url" + disk.toString());
+
+      checkNotNull(disk.getLabel(), "While Label can be null for Disk, its Optional wrapper cannot: %s",
+               disk);
+
+      checkNotNull(disk.getDescription(), "While Description can be null for Disk, its Optional wrapper cannot: %s",
+               disk);
+
+      checkNotNull(disk.getLocation(), "While Location can be null for Disk, its Optional wrapper cannot: %s", disk);
+      if (disk.getLocation().isPresent()) {
+         assertTrue(locations.contains(disk.getLocation().get()),
+                  "Location not in " + locations + " :" + disk.toString());
+      }
+
+      checkNotNull(disk.getSourceImage(), "While SourceImage can be null for Disk, its Optional wrapper cannot: %s",
+               disk);
+      if (disk.getSourceImage().isPresent()) {
+         assertTrue(images.contains(disk.getSourceImage().get()),
+                  "SourceImage not in " + images + " :" + disk.toString());
+      }
+
+      checkNotNull(disk.getAffinityGroup(),
+               "While AffinityGroup can be null for Disk, its Optional wrapper cannot: %s", disk);
+      if (disk.getAffinityGroup().isPresent()) {
+         // TODO: list getAffinityGroups and check if there
+      }
+   }
+
+   private DiskApi api() {
+      return api.getDiskApi();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/features/DiskApiMockTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/features/DiskApiMockTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/features/DiskApiMockTest.java
new file mode 100644
index 0000000..c6fab15
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/features/DiskApiMockTest.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.azurecompute.features;
+
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import org.jclouds.azurecompute.internal.BaseAzureComputeApiMockTest;
+import org.jclouds.azurecompute.parse.ListDisksTest;
+import org.testng.annotations.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Test(groups = "unit", testName = "DiskApiMockTest")
+public class DiskApiMockTest extends BaseAzureComputeApiMockTest {
+
+   public void listWhenFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(xmlResponse("/disks.xml"));
+
+      try {
+         DiskApi api = api(server.getUrl("/")).getDiskApi();
+
+         assertThat(api.list()).containsExactlyElementsOf(ListDisksTest.expected());
+
+         assertSent(server, "GET", "/services/disks");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void listWhenNotFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(new MockResponse().setResponseCode(404));
+
+      try {
+         DiskApi api = api(server.getUrl("/")).getDiskApi();
+
+         assertThat(api.list()).isEmpty();
+
+         assertSent(server, "GET", "/services/disks");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void deleteWhenFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(requestIdResponse("request-1"));
+
+      try {
+         DiskApi api = api(server.getUrl("/")).getDiskApi();
+
+         assertThat(api.delete("my-disk")).isEqualTo("request-1");
+
+         assertSent(server, "DELETE", "/services/disks/my-disk");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void deleteWhenNotFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(new MockResponse().setResponseCode(404));
+
+      try {
+         DiskApi api = api(server.getUrl("/")).getDiskApi();
+
+         assertThat(api.delete("my-disk")).isNull();
+
+         assertSent(server, "DELETE", "/services/disks/my-disk");
+      } finally {
+         server.shutdown();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/features/HostedServiceApiLiveTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/features/HostedServiceApiLiveTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/features/HostedServiceApiLiveTest.java
new file mode 100644
index 0000000..558689f
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/features/HostedServiceApiLiveTest.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.azurecompute.features;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import java.util.List;
+import java.util.logging.Logger;
+import org.jclouds.azurecompute.domain.DetailedHostedServiceProperties;
+import org.jclouds.azurecompute.domain.HostedService;
+import org.jclouds.azurecompute.domain.HostedService.Status;
+import org.jclouds.azurecompute.domain.HostedServiceWithDetailedProperties;
+import org.jclouds.azurecompute.domain.Operation;
+import org.jclouds.azurecompute.internal.BaseAzureComputeApiLiveTest;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.jclouds.util.Predicates2.retry;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+
+@Test(groups = "live", testName = "HostedServiceApiLiveTest")
+public class HostedServiceApiLiveTest extends BaseAzureComputeApiLiveTest {
+
+   public static final String HOSTED_SERVICE = (System.getProperty("user.name") + "-jclouds-hostedService")
+            .toLowerCase();
+
+   private Predicate<String> operationSucceeded;
+   private Predicate<HostedServiceWithDetailedProperties> hostedServiceCreated;
+   private Predicate<HostedService> hostedServiceGone;
+
+   private String location;
+
+   @BeforeClass(groups = { "integration", "live" })
+   public void setup() {
+      super.setup();
+      // TODO: filter locations on those who have compute
+      location = Iterables.get(api.getLocationApi().list(), 0).getName();
+      operationSucceeded = retry(new Predicate<String>() {
+         public boolean apply(String input) {
+            return api.getOperationApi().get(input).getStatus() == Operation.Status.SUCCEEDED;
+         }
+      }, 600, 5, 5, SECONDS);
+      hostedServiceCreated = retry(new Predicate<HostedServiceWithDetailedProperties>() {
+         public boolean apply(HostedServiceWithDetailedProperties input) {
+            return api().getDetails(input.getName()).getProperties().getStatus() == Status.CREATED;
+         }
+      }, 600, 5, 5, SECONDS);
+      hostedServiceGone = retry(new Predicate<HostedService>() {
+         public boolean apply(HostedService input) {
+            return api().get(input.getName()) == null;
+         }
+      }, 600, 5, 5, SECONDS);
+   }
+
+   private HostedServiceWithDetailedProperties hostedService;
+
+   public void testCreateHostedService() {
+
+      String requestId = api().createServiceWithLabelInLocation(HOSTED_SERVICE, HOSTED_SERVICE, location);
+      assertTrue(operationSucceeded.apply(requestId), requestId);
+      Logger.getAnonymousLogger().info("operation succeeded: " + requestId);
+
+      hostedService = api().getDetails(HOSTED_SERVICE);
+      Logger.getAnonymousLogger().info("created hostedService: " + hostedService);
+
+      assertEquals(hostedService.getName(), HOSTED_SERVICE);
+
+      checkHostedService(hostedService);
+
+      assertTrue(hostedServiceCreated.apply(hostedService), hostedService.toString());
+      hostedService = api().getDetails(hostedService.getName());
+      Logger.getAnonymousLogger().info("hostedService available: " + hostedService);
+
+   }
+
+   @Test(dependsOnMethods = "testCreateHostedService")
+   public void testDeleteHostedService() {
+      String requestId = api().delete(hostedService.getName());
+      assertTrue(operationSucceeded.apply(requestId), requestId);
+      Logger.getAnonymousLogger().info("operation succeeded: " + requestId);
+
+      assertTrue(hostedServiceGone.apply(hostedService), hostedService.toString());
+      Logger.getAnonymousLogger().info("hostedService deleted: " + hostedService);
+   }
+
+   @Override
+   @AfterClass(groups = "live")
+   protected void tearDown() {
+      String requestId = api().delete(HOSTED_SERVICE);
+      if (requestId != null)
+         operationSucceeded.apply(requestId);
+
+      super.tearDown();
+   }
+
+   @Test
+   protected void testList() {
+      List<HostedServiceWithDetailedProperties> response = api().list();
+
+      for (HostedServiceWithDetailedProperties hostedService : response) {
+         checkHostedService(hostedService);
+      }
+
+      if (response.size() > 0) {
+         HostedService hostedService = response.iterator().next();
+         Assert.assertEquals(api().getDetails(hostedService.getName()), hostedService);
+      }
+   }
+
+   private void checkHostedService(HostedServiceWithDetailedProperties hostedService) {
+      checkNotNull(hostedService.getUrl(), "Url cannot be null for a HostedService.");
+      checkNotNull(hostedService.getName(), "ServiceName cannot be null for HostedService %s", hostedService.getUrl());
+      checkNotNull(hostedService.getProperties(), "Properties cannot be null for HostedService %s",
+               hostedService.getUrl());
+      checkProperties(hostedService.getProperties());
+   }
+
+   private void checkProperties(DetailedHostedServiceProperties hostedService) {
+      checkNotNull(hostedService.getDescription(),
+               "While Description can be null for DetailedHostedServiceProperties, its Optional wrapper cannot: %s",
+               hostedService);
+      checkNotNull(hostedService.getLocation(),
+               "While Location can be null for DetailedHostedServiceProperties, its Optional wrapper cannot: %s",
+               hostedService);
+      checkNotNull(hostedService.getAffinityGroup(),
+               "While AffinityGroup can be null for DetailedHostedServiceProperties, its Optional wrapper cannot: %s",
+               hostedService);
+      checkState(hostedService.getLocation().isPresent() || hostedService.getAffinityGroup().isPresent(),
+               "Location or AffinityGroup must be present for DetailedHostedServiceProperties: %s", hostedService);
+      checkNotNull(hostedService.getLabel(), "Label cannot be null for HostedService %s", hostedService);
+
+      checkNotNull(hostedService.getStatus(), "Status cannot be null for DetailedHostedServiceProperties: %s",
+               hostedService);
+      assertNotEquals(hostedService.getStatus(), Status.UNRECOGNIZED,
+               "Status cannot be UNRECOGNIZED for DetailedHostedServiceProperties: " + hostedService);
+      checkNotNull(hostedService.getCreated(), "Created cannot be null for DetailedHostedServiceProperties %s",
+               hostedService);
+      checkNotNull(hostedService.getLastModified(),
+               "LastModified cannot be null for DetailedHostedServiceProperties %s", hostedService);
+      checkNotNull(hostedService.getExtendedProperties(),
+               "ExtendedProperties cannot be null for DetailedHostedServiceProperties %s", hostedService);
+   }
+
+   private HostedServiceApi api() {
+      return api.getHostedServiceApi();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/features/HostedServiceApiMockTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/features/HostedServiceApiMockTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/features/HostedServiceApiMockTest.java
new file mode 100644
index 0000000..a2a4aaf
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/features/HostedServiceApiMockTest.java
@@ -0,0 +1,186 @@
+/*
+ * 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.azurecompute.features;
+
+import com.google.common.collect.ImmutableMap;
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import org.jclouds.azurecompute.internal.BaseAzureComputeApiMockTest;
+import org.jclouds.azurecompute.parse.GetHostedServiceDetailsTest;
+import org.jclouds.azurecompute.parse.GetHostedServiceTest;
+import org.jclouds.azurecompute.parse.ListHostedServicesTest;
+import org.testng.annotations.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.jclouds.azurecompute.options.CreateHostedServiceOptions.Builder.description;
+
+@Test(groups = "unit", testName = "HostedServiceApiMockTest")
+public class HostedServiceApiMockTest extends BaseAzureComputeApiMockTest {
+
+   public void listWhenFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(xmlResponse("/hostedservices.xml"));
+
+      try {
+         HostedServiceApi api = api(server.getUrl("/")).getHostedServiceApi();
+
+         assertThat(api.list()).containsExactlyElementsOf(ListHostedServicesTest.expected());
+
+         assertSent(server, "GET", "/services/hostedservices");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void listWhenNotFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(new MockResponse().setResponseCode(404));
+
+      try {
+         HostedServiceApi api = api(server.getUrl("/")).getHostedServiceApi();
+
+         assertThat(api.list()).isEmpty();
+
+         assertSent(server, "GET", "/services/hostedservices");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void getWhenFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(xmlResponse("/hostedservice.xml"));
+
+      try {
+         HostedServiceApi api = api(server.getUrl("/")).getHostedServiceApi();
+
+         assertThat(api.get("myservice")).isEqualTo(GetHostedServiceTest.expected());
+
+         assertSent(server, "GET", "/services/hostedservices/myservice");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void getWhenNotFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(new MockResponse().setResponseCode(404));
+
+      try {
+         HostedServiceApi api = api(server.getUrl("/")).getHostedServiceApi();
+
+         assertThat(api.get("myservice")).isNull();
+
+         assertSent(server, "GET", "/services/hostedservices/myservice");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void getDetailsWhenFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(xmlResponse("/hostedservice_details.xml"));
+
+      try {
+         HostedServiceApi api = api(server.getUrl("/")).getHostedServiceApi();
+
+         assertThat(api.getDetails("myservice")).isEqualTo(GetHostedServiceDetailsTest.expected());
+
+         assertSent(server, "GET", "/services/hostedservices/myservice?embed-detail=true");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void getDetailsWhenNotFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(new MockResponse().setResponseCode(404));
+
+      try {
+         HostedServiceApi api = api(server.getUrl("/")).getHostedServiceApi();
+
+         assertThat(api.getDetails("myservice")).isNull();
+
+         assertSent(server, "GET", "/services/hostedservices/myservice?embed-detail=true");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void createServiceWithLabelInLocation() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(requestIdResponse("request-1"));
+
+      try {
+         HostedServiceApi api = api(server.getUrl("/")).getHostedServiceApi();
+
+         assertThat(api.createServiceWithLabelInLocation("myservice", "service mine", "West US"))
+               .isEqualTo("request-1");
+
+         assertSent(server, "POST", "/services/hostedservices", "/create_hostedservice_location.xml");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void createServiceWithLabelInLocationOptions() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(requestIdResponse("request-1"));
+
+      try {
+         HostedServiceApi api = api(server.getUrl("/")).getHostedServiceApi();
+
+         assertThat(api.createServiceWithLabelInLocation("myservice", "service mine", "West US",
+               description("my description").extendedProperties(ImmutableMap.of("Role", "Production"))))
+               .isEqualTo("request-1");
+
+         assertSent(server, "POST", "/services/hostedservices", "/create_hostedservice_location_options.xml");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void deleteWhenFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(requestIdResponse("request-1"));
+
+      try {
+         HostedServiceApi api = api(server.getUrl("/")).getHostedServiceApi();
+
+         assertThat(api.delete("myservice")).isEqualTo("request-1");
+
+         assertSent(server, "DELETE", "/services/hostedservices/myservice");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void deleteWhenNotFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(new MockResponse().setResponseCode(404));
+
+      try {
+         HostedServiceApi api = api(server.getUrl("/")).getHostedServiceApi();
+
+         assertThat(api.delete("myservice")).isNull();
+
+         assertSent(server, "DELETE", "/services/hostedservices/myservice");
+      } finally {
+         server.shutdown();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/features/ImageApiLiveTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/features/ImageApiLiveTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/features/ImageApiLiveTest.java
new file mode 100644
index 0000000..3507147
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/features/ImageApiLiveTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.azurecompute.features;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableSet;
+import java.util.List;
+import org.jclouds.azurecompute.domain.Image;
+import org.jclouds.azurecompute.domain.Location;
+import org.jclouds.azurecompute.domain.OSType;
+import org.jclouds.azurecompute.internal.BaseAzureComputeApiLiveTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.transform;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+
+@Test(groups = "live", testName = "ImageApiLiveTest")
+public class ImageApiLiveTest extends BaseAzureComputeApiLiveTest {
+
+   private ImmutableSet<String> locations;
+
+   @BeforeClass(groups = { "integration", "live" })
+   public void setup() {
+      super.setup();
+
+      locations = ImmutableSet.copyOf(transform(api.getLocationApi().list(),
+               new Function<Location, String>() {
+                  @Override
+                  public String apply(Location in) {
+                     return in.getName();
+                  }
+               }));
+   }
+
+   @Test
+   protected void testList() {
+      List<Image> response = api().list();
+
+      for (Image image : response) {
+         checkOSImage(image);
+      }
+   }
+
+   private void checkOSImage(Image image) {
+      checkNotNull(image.getLabel(), "Label cannot be null for OSImage %s", image);
+      checkNotNull(image.getName(), "Name cannot be null for OSImage %s", image.getLabel());
+      checkNotNull(image.getOS(), "OS cannot be null for OSImage: %s", image);
+      assertNotEquals(image.getOS(), OSType.UNRECOGNIZED, "Status cannot be UNRECOGNIZED for OSImage: " + image);
+
+      checkNotNull(image.getCategory(), "While Category can be null for OSImage, its Optional wrapper cannot: %s",
+               image);
+      if (image.getCategory().isPresent())
+         assertNotEquals("", image.getCategory().get().trim(), "Invalid Category: " + image.toString());
+
+      checkNotNull(image.getLogicalSizeInGB(),
+               "While LogicalSizeInGB can be null for OSImage, its Optional wrapper cannot: %s", image);
+
+      if (image.getLogicalSizeInGB().isPresent())
+         assertTrue(image.getLogicalSizeInGB().get() > 0,
+                  "LogicalSizeInGB should be positive, if set" + image.toString());
+
+      checkNotNull(image.getMediaLink(), "While MediaLink can be null for OSImage, its Optional wrapper cannot: %s",
+               image);
+
+      if (image.getMediaLink().isPresent())
+         assertTrue(ImmutableSet.of("http", "https").contains(image.getMediaLink().get().getScheme()),
+                  "MediaLink should be an http(s) url" + image.toString());
+
+      checkNotNull(image.getDescription(),
+               "While Description can be null for OSImage, its Optional wrapper cannot: %s", image);
+
+      checkNotNull(image.getLocation(), "While Location can be null for OSImage, its Optional wrapper cannot: %s",
+               image);
+      if (image.getLocation().isPresent()) {
+         assertTrue(locations.contains(image.getLocation().get()),
+                  "Location not in " + locations + " :" + image.toString());
+      }
+
+      // Ex. Dirty data in RightScale eula field comes out as an empty string.
+      assertThat(image.getEula()).isNotNull().doesNotContain("");
+
+      checkNotNull(image.getAffinityGroup(),
+               "While AffinityGroup can be null for OSImage, its Optional wrapper cannot: %s", image);
+      if (image.getAffinityGroup().isPresent()) {
+         // TODO: list getAffinityGroups and check if there
+      }
+   }
+
+   private ImageApi api() {
+      return api.getImageApi();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/features/ImageApiMockTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/features/ImageApiMockTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/features/ImageApiMockTest.java
new file mode 100644
index 0000000..6c7b5c4
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/features/ImageApiMockTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.azurecompute.features;
+
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import java.net.URI;
+import org.jclouds.azurecompute.domain.ImageParams;
+import org.jclouds.azurecompute.domain.OSType;
+import org.jclouds.azurecompute.internal.BaseAzureComputeApiMockTest;
+import org.jclouds.azurecompute.parse.ListImagesTest;
+import org.testng.annotations.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Test(groups = "unit", testName = "ImageApiMockTest")
+public class ImageApiMockTest extends BaseAzureComputeApiMockTest {
+
+   public void listWhenFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(xmlResponse("/images.xml"));
+
+      try {
+         ImageApi api = api(server.getUrl("/")).getImageApi();
+
+         assertThat(api.list()).containsExactlyElementsOf(ListImagesTest.expected());
+
+         assertSent(server, "GET", "/services/images");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void listWhenNotFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(new MockResponse().setResponseCode(404));
+
+      try {
+         ImageApi api = api(server.getUrl("/")).getImageApi();
+
+         assertThat(api.list()).isEmpty();
+
+         assertSent(server, "GET", "/services/images");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void add() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(requestIdResponse("request-1"));
+
+      try {
+         ImageApi api = api(server.getUrl("/")).getImageApi();
+
+         ImageParams params = ImageParams.builder().name("myimage").label("foo").os(OSType.LINUX)
+               .mediaLink(URI.create("http://example.blob.core.windows.net/disks/mydisk.vhd")).build();
+
+         assertThat(api.add(params)).isEqualTo("request-1");
+
+         assertSent(server, "POST", "/services/images", "/imageparams.xml");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void update() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(requestIdResponse("request-1"));
+
+      try {
+         ImageApi api = api(server.getUrl("/")).getImageApi();
+
+         ImageParams params = ImageParams.builder().name("myimage").label("foo").os(OSType.LINUX)
+               .mediaLink(URI.create("http://example.blob.core.windows.net/disks/mydisk.vhd")).build();
+
+         assertThat(api.update(params)).isEqualTo("request-1");
+
+         assertSent(server, "PUT", "/services/images/myimage", "/imageparams.xml");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void deleteWhenFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(requestIdResponse("request-1"));
+
+      try {
+         ImageApi api = api(server.getUrl("/")).getImageApi();
+
+         assertThat(api.delete("myimage")).isEqualTo("request-1");
+
+         assertSent(server, "DELETE", "/services/images/myimage");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void deleteWhenNotFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(new MockResponse().setResponseCode(404));
+
+      try {
+         ImageApi api = api(server.getUrl("/")).getImageApi();
+
+         assertThat(api.delete("myimage")).isNull();
+
+         assertSent(server, "DELETE", "/services/images/myimage");
+      } finally {
+         server.shutdown();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/features/LocationApiLiveTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/features/LocationApiLiveTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/features/LocationApiLiveTest.java
new file mode 100644
index 0000000..455ef11
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/features/LocationApiLiveTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.azurecompute.features;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import java.util.Arrays;
+import java.util.List;
+import org.jclouds.azurecompute.domain.Location;
+import org.jclouds.azurecompute.internal.BaseAzureComputeApiLiveTest;
+import org.testng.annotations.Test;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+@Test(groups = "live", testName = "LocationApiLiveTest")
+public class LocationApiLiveTest extends BaseAzureComputeApiLiveTest {
+
+   @Test
+   protected void testList() {
+      List<Location> response = api().list();
+
+      for (Location location : response) {
+         checkLocation(location);
+      }
+
+   }
+
+   private Predicate<String> knownServices = Predicates
+         .in(Arrays.asList("Compute", "Storage", "PersistentVMRole", "HighMemory"));
+
+   private void checkLocation(Location location) {
+      checkNotNull(location.getName(), "Name cannot be null for a Location.");
+      checkNotNull(location.getDisplayName(), "DisplayName cannot be null for Location %s", location.getName());
+      checkNotNull(location.getAvailableServices(), "AvailableServices cannot be null for Location %s",
+            location.getName());
+      checkState(Iterables.all(location.getAvailableServices(), knownServices),
+            "AvailableServices in Location %s didn't match %s: %s", location.getName(), knownServices,
+            location.getAvailableServices());
+   }
+
+   private LocationApi api() {
+      return api.getLocationApi();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/features/LocationApiMockTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/features/LocationApiMockTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/features/LocationApiMockTest.java
new file mode 100644
index 0000000..695b54d
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/features/LocationApiMockTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.azurecompute.features;
+
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import org.jclouds.azurecompute.internal.BaseAzureComputeApiMockTest;
+import org.jclouds.azurecompute.parse.ListLocationsTest;
+import org.testng.annotations.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Test(groups = "unit", testName = "LocationApiMockTest")
+public class LocationApiMockTest extends BaseAzureComputeApiMockTest {
+
+   public void listWhenLocationsFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(xmlResponse("/locations.xml"));
+
+      try {
+         LocationApi api = api(server.getUrl("/")).getLocationApi();
+
+         assertThat(api.list()).containsExactlyElementsOf(ListLocationsTest.expected());
+
+         assertSent(server, "GET", "/locations");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void listWhenLocationsNotFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(new MockResponse().setResponseCode(404));
+
+      try {
+         LocationApi api = api(server.getUrl("/")).getLocationApi();
+
+         assertThat(api.list()).isEmpty();
+
+         assertSent(server, "GET", "/locations");
+      } finally {
+         server.shutdown();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/features/OperationApiMockTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/features/OperationApiMockTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/features/OperationApiMockTest.java
new file mode 100644
index 0000000..2298bc0
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/features/OperationApiMockTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.azurecompute.features;
+
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import org.jclouds.azurecompute.internal.BaseAzureComputeApiMockTest;
+import org.jclouds.azurecompute.parse.GetOperationTest;
+import org.testng.annotations.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Test(groups = "unit", testName = "OperationApiMockTest")
+public class OperationApiMockTest extends BaseAzureComputeApiMockTest {
+
+   public void getWhenFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(xmlResponse("/operation.xml"));
+
+      try {
+         OperationApi api = api(server.getUrl("/")).getOperationApi();
+
+         assertThat(api.get("request-id")).isEqualTo(GetOperationTest.expected());
+
+         assertSent(server, "GET", "/operations/request-id");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void getWhenNotFound() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(new MockResponse().setResponseCode(404));
+
+      try {
+         OperationApi api = api(server.getUrl("/")).getOperationApi();
+
+         assertThat(api.get("request-id")).isNull();
+
+         assertSent(server, "GET", "/operations/request-id");
+      } finally {
+         server.shutdown();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/features/VirtualMachineApiMockTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/features/VirtualMachineApiMockTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/features/VirtualMachineApiMockTest.java
new file mode 100644
index 0000000..7e3ce5a
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/features/VirtualMachineApiMockTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.azurecompute.features;
+
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import org.jclouds.azurecompute.internal.BaseAzureComputeApiMockTest;
+import org.testng.annotations.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Test(groups = "unit", testName = "ApiMockTest")
+public class VirtualMachineApiMockTest extends BaseAzureComputeApiMockTest {
+
+   public void start() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(requestIdResponse("request-1"));
+
+      try {
+         VirtualMachineApi api = vmApi(server);
+
+         assertThat(api.start("myvm")).isEqualTo("request-1");
+
+         assertSent(server, "POST",
+               "/services/hostedservices/my-service/deployments/mydeployment/roleinstances/myvm/Operations",
+               "/startrolepayload.xml");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void restart() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(requestIdResponse("request-1"));
+
+      try {
+         VirtualMachineApi api = vmApi(server);
+
+         assertThat(api.restart("myvm")).isEqualTo("request-1");
+
+         assertSent(server, "POST",
+               "/services/hostedservices/my-service/deployments/mydeployment/roleinstances/myvm/Operations",
+               "/restartrolepayload.xml");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void shutdown() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(requestIdResponse("request-1"));
+
+      try {
+         VirtualMachineApi api = vmApi(server);
+
+         assertThat(api.shutdown("myvm")).isEqualTo("request-1");
+
+         assertSent(server, "POST",
+               "/services/hostedservices/my-service/deployments/mydeployment/roleinstances/myvm/Operations",
+               "/shutdownrolepayload.xml");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   public void capture() throws Exception {
+      MockWebServer server = mockAzureManagementServer();
+      server.enqueue(requestIdResponse("request-1"));
+
+      try {
+         VirtualMachineApi api = vmApi(server);
+
+         assertThat(api.capture("myvm", "myImageName", "myImageLabel")).isEqualTo("request-1");
+
+         assertSent(server, "POST",
+               "/services/hostedservices/my-service/deployments/mydeployment/roleinstances/myvm/Operations",
+               "/capturerolepayload.xml");
+      } finally {
+         server.shutdown();
+      }
+   }
+
+   private VirtualMachineApi vmApi(MockWebServer server) {
+      return api(server.getUrl("/")).getVirtualMachineApiForDeploymentInService("mydeployment", "my-service");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/internal/BaseAzureComputeApiLiveTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/internal/BaseAzureComputeApiLiveTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/internal/BaseAzureComputeApiLiveTest.java
new file mode 100644
index 0000000..5e3fea4
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/internal/BaseAzureComputeApiLiveTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.azurecompute.internal;
+
+import java.util.Properties;
+import org.jclouds.apis.BaseApiLiveTest;
+import org.jclouds.azurecompute.AzureComputeApi;
+
+import static org.jclouds.azurecompute.config.AzureComputeProperties.SUBSCRIPTION_ID;
+
+public class BaseAzureComputeApiLiveTest extends BaseApiLiveTest<AzureComputeApi> {
+
+   protected String subscriptionId;
+
+   public BaseAzureComputeApiLiveTest() {
+      provider = "azurecompute";
+   }
+
+   @Override
+   protected Properties setupProperties() {
+      Properties props = super.setupProperties();
+      subscriptionId = setIfTestSystemPropertyPresent(props, SUBSCRIPTION_ID);
+      return props;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/internal/BaseAzureComputeApiMockTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/internal/BaseAzureComputeApiMockTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/internal/BaseAzureComputeApiMockTest.java
new file mode 100644
index 0000000..0ecba9d
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/internal/BaseAzureComputeApiMockTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.azurecompute.internal;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import com.squareup.okhttp.mockwebserver.RecordedRequest;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Set;
+import org.jclouds.ContextBuilder;
+import org.jclouds.azurecompute.AzureComputeApi;
+import org.jclouds.concurrent.config.ExecutorServiceModule;
+import org.jclouds.util.Strings2;
+
+import static com.google.common.base.Charsets.UTF_8;
+import static com.google.common.util.concurrent.MoreExecutors.newDirectExecutorService;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class BaseAzureComputeApiMockTest {
+   private final Set<Module> modules = ImmutableSet
+         .<Module>of(new ExecutorServiceModule(newDirectExecutorService(), newDirectExecutorService()));
+
+   protected String provider;
+   private final String identity;
+   private final String credential;
+
+   public BaseAzureComputeApiMockTest() {
+      provider = "azurecompute";
+      // self-signed dummy cert:
+      // keytool -genkey -alias test -keyalg RSA -keysize 1024 -validity 5475 -dname "CN=localhost" -keystore azure-test.p12 -storepass azurepass -storetype pkcs12
+      identity = this.getClass().getResource("/azure-test.p12").getFile();
+      credential = "azurepass";
+   }
+
+   public AzureComputeApi api(URL url) {
+      return ContextBuilder.newBuilder(provider).credentials(identity, credential).endpoint(url.toString())
+            .modules(modules).buildApi(AzureComputeApi.class);
+   }
+
+   protected static MockWebServer mockAzureManagementServer() throws IOException {
+      MockWebServer server = new MockWebServer();
+      server.play();
+      return server;
+   }
+
+   protected MockResponse xmlResponse(String resource) {
+      return new MockResponse().addHeader("Content-Type", "application/xml").setBody(stringFromResource(resource));
+   }
+
+   protected MockResponse requestIdResponse(String requestId) {
+      return new MockResponse().addHeader("x-ms-request-id", requestId);
+   }
+
+   protected String stringFromResource(String resourceName) {
+      try {
+         return Strings2.toStringAndClose(getClass().getResourceAsStream(resourceName));
+      } catch (IOException e) {
+         throw Throwables.propagate(e);
+      }
+   }
+
+   protected RecordedRequest assertSent(MockWebServer server, String method, String path) throws InterruptedException {
+      RecordedRequest request = server.takeRequest();
+      assertThat(request.getMethod()).isEqualTo(method);
+      assertThat(request.getPath()).isEqualTo(path);
+      assertThat(request.getHeader("x-ms-version")).isEqualTo("2012-03-01");
+      assertThat(request.getHeader("Accept")).isEqualTo("application/xml");
+      return request;
+   }
+
+   protected RecordedRequest assertSent(MockWebServer server, String method, String path, String resource)
+         throws InterruptedException {
+      RecordedRequest request = assertSent(server, method, path);
+      assertThat(new String(request.getBody(), UTF_8)).isEqualTo(stringFromResource(resource));
+      return request;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/parse/ErrorTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/parse/ErrorTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/parse/ErrorTest.java
new file mode 100644
index 0000000..12d38c6
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/parse/ErrorTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.azurecompute.parse;
+
+import java.io.InputStream;
+import org.jclouds.azurecompute.domain.Error;
+import org.jclouds.azurecompute.domain.Error.Code;
+import org.jclouds.azurecompute.xml.ErrorHandler;
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+@Test(groups = "unit", testName = "ErrorTest")
+public class ErrorTest extends BaseHandlerTest {
+
+   public void test() {
+      InputStream is = getClass().getResourceAsStream("/error.xml");
+
+      Error expected = expected();
+
+      ErrorHandler handler = injector.getInstance(ErrorHandler.class);
+      Error result = factory.create(handler).parse(is);
+
+      assertEquals(result.toString(), expected.toString());
+
+   }
+
+   public Error expected() {
+      return Error.builder()
+                  .rawCode("MissingOrInvalidRequiredQueryParameter")
+                  .code(Code.MISSING_OR_INVALID_REQUIRED_QUERY_PARAMETER)
+                  .message("A required query parameter was not specified for this request or was specified incorrectly.")
+                  .build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetDeploymentTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetDeploymentTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetDeploymentTest.java
new file mode 100644
index 0000000..76bad81
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetDeploymentTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.azurecompute.parse;
+
+import java.io.InputStream;
+import java.net.URI;
+import org.jclouds.azurecompute.domain.Deployment;
+import org.jclouds.azurecompute.domain.DeploymentSlot;
+import org.jclouds.azurecompute.domain.DeploymentStatus;
+import org.jclouds.azurecompute.domain.InstanceStatus;
+import org.jclouds.azurecompute.domain.RoleSize;
+import org.jclouds.azurecompute.xml.DeploymentHandler;
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+@Test(groups = "unit", testName = "GetDeploymentTest")
+public class GetDeploymentTest extends BaseHandlerTest {
+
+   public void test() {
+      InputStream is = getClass().getResourceAsStream("/deployment.xml");
+
+      Deployment expected = expected();
+
+      DeploymentHandler handler = injector.getInstance(DeploymentHandler.class);
+      Deployment result = factory.create(handler).parse(is);
+
+      assertEquals(result.toString(), expected.toString());
+   }
+
+   public static Deployment expected() {
+      return Deployment.builder()
+         .deploymentName("neotysss")
+         .deploymentSlot(DeploymentSlot.PRODUCTION)
+         .deploymentStatus(DeploymentStatus.RUNNING)
+         .deploymentLabel("neotysss")
+         .deploymentURL(URI.create("http://neotysss.cloudapp.net/"))
+         .roleName("neotysss")
+         .instanceName("neotysss")
+         .instanceStatus(InstanceStatus.READY_ROLE)
+         .instanceSize(RoleSize.MEDIUM)
+         .privateIpAddress("10.59.244.162")
+         .publicIpAddress("168.63.27.148")
+         .build();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetHostedServiceDetailsTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetHostedServiceDetailsTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetHostedServiceDetailsTest.java
new file mode 100644
index 0000000..8a71f50
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetHostedServiceDetailsTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.azurecompute.parse;
+
+import java.io.InputStream;
+import java.net.URI;
+import org.jclouds.azurecompute.domain.DetailedHostedServiceProperties;
+import org.jclouds.azurecompute.domain.HostedService;
+import org.jclouds.azurecompute.domain.HostedService.Status;
+import org.jclouds.azurecompute.domain.HostedServiceWithDetailedProperties;
+import org.jclouds.azurecompute.xml.HostedServiceWithDetailedPropertiesHandler;
+import org.jclouds.date.DateService;
+import org.jclouds.date.internal.SimpleDateFormatDateService;
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+@Test(groups = "unit", testName = "DetailedHostedServiceProperties")
+public class GetHostedServiceDetailsTest extends BaseHandlerTest {
+
+   public void test() {
+      InputStream is = getClass().getResourceAsStream("/hostedservice_details.xml");
+
+      HostedService expected = expected();
+
+      HostedServiceWithDetailedPropertiesHandler handler = injector.getInstance(HostedServiceWithDetailedPropertiesHandler.class);
+      HostedServiceWithDetailedProperties result = HostedServiceWithDetailedProperties.class.cast(factory.create(handler).parse(is));
+
+      assertEquals(result.toString(), expected.toString());
+
+   }
+
+   private static final DateService dateService = new SimpleDateFormatDateService();
+
+   public static HostedServiceWithDetailedProperties expected() {
+      return HostedServiceWithDetailedProperties.builder()
+                          .url(URI.create("https://management.core.windows.net/eb0347c3-68d4-4550-9b39-5e7e0f92f7db/services/hostedservices/neotys"))
+                          .name("neotys")
+                          .properties(DetailedHostedServiceProperties.builder()
+                                                                     .description("Implicitly created hosted service2012-08-06 14:55")
+                                                                     .location("West Europe")
+                                                                     .label("neotys")
+                                                                     .rawStatus("Created")
+                                                                     .status(Status.CREATED)
+                                                                     .created(dateService.iso8601SecondsDateParse("2012-08-06T14:55:17Z"))
+                                                                     .lastModified(dateService.iso8601SecondsDateParse("2012-08-06T15:50:34Z"))
+                                                                     .build())
+                          .build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetHostedServiceTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetHostedServiceTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetHostedServiceTest.java
new file mode 100644
index 0000000..b5ccd31
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetHostedServiceTest.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.azurecompute.parse;
+
+import java.io.InputStream;
+import java.net.URI;
+import org.jclouds.azurecompute.domain.HostedService;
+import org.jclouds.azurecompute.domain.HostedServiceProperties;
+import org.jclouds.azurecompute.xml.HostedServiceHandler;
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+@Test(groups = "unit", testName = "GetHostedServiceTest")
+public class GetHostedServiceTest extends BaseHandlerTest {
+
+   public void test() {
+      InputStream is = getClass().getResourceAsStream("/hostedservice.xml");
+
+      HostedService expected = expected();
+
+      HostedServiceHandler handler = injector.getInstance(HostedServiceHandler.class);
+      HostedService result = factory.create(handler).parse(is);
+
+      assertEquals(result.toString(), expected.toString());
+
+   }
+
+   public static HostedService expected() {
+      return HostedService.builder()
+                          .url(URI.create("https://management.core.windows.net/eb0347c3-68d4-4550-9b39-5e7e0f92f7db/services/hostedservices/neotys"))
+                          .name("neotys")
+                          .properties(HostedServiceProperties.builder()
+                                                             .description("Implicitly created hosted service2012-08-06 14:55")
+                                                             .location("West Europe")
+                                                             .label("neotys")
+                                                             .build())
+                          .build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetOperationTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetOperationTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetOperationTest.java
new file mode 100644
index 0000000..ecf7083
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/parse/GetOperationTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.azurecompute.parse;
+
+import java.io.InputStream;
+import org.jclouds.azurecompute.domain.Error;
+import org.jclouds.azurecompute.domain.Error.Code;
+import org.jclouds.azurecompute.domain.Operation;
+import org.jclouds.azurecompute.domain.Operation.Status;
+import org.jclouds.azurecompute.xml.OperationHandler;
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+@Test(groups = "unit", testName = "GetOperationTest")
+public class GetOperationTest extends BaseHandlerTest {
+
+   public void test() {
+      InputStream is = getClass().getResourceAsStream("/operation.xml");
+
+      Operation expected = expected();
+
+      OperationHandler handler = injector.getInstance(OperationHandler.class);
+      Operation result = factory.create(handler).parse(is);
+
+      assertEquals(result.toString(), expected.toString());
+   }
+
+   public static Operation expected() {
+      return Operation.builder()
+                      .id("request-id")
+                      .rawStatus("Failed")
+                      .status(Status.FAILED)
+                      .httpStatusCode(400)
+                      .error(Error.builder()
+                                  .rawCode("MissingOrInvalidRequiredQueryParameter")
+                                  .code(Code.MISSING_OR_INVALID_REQUIRED_QUERY_PARAMETER)
+                                  .message("A required query parameter was not specified for this request or was specified incorrectly.")
+                                  .build())
+                      .build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6ab58bd2/azurecompute/src/test/java/org/jclouds/azurecompute/parse/ListDisksTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/parse/ListDisksTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/parse/ListDisksTest.java
new file mode 100644
index 0000000..390b007
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/parse/ListDisksTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.azurecompute.parse;
+
+import com.google.common.collect.ImmutableSet;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.List;
+import java.util.Set;
+import org.jclouds.azurecompute.domain.Disk;
+import org.jclouds.azurecompute.domain.Disk.Attachment;
+import org.jclouds.azurecompute.domain.OSType;
+import org.jclouds.azurecompute.xml.ListDisksHandler;
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+@Test(groups = "unit", testName = "ListDisksTest")
+public class ListDisksTest extends BaseHandlerTest {
+
+   public void test() {
+      InputStream is = getClass().getResourceAsStream("/disks.xml");
+
+      Set<Disk> expected = expected();
+
+      ListDisksHandler handler = injector.getInstance(ListDisksHandler.class);
+      List<Disk> result = factory.create(handler).parse(is);
+
+      assertEquals(result.toString(), expected.toString());
+
+   }
+
+   public static Set<Disk> expected() {
+
+      return ImmutableSet.<Disk>builder()
+                         .add(Disk.builder()
+                                     .os(OSType.LINUX)
+                                     .location("West Europe")
+                                     .logicalSizeInGB(30)
+                                     .mediaLink(URI.create("http://neotysbucket1.blob.core.windows.net/vhds/testimage2-testimage2-2012-08-17.vhd"))
+                                     .name("testimage2-testimage2-0-20120817095145")
+                                     .sourceImage("OpenLogic__OpenLogic-CentOS-62-20120531-en-us-30GB.vhd")
+                                     .build())
+                          .add(Disk.builder()
+                                     .attachedTo(Attachment.builder().deployment("neotysss").hostedService("neotysss").role("neotysss").build())
+                                     .os(OSType.WINDOWS)
+                                     .location("West Europe")
+                                     .logicalSizeInGB(30)
+                                     .mediaLink(URI.create("http://portalvhds0g7xhnq2x7t21.blob.core.windows.net/disks/neotysss/MSFT__Win2K8R2SP1-120612-1520-121206-01-en-us-30GB.vhd"))
+                                     .name("neotysss-neotysss-0-20120824091357")
+                                     .sourceImage("MSFT__Win2K8R2SP1-120612-1520-121206-01-en-us-30GB.vhd")
+                                     .build())
+                        .build();
+   }
+
+}