You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by na...@apache.org on 2015/04/20 11:30:13 UTC

jclouds-labs git commit: JCLOUDS-839: Get Cloud Service Properties Operation Support

Repository: jclouds-labs
Updated Branches:
  refs/heads/1.9.x c607a19ad -> bc99a7028


JCLOUDS-839: Get Cloud Service Properties Operation Support

Minor change

Added Mock Tests to Cloud Service Properties


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

Branch: refs/heads/1.9.x
Commit: bc99a70283f4354c8c0265b87ed8d8f193de45b9
Parents: c607a19
Author: hsbhathiya <hs...@gmail.com>
Authored: Tue Mar 17 21:50:00 2015 +0530
Committer: Ignasi Barrera <na...@apache.org>
Committed: Mon Apr 20 11:26:00 2015 +0200

----------------------------------------------------------------------
 .../domain/CloudServiceProperties.java          |  96 ++++++++++++
 .../azurecompute/features/CloudServiceApi.java  |  26 ++++
 .../xml/CloudServicePropertiesHandler.java      | 155 +++++++++++++++++++
 .../features/CloudServiceApiMockTest.java       |  31 ++++
 .../features/DeploymentApiLiveTest.java         |  24 +++
 .../xml/CloudServicePropertiesHandlerTest.java  | 147 ++++++++++++++++++
 .../test/resources/cloudserviceproperties.xml   | 120 ++++++++++++++
 7 files changed, 599 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/bc99a702/azurecompute/src/main/java/org/jclouds/azurecompute/domain/CloudServiceProperties.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/domain/CloudServiceProperties.java b/azurecompute/src/main/java/org/jclouds/azurecompute/domain/CloudServiceProperties.java
new file mode 100644
index 0000000..a363b83
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/domain/CloudServiceProperties.java
@@ -0,0 +1,96 @@
+/*
+ * 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.domain;
+
+import com.google.auto.value.AutoValue;
+import org.jclouds.javax.annotation.Nullable;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.collect.ImmutableMap.copyOf;
+import static com.google.common.collect.ImmutableList.copyOf;
+
+/**
+ * System properties for the specified cloud service. These properties include the service name and
+ * service type; the name of the affinity group to which the service belongs, or its location if it
+ * is not part of an affinity group.
+ *
+ * @see <a href="https://msdn.microsoft.com/en-us/library/azure/ee460806.aspx" >CloudService</a>
+ */
+@AutoValue
+public abstract class CloudServiceProperties {
+
+   public enum Status {
+      CREATING, CREATED, DELETING, DELETED, CHANGING, RESOLVING_DNS,
+      UNRECOGNIZED;
+   }
+
+   CloudServiceProperties() {
+   } // For AutoValue only!
+
+   /**
+    * The name of the cloud service. This name is the DNS prefix name and can be used to access the
+    * cloud service.
+    * <p/>
+    * <p/>For example, if the service name is MyService you could access the access the service by
+    * calling: http://MyService.cloudapp.net
+    */
+   public abstract String serviceName();
+
+   public abstract URI url();
+
+   /**
+    * The geo-location of the cloud service in Windows Azure, if the cloud service is not
+    * associated with an affinity group. If a location has been specified, the AffinityGroup element
+    * is not returned.
+    */
+   @Nullable public abstract String location();
+
+   /**
+    * The affinity group with which this cloud service is associated, if any. If the service is
+    * associated with an affinity group, the Location element is not returned.
+    */
+   @Nullable public abstract String affinityGroup();
+
+   /**
+    * The name can be up to 100 characters in length. The name can be used identify the storage account for your
+    * tracking purposes.
+    */
+   public abstract String label();
+
+   @Nullable public abstract String description();
+
+   @Nullable public abstract Status status();
+
+   @Nullable public abstract Date created();
+
+   @Nullable public abstract Date lastModified();
+
+   public abstract Map<String, String> extendedProperties();
+
+   public abstract List<Deployment> deployments();
+
+   public static CloudServiceProperties create(String name, URI url, String location, String affinityGroup,
+         String label, String description, Status status, Date created, Date lastModified, Map<String, String> extendedProperties,
+         List<Deployment> deployments) {
+      return new AutoValue_CloudServiceProperties(name, url, location, affinityGroup, label, description, status,
+            created, lastModified, copyOf(extendedProperties), copyOf(deployments));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/bc99a702/azurecompute/src/main/java/org/jclouds/azurecompute/features/CloudServiceApi.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/features/CloudServiceApi.java b/azurecompute/src/main/java/org/jclouds/azurecompute/features/CloudServiceApi.java
index 94d203f..c33c8b8 100644
--- a/azurecompute/src/main/java/org/jclouds/azurecompute/features/CloudServiceApi.java
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/features/CloudServiceApi.java
@@ -32,9 +32,11 @@ import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 
 import org.jclouds.azurecompute.domain.CloudService;
+import org.jclouds.azurecompute.domain.CloudServiceProperties;
 import org.jclouds.azurecompute.functions.Base64EncodeLabel;
 import org.jclouds.azurecompute.functions.ParseRequestIdHeader;
 import org.jclouds.azurecompute.xml.CloudServiceHandler;
+import org.jclouds.azurecompute.xml.CloudServicePropertiesHandler;
 import org.jclouds.azurecompute.xml.ListCloudServicesHandler;
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.rest.annotations.Fallback;
@@ -122,4 +124,28 @@ public interface CloudServiceApi {
    @Fallback(NullOnNotFoundOr404.class)
    @ResponseParser(ParseRequestIdHeader.class)
    String delete(@PathParam("name") String name);
+
+   /*
+   * The Get Cloud Service Properties operation retrieves properties for the specified cloud service.
+   *
+   * These properties include the following values:
+   *  The name and the description of the cloud service.
+   *
+   *  The name of the affinity group to which the cloud service belongs, or its location if it is not part of an affinity group.
+   *
+   *  The label that can be used to track the cloud service.
+   *
+   *  The date and time that the cloud service was created or modified.
+   *
+   *  If details are requested, information about deployments in the cloud service is returned.
+   *
+   * */
+
+   @Named("CloudServiceProperties")
+   @GET
+   @Path("/{name}")
+   @QueryParams(keys = "embed-detail", values = "true")
+   @XMLResponseParser(CloudServicePropertiesHandler.class)
+   @Fallback(NullOnNotFoundOr404.class)
+   @Nullable CloudServiceProperties getProperties(@PathParam("name") String name);
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/bc99a702/azurecompute/src/main/java/org/jclouds/azurecompute/xml/CloudServicePropertiesHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/CloudServicePropertiesHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/CloudServicePropertiesHandler.java
new file mode 100644
index 0000000..40b6b9f
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/CloudServicePropertiesHandler.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.azurecompute.xml;
+
+import autovalue.shaded.com.google.common.common.collect.ImmutableList;
+import autovalue.shaded.com.google.common.common.collect.Lists;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import org.jclouds.azurecompute.domain.CloudServiceProperties;
+import org.jclouds.azurecompute.domain.Deployment;
+import org.jclouds.date.DateService;
+import org.jclouds.http.functions.ParseSax;
+import org.xml.sax.Attributes;
+
+import javax.inject.Inject;
+import java.net.URI;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
+import static org.jclouds.util.SaxUtils.currentOrNull;
+
+/**
+ * @see <a href="https://msdn.microsoft.com/en-us/library/azure/ee460806.aspx" >Response body description</a>
+ */
+public final class CloudServicePropertiesHandler
+      extends ParseSax.HandlerForGeneratedRequestWithResult<CloudServiceProperties> {
+   private String name;
+   private URI url;
+   private String location;
+   private String affinityGroup;
+   private String label;
+   private String description;
+   private CloudServiceProperties.Status status;
+   private Date created;
+   private Date lastModified;
+   private Map<String, String> extendedProperties = Maps.newLinkedHashMap();
+   private List<Deployment> deploymentList = Lists.newArrayList();
+
+   private boolean inHostedServiceProperties;
+   private boolean inDeployment;
+   private String propertyName;
+   private StringBuilder currentText = new StringBuilder();
+   private final DateService dateService;
+   private final DeploymentHandler deploymentHandler;
+
+   @Inject CloudServicePropertiesHandler(DateService dateService, DeploymentHandler deploymentHandler) {
+      this.dateService = dateService;
+      this.deploymentHandler = deploymentHandler;
+   }
+
+   @Override public CloudServiceProperties getResult() {
+      CloudServiceProperties result = CloudServiceProperties
+            .create(name, url, location, affinityGroup, label, description, status, created, //
+                  lastModified, ImmutableMap.copyOf(extendedProperties), ImmutableList.copyOf(deploymentList));
+      resetState(); // handler is called in a loop.
+      return result;
+   }
+
+   private void resetState() {
+      name = description = location = affinityGroup = label = null;
+      status = null;
+      created = lastModified = null;
+      extendedProperties.clear();
+      inHostedServiceProperties = false;
+      propertyName = null;
+   }
+
+   @Override public void startElement(String ignoredUri, String ignoredLocalName, String qName,
+         Attributes ignoredAttributes) {
+      if (qName.equals("HostedServiceProperties")) {
+         inHostedServiceProperties = true;
+      } else if (qName.equals("Deployment")) {
+         inDeployment = true;
+      }
+      if (inDeployment) {
+         deploymentHandler.startElement(ignoredUri, ignoredLocalName, qName, ignoredAttributes);
+      }
+   }
+
+   @Override public void endElement(String ignoredUri, String ignoredName, String qName) {
+      if (qName.equals("HostedServiceProperties")) {
+         inHostedServiceProperties = false;
+      } else if (inHostedServiceProperties) {
+         if (qName.equals("DateCreated")) {
+            created = dateService.iso8601SecondsDateParse(currentOrNull(currentText));
+         } else if (qName.equals("DateLastModified")) {
+            lastModified = dateService.iso8601SecondsDateParse(currentOrNull(currentText));
+         } else if (qName.equals("Status")) {
+            String statusText = currentOrNull(currentText);
+            if (statusText != null) {
+               status = status(statusText);
+            }
+         } else if (qName.equals("Name")) {
+            propertyName = currentOrNull(currentText);
+         } else if (qName.equals("Value")) {
+            extendedProperties.put(propertyName, currentOrNull(currentText));
+            propertyName = null;
+         } else if (qName.equals("Description")) {
+            description = currentOrNull(currentText);
+         } else if (qName.equals("Location")) {
+            location = currentOrNull(currentText);
+         } else if (qName.equals("AffinityGroup")) {
+            affinityGroup = currentOrNull(currentText);
+         } else if (qName.equals("Label")) {
+            label = currentOrNull(currentText);
+         }
+      } else if (qName.equals("ServiceName")) {
+         name = currentOrNull(currentText);
+      } else if (qName.equals("Deployment")) {
+         deploymentList.add(deploymentHandler.getResult());
+         inDeployment = false;
+      } else if (inDeployment) {
+         deploymentHandler.endElement(ignoredUri, ignoredName, qName);
+      } else if (qName.equals("Url")) {
+         String link = currentOrNull(currentText);
+         if (link != null) {
+            url = URI.create(link);
+         }
+      }
+      currentText.setLength(0);
+   }
+
+   @Override public void characters(char ch[], int start, int length) {
+      if (inDeployment) {
+         deploymentHandler.characters(ch, start, length);
+      } else {
+         currentText.append(ch, start, length);
+      }
+   }
+
+   private static CloudServiceProperties.Status status(String status) {
+      try {
+         return CloudServiceProperties.Status.valueOf(UPPER_CAMEL.to(UPPER_UNDERSCORE, status));
+      } catch (IllegalArgumentException e) {
+         return CloudServiceProperties.Status.UNRECOGNIZED;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/bc99a702/azurecompute/src/test/java/org/jclouds/azurecompute/features/CloudServiceApiMockTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/features/CloudServiceApiMockTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/features/CloudServiceApiMockTest.java
index a929fff..c321d5d 100644
--- a/azurecompute/src/test/java/org/jclouds/azurecompute/features/CloudServiceApiMockTest.java
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/features/CloudServiceApiMockTest.java
@@ -22,6 +22,7 @@ import static org.testng.Assert.assertTrue;
 
 import org.jclouds.azurecompute.internal.BaseAzureComputeApiMockTest;
 import org.jclouds.azurecompute.xml.CloudServiceHandlerTest;
+import org.jclouds.azurecompute.xml.CloudServicePropertiesHandlerTest;
 import org.jclouds.azurecompute.xml.ListCloudServicesHandlerTest;
 import org.testng.annotations.Test;
 
@@ -91,6 +92,36 @@ public class CloudServiceApiMockTest extends BaseAzureComputeApiMockTest {
       }
    }
 
+    public void getPropertiesWhenFound() throws Exception {
+        MockWebServer server = mockAzureManagementServer();
+        server.enqueue(xmlResponse("/cloudserviceproperties.xml"));
+
+        try {
+            CloudServiceApi api = api(server.getUrl("/")).getCloudServiceApi();
+
+            assertEquals(api.getProperties("myservice"), CloudServicePropertiesHandlerTest.expected());
+
+            assertSent(server, "GET", "/services/hostedservices/myservice?embed-detail=true");
+        } finally {
+            server.shutdown();
+        }
+    }
+
+    public void getPropertiesWhenNotFound() throws Exception {
+        MockWebServer server = mockAzureManagementServer();
+        server.enqueue(new MockResponse().setResponseCode(404));
+
+        try {
+            CloudServiceApi api = api(server.getUrl("/")).getCloudServiceApi();
+
+            assertNull(api.getProperties("myservice"));
+
+            assertSent(server, "GET", "/services/hostedservices/myservice?embed-detail=true");
+        } finally {
+            server.shutdown();
+        }
+    }
+
    public void createWithLabelInLocation() throws Exception {
       MockWebServer server = mockAzureManagementServer();
       server.enqueue(requestIdResponse("request-1"));

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/bc99a702/azurecompute/src/test/java/org/jclouds/azurecompute/features/DeploymentApiLiveTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/features/DeploymentApiLiveTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/features/DeploymentApiLiveTest.java
index 5cbf7f5..17e5f3a 100644
--- a/azurecompute/src/test/java/org/jclouds/azurecompute/features/DeploymentApiLiveTest.java
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/features/DeploymentApiLiveTest.java
@@ -21,6 +21,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.jclouds.util.Predicates2.retry;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertEquals;
 
 import java.util.logging.Logger;
 
@@ -30,6 +31,7 @@ import org.jclouds.azurecompute.domain.Deployment;
 import org.jclouds.azurecompute.domain.DeploymentParams;
 import org.jclouds.azurecompute.domain.OSImage;
 import org.jclouds.azurecompute.domain.RoleSize;
+import org.jclouds.azurecompute.domain.CloudServiceProperties;
 import org.jclouds.azurecompute.internal.BaseAzureComputeApiLiveTest;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -118,6 +120,17 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest {
       assertThat(foundDeployment).isEqualToComparingFieldByField(deployment);
    }
 
+   // Test CloudServiceProperties with a deployment
+   @Test(dependsOnMethods = "testCreate")
+   public void testGetProperties() {
+      CloudServiceProperties cloudServiceProperties = api.getCloudServiceApi().getProperties(cloudService.name());
+      assertNotNull(cloudServiceProperties);
+      assertEquals(cloudServiceProperties.serviceName(), CLOUD_SERVICE);
+
+      Deployment deployment = cloudServiceProperties.deployments().get(0);
+      checkDeployment(deployment);
+   }
+
    @Test(dependsOnMethods = "testGet")
    public void testDelete() {
       final List<Role> roles = api.getDeploymentApiForService(cloudService.name()).get(DEPLOYMENT).roleList();
@@ -155,6 +168,17 @@ public class DeploymentApiLiveTest extends BaseAzureComputeApiLiveTest {
       }
    }
 
+   private void checkDeployment(Deployment deployment) {
+      assertNotNull(deployment);
+      assertNotNull(deployment.name(), "Name cannot be Null for Deployment" + deployment);
+      assertTrue(deployment.roleList().size() > 0, "There should be atleast 1 Virtual machine for a deployment  ");
+      assertNotNull(deployment.label(), "Label cannot be Null for Deployment" + deployment);
+
+      Deployment.Slot slot = deployment.slot();
+      assertTrue((slot == Deployment.Slot.PRODUCTION) || (slot == Deployment.Slot.STAGING));
+      assertEquals(deployment.name(), DEPLOYMENT);
+   }
+
    @Override
    @AfterClass(groups = "live", alwaysRun = true)
    protected void tearDown() {

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/bc99a702/azurecompute/src/test/java/org/jclouds/azurecompute/xml/CloudServicePropertiesHandlerTest.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/java/org/jclouds/azurecompute/xml/CloudServicePropertiesHandlerTest.java b/azurecompute/src/test/java/org/jclouds/azurecompute/xml/CloudServicePropertiesHandlerTest.java
new file mode 100644
index 0000000..6390442
--- /dev/null
+++ b/azurecompute/src/test/java/org/jclouds/azurecompute/xml/CloudServicePropertiesHandlerTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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 static org.testng.Assert.assertEquals;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.jclouds.azurecompute.domain.Deployment;
+import org.jclouds.azurecompute.domain.CloudServiceProperties;
+import org.jclouds.azurecompute.domain.RoleSize;
+import org.jclouds.azurecompute.domain.Role;
+import org.jclouds.azurecompute.domain.DataVirtualHardDisk;
+import org.jclouds.azurecompute.domain.OSImage;
+import org.jclouds.azurecompute.domain.Deployment.InstanceStatus;
+import org.jclouds.azurecompute.domain.Deployment.Slot;
+import org.jclouds.azurecompute.domain.Deployment.Status;
+import org.jclouds.azurecompute.domain.Role.ConfigurationSet;
+import org.jclouds.azurecompute.domain.Role.ConfigurationSet.InputEndpoint;
+import org.jclouds.azurecompute.domain.Role.OSVirtualHardDisk;
+import org.jclouds.date.DateService;
+import org.jclouds.date.internal.SimpleDateFormatDateService;
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.testng.annotations.Test;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.util.List;
+
+@Test(groups = "unit", testName = "CloudServicePropertiesHandlerTest")
+public class CloudServicePropertiesHandlerTest extends BaseHandlerTest {
+
+    private static final DateService DATE_SERVICE = new SimpleDateFormatDateService();
+
+    public void test() {
+        InputStream is = getClass().getResourceAsStream("/cloudserviceproperties.xml");
+        CloudServiceProperties result = factory.create(
+                new CloudServicePropertiesHandler(DATE_SERVICE, new DeploymentHandler(
+                        new VirtualIPHandler(),
+                        new RoleInstanceHandler(),
+                        new RoleHandler(
+                                new ConfigurationSetHandler(new InputEndpointHandler(), new SubnetNameHandler()),
+                                new OSVirtualHardDiskHandler(),
+                                new DataVirtualHardDiskHandler(),
+                                new ResourceExtensionReferenceHandler(new ResourceExtensionParameterValueHandler())))))
+                .parse(is);
+        assertEquals(result, expected());
+    }
+
+    public static CloudServiceProperties expected() {
+        return CloudServiceProperties.create("neotys",
+                URI.create("https://api/services/hostedservices/neotys"),
+                "West Europe",
+                null,
+                "bmVvdHlz",
+                "Implicitly created cloud service2012-08-06 14:55",
+                CloudServiceProperties.Status.CREATED,
+                DATE_SERVICE.iso8601SecondsDateParse("2012-08-06T14:55:17Z"), // created
+                DATE_SERVICE.iso8601SecondsDateParse("2012-08-06T15:50:34Z"),
+                ImmutableMap.<String, String>builder().build(),
+                deploymentList()
+        );
+    }
+
+    private static List<Deployment> deploymentList() {
+        return ImmutableList.of(
+                Deployment.create( //
+                        "node1855162607153993262-b26", // name
+                        Slot.PRODUCTION, // slot
+                        Status.RUNNING, // status
+                        "node1855162607153993262-b26", // label
+                        null, // instanceStateDetails
+                        null, // instanceErrorCode
+                        ImmutableList.of(Deployment.VirtualIP.create("191.233.85.49", true,
+                                "node1855162607153993262-b26ContractContract")), //virtualIPs
+                        ImmutableList.of(Deployment.RoleInstance.create(
+                                "node1855162607153993262-b26", // roleName
+                                "node1855162607153993262-b26", // instanceName
+                                InstanceStatus.READY_ROLE, //instanceStatus
+                                Deployment.PowerState.STARTED,
+                                0,
+                                0,
+                                RoleSize.Type.BASIC_A0,
+                                "10.0.2.6",
+                                "node1855162607153993262-b26", // hostname
+                                ImmutableList.of(
+                                        Deployment.InstanceEndpoint.create(
+                                                "tcp_22-22", // name
+                                                "191.233.85.49", // vip
+                                                22, // publicPort
+                                                22, // localPort
+                                                "tcp" // protocol
+                                        )
+                                )
+                        )),
+                        ImmutableList.of(Role.create(
+                                "node1855162607153993262-b26",
+                                "PersistentVMRole",
+                                null,
+                                null,
+                                ImmutableList.of(ConfigurationSet.create(
+                                        "NetworkConfiguration",
+                                        ImmutableList.of(
+                                                InputEndpoint.create("tcp_22-22", "tcp", 22, 22, "191.233.85.49",
+                                                        false, null, null, null),
+                                                InputEndpoint.create("tcp_2375-2375", "tcp", 2375, 2375,
+                                                        "191.233.85.49", false, null, null, null)
+                                        ),
+                                        ImmutableList.of(ConfigurationSet.SubnetName.create("Subnet-1")),
+                                        null,
+                                        ImmutableList.<ConfigurationSet.PublicIP>of(),
+                                        null)),
+                                ImmutableList.<Role.ResourceExtensionReference>of(),
+                                null,
+                                ImmutableList.<DataVirtualHardDisk>of(),
+                                OSVirtualHardDisk.create(
+                                        "ReadWrite",
+                                        "node1855162607153993262-b26-node1855162607153993262-b26-0-201412221704390597",
+                                        null,
+                                        null,
+                                        URI.create(
+                                                "https://test.blob.core.windows.net/clockerblob/container-node1855162607153993262-b26.vhd"),
+                                        "b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu_DAILY_BUILD-trusty-14_04_1-LTS-amd64-server-20141212-en-us-30GB",
+                                        OSImage.Type.LINUX),
+                                RoleSize.Type.BASIC_A0,
+                                null,
+                                null
+                        )),
+                        "jclouds" // virtualNetworkName
+                )
+        );
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/bc99a702/azurecompute/src/test/resources/cloudserviceproperties.xml
----------------------------------------------------------------------
diff --git a/azurecompute/src/test/resources/cloudserviceproperties.xml b/azurecompute/src/test/resources/cloudserviceproperties.xml
new file mode 100644
index 0000000..bd2d58f
--- /dev/null
+++ b/azurecompute/src/test/resources/cloudserviceproperties.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<HostedService xmlns="http://schemas.microsoft.com/windowsazure">
+    <Url>https://api/services/hostedservices/neotys</Url>
+    <ServiceName>neotys</ServiceName>
+    <HostedServiceProperties>
+        <Description>Implicitly created cloud service2012-08-06 14:55</Description>
+        <Location>West Europe</Location>
+        <Label>bmVvdHlz</Label>
+        <Status>Created</Status>
+        <DateCreated>2012-08-06T14:55:17Z</DateCreated>
+        <DateLastModified>2012-08-06T15:50:34Z</DateLastModified>
+        <ExtendedProperties/>
+    </HostedServiceProperties>
+    <Deployments>
+        <Deployment xmlns="http://schemas.microsoft.com/windowsazure">
+            <Name>node1855162607153993262-b26</Name>
+            <DeploymentSlot>Production</DeploymentSlot>
+            <PrivateID>706868c87c1847f28a47644b68f3babf</PrivateID>
+            <Status>Running</Status>
+            <Label>bm9kZTE4NTUxNjI2MDcxNTM5OTMyNjItYjI2</Label>
+            <Url>http://node1855162607153993262-b26.cloudapp.net/</Url>
+            <Configuration>
+                PFNlcnZpY2VDb25maWd1cmF0aW9uIHhtbG5zOnhzZD0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL1NlcnZpY2VIb3N0aW5nLzIwMDgvMTAvU2VydmljZUNvbmZpZ3VyYXRpb24iPg0KICA8Um9sZSBuYW1lPSJub2RlMTg1NTE2MjYwNzE1Mzk5MzI2Mi1iMjYiPg0KICAgIDxJbnN0YW5jZXMgY291bnQ9IjEiIC8+DQogIDwvUm9sZT4NCjwvU2VydmljZUNvbmZpZ3VyYXRpb24+
+            </Configuration>
+            <RoleInstanceList>
+                <RoleInstance>
+                    <RoleName>node1855162607153993262-b26</RoleName>
+                    <InstanceName>node1855162607153993262-b26</InstanceName>
+                    <InstanceStatus>ReadyRole</InstanceStatus>
+                    <InstanceUpgradeDomain>0</InstanceUpgradeDomain>
+                    <InstanceFaultDomain>0</InstanceFaultDomain>
+                    <InstanceSize>Basic_A0</InstanceSize>
+                    <InstanceStateDetails/>
+                    <IpAddress>10.0.2.6</IpAddress>
+                    <InstanceEndpoints>
+                        <InstanceEndpoint>
+                            <Name>tcp_22-22</Name>
+                            <Vip>191.233.85.49</Vip>
+                            <PublicPort>22</PublicPort>
+                            <LocalPort>22</LocalPort>
+                            <Protocol>tcp</Protocol>
+                        </InstanceEndpoint>
+                    </InstanceEndpoints>
+                    <PowerState>Started</PowerState>
+                    <HostName>node1855162607153993262-b26</HostName>
+                </RoleInstance>
+            </RoleInstanceList>
+            <UpgradeDomainCount>1</UpgradeDomainCount>
+            <RoleList>
+                <Role>
+                    <RoleName>node1855162607153993262-b26</RoleName>
+                    <OsVersion/>
+                    <RoleType>PersistentVMRole</RoleType>
+                    <ConfigurationSets>
+                        <ConfigurationSet>
+                            <ConfigurationSetType>NetworkConfiguration</ConfigurationSetType>
+                            <InputEndpoints>
+                                <InputEndpoint>
+                                    <LocalPort>22</LocalPort>
+                                    <Name>tcp_22-22</Name>
+                                    <Port>22</Port>
+                                    <Protocol>tcp</Protocol>
+                                    <Vip>191.233.85.49</Vip>
+                                    <EnableDirectServerReturn>false</EnableDirectServerReturn>
+                                </InputEndpoint>
+                                <InputEndpoint>
+                                    <LocalPort>2375</LocalPort>
+                                    <Name>tcp_2375-2375</Name>
+                                    <Port>2375</Port>
+                                    <Protocol>tcp</Protocol>
+                                    <Vip>191.233.85.49</Vip>
+                                    <EnableDirectServerReturn>false</EnableDirectServerReturn>
+                                </InputEndpoint>
+                            </InputEndpoints>
+                            <SubnetNames>
+                                <SubnetName>Subnet-1</SubnetName>
+                            </SubnetNames>
+                        </ConfigurationSet>
+                    </ConfigurationSets>
+                    <DataVirtualHardDisks/>
+                    <OSVirtualHardDisk>
+                        <HostCaching>ReadWrite</HostCaching>
+                        <DiskName>node1855162607153993262-b26-node1855162607153993262-b26-0-201412221704390597
+                        </DiskName>
+                        <MediaLink>
+                            https://test.blob.core.windows.net/clockerblob/container-node1855162607153993262-b26.vhd
+                        </MediaLink>
+                        <SourceImageName>
+                            b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu_DAILY_BUILD-trusty-14_04_1-LTS-amd64-server-20141212-en-us-30GB
+                        </SourceImageName>
+                        <OS>Linux</OS>
+                    </OSVirtualHardDisk>
+                    <RoleSize>Basic_A0</RoleSize>
+                </Role>
+            </RoleList>
+            <SdkVersion/>
+            <Locked>false</Locked>
+            <RollbackAllowed>false</RollbackAllowed>
+            <VirtualNetworkName>jclouds</VirtualNetworkName>
+            <CreatedTime>2014-12-22T17:04:35Z</CreatedTime>
+            <LastModifiedTime>2014-12-22T17:07:02Z</LastModifiedTime>
+            <ExtendedProperties/>
+            <PersistentVMDowntime>
+                <StartTime>2014-12-02T01:25:12Z</StartTime>
+                <EndTime>2014-12-04T01:25:12Z</EndTime>
+                <Status>PersistentVMUpdateScheduled</Status>
+            </PersistentVMDowntime>
+            <VirtualIPs>
+                <VirtualIP>
+                    <Address>191.233.85.49</Address>
+                    <IsDnsProgrammed>true</IsDnsProgrammed>
+                    <Name>node1855162607153993262-b26ContractContract</Name>
+                </VirtualIP>
+            </VirtualIPs>
+            <InternalDnsSuffix>node1855162607153993262-b26.a5.internal.cloudapp.net</InternalDnsSuffix>
+            <LoadBalancers/>
+        </Deployment>
+    </Deployments>
+    <DefaultWinRmCertificateThumbprint>thumbprint-of-winrm-certificate</DefaultWinRmCertificateThumbprint>
+</HostedService>
\ No newline at end of file