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 2017/07/06 14:18:34 UTC

[1/2] jclouds-labs git commit: JCLOUDS-1255 Dimension Data Network API implementation.

Repository: jclouds-labs
Updated Branches:
  refs/heads/master 4febcfa6b -> 2495dd9a6


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/utils/ResponseParseTest.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/utils/ResponseParseTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/utils/ResponseParseTest.java
new file mode 100644
index 0000000..5c4ea1d
--- /dev/null
+++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/utils/ResponseParseTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.dimensiondata.cloudcontrol.utils;
+
+import org.jclouds.dimensiondata.cloudcontrol.domain.Property;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Response;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Test(groups = "unit", testName = "ResponseParseTest", singleThreaded = true)
+public class ResponseParseTest {
+
+   public void testTryFindPropertyValue() {
+
+      List<Property> infoProperties = new ArrayList<Property>();
+      infoProperties.add(Property.create("propertyName1", "propertyValue1"));
+      infoProperties.add(Property.create("propertyName2", "propertyValue2"));
+
+      Response response = Response.builder().responseCode("responseCode").error(null).message("message")
+            .operation("operation").requestId("requestId").info(infoProperties).build();
+
+      Assert.assertEquals(new ParseResponse(null, "propertyName1").tryFindInfoPropertyValue(response),
+            "propertyValue1");
+      Assert.assertEquals(new ParseResponse(null, "propertyName2").tryFindInfoPropertyValue(response),
+            "propertyValue2");
+   }
+
+   @Test(expectedExceptions = { IllegalStateException.class })
+   public void testTryFindPropertyValue_PropertyNotFound() {
+
+      List<Property> infoProperties = new ArrayList<Property>();
+      infoProperties.add(Property.create("propertyName1", "propertyValue1"));
+
+      Response response = Response.builder().responseCode("responseCode").error(null).message("message")
+            .operation("operation").requestId("requestId").info(infoProperties).build();
+
+      new ParseResponse(null, "noProperty").tryFindInfoPropertyValue(response);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/firewallRules-page1.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/firewallRules-page1.json b/dimensiondata/src/test/resources/firewallRules-page1.json
new file mode 100644
index 0000000..9b328f4
--- /dev/null
+++ b/dimensiondata/src/test/resources/firewallRules-page1.json
@@ -0,0 +1,283 @@
+{
+  "firewallRule": [
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-xe21wswq",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-xe1sw1x",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-ne21e1c",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-xe21xe2",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-ce12ce2",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-xe21xe21v",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-xe21x1e2",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-xr32rx2",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-b23br32",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-dhtrhr",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-d1d121221",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    }
+  ],
+  "pageNumber": 1,
+  "pageCount": 11,
+  "totalCount": 15,
+  "pageSize": 11
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/firewallRules-page2.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/firewallRules-page2.json b/dimensiondata/src/test/resources/firewallRules-page2.json
new file mode 100644
index 0000000..557a358
--- /dev/null
+++ b/dimensiondata/src/test/resources/firewallRules-page2.json
@@ -0,0 +1,108 @@
+{
+  "firewallRule": [
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-br32rb23",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-3h33",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-htrhtr",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-g312yg53",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    }
+  ],
+  "pageNumber": 2,
+  "pageCount": 4,
+  "totalCount": 15,
+  "pageSize": 11
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/firewallRules.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/firewallRules.json b/dimensiondata/src/test/resources/firewallRules.json
new file mode 100644
index 0000000..2c2ea0b
--- /dev/null
+++ b/dimensiondata/src/test/resources/firewallRules.json
@@ -0,0 +1,33 @@
+{
+  "firewallRule": [
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "name": "CCDEFAULT.BlockOutboundMailIPv6Secure",
+      "action": "DROP",
+      "ipVersion": "IPV6",
+      "protocol": "TCP",
+      "source": {
+        "ip": {
+          "address": "ANY"
+        }
+      },
+      "destination": {
+        "ip": {
+          "address": "ANY"
+        },
+        "port": {
+          "begin": 587
+        }
+      },
+      "enabled": true,
+      "state": "NORMAL",
+      "id": "1aa3d0ce-d95d-4296-8338-9717e0d37ff9",
+      "datacenterId": "NA9",
+      "ruleType": "DEFAULT_RULE"
+    }
+  ],
+  "pageNumber": 1,
+  "pageCount": 4,
+  "totalCount": 4,
+  "pageSize": 50
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/natRule.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/natRule.json b/dimensiondata/src/test/resources/natRule.json
new file mode 100644
index 0000000..eb77796
--- /dev/null
+++ b/dimensiondata/src/test/resources/natRule.json
@@ -0,0 +1,9 @@
+{
+  "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+  "internalIp": "10.0.0.16",
+  "externalIp": "165.180.12.19",
+  "createTime": "2015-03-06T13:45:10.000Z",
+  "state": "NORMAL",
+  "id": "2169a38e-5692-497e-a22a-701a838a6539",
+  "datacenterId": "NA9"
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/natRules-page1.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/natRules-page1.json b/dimensiondata/src/test/resources/natRules-page1.json
new file mode 100644
index 0000000..37c085d
--- /dev/null
+++ b/dimensiondata/src/test/resources/natRules-page1.json
@@ -0,0 +1,98 @@
+{
+  "natRule": [
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.15",
+      "externalIp": "165.180.12.18",
+      "createTime": "2015-03-06T13:43:45.000Z",
+      "state": "NORMAL",
+      "id": "2187a636-7ebb-49a1-a2ff-5d617f496dce",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    }
+  ],
+  "pageNumber": 1,
+  "pageCount": 10,
+  "totalCount": 20,
+  "pageSize": 10
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/natRules-page2.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/natRules-page2.json b/dimensiondata/src/test/resources/natRules-page2.json
new file mode 100644
index 0000000..4d8c124
--- /dev/null
+++ b/dimensiondata/src/test/resources/natRules-page2.json
@@ -0,0 +1,98 @@
+{
+  "natRule": [
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.15",
+      "externalIp": "165.180.12.18",
+      "createTime": "2015-03-06T13:43:45.000Z",
+      "state": "NORMAL",
+      "id": "2187a636-7ebb-49a1-a2ff-5d617f496dce",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    }
+  ],
+  "pageNumber": 2,
+  "pageCount": 10,
+  "totalCount": 20,
+  "pageSize": 10
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/natRules.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/natRules.json b/dimensiondata/src/test/resources/natRules.json
new file mode 100644
index 0000000..7501f36
--- /dev/null
+++ b/dimensiondata/src/test/resources/natRules.json
@@ -0,0 +1,26 @@
+{
+  "natRule": [
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.15",
+      "externalIp": "165.180.12.18",
+      "createTime": "2015-03-06T13:43:45.000Z",
+      "state": "NORMAL",
+      "id": "2187a636-7ebb-49a1-a2ff-5d617f496dce",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "484174a2-ae74-4658-9e56-50fc90e086cf",
+      "internalIp": "10.0.0.16",
+      "externalIp": "165.180.12.19",
+      "createTime": "2015-03-06T13:45:10.000Z",
+      "state": "NORMAL",
+      "id": "2169a38e-5692-497e-a22a-701a838a6539",
+      "datacenterId": "NA9"
+    }
+  ],
+  "pageNumber": 1,
+  "pageCount": 2,
+  "totalCount": 2,
+  "pageSize": 250
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/networkDomain.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/networkDomain.json b/dimensiondata/src/test/resources/networkDomain.json
new file mode 100644
index 0000000..221076e
--- /dev/null
+++ b/dimensiondata/src/test/resources/networkDomain.json
@@ -0,0 +1,10 @@
+{
+  "name": "test",
+  "description": "",
+  "type": "ESSENTIALS",
+  "snatIpv4Address": "168.128.3.44",
+  "createTime": "2016-03-08T14:39:47.000Z",
+  "state": "NORMAL",
+  "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+  "datacenterId": "NA9"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/networkDomains-page1.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/networkDomains-page1.json b/dimensiondata/src/test/resources/networkDomains-page1.json
new file mode 100644
index 0000000..b931857
--- /dev/null
+++ b/dimensiondata/src/test/resources/networkDomains-page1.json
@@ -0,0 +1,108 @@
+{
+  "networkDomain": [
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    }
+  ],
+  "pageNumber": 1,
+  "pageCount": 10,
+  "totalCount": 20,
+  "pageSize": 10
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/networkDomains-page2.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/networkDomains-page2.json b/dimensiondata/src/test/resources/networkDomains-page2.json
new file mode 100644
index 0000000..e939571
--- /dev/null
+++ b/dimensiondata/src/test/resources/networkDomains-page2.json
@@ -0,0 +1,108 @@
+{
+  "networkDomain": [
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    },
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    }
+  ],
+  "pageNumber": 2,
+  "pageCount": 10,
+  "totalCount": 20,
+  "pageSize": 10
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/networkDomains.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/networkDomains.json b/dimensiondata/src/test/resources/networkDomains.json
new file mode 100644
index 0000000..34ef39b
--- /dev/null
+++ b/dimensiondata/src/test/resources/networkDomains.json
@@ -0,0 +1,18 @@
+{
+  "networkDomain": [
+    {
+      "name": "test",
+      "description": "",
+      "type": "ESSENTIALS",
+      "snatIpv4Address": "168.128.3.44",
+      "createTime": "2016-03-08T14:39:47.000Z",
+      "state": "NORMAL",
+      "id": "8e082ed6-c198-4eff-97cb-aeac6f9685d8",
+      "datacenterId": "NA9"
+    }
+  ],
+  "pageNumber": 1,
+  "pageCount": 1,
+  "totalCount": 1,
+  "pageSize": 250
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/portList.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/portList.json b/dimensiondata/src/test/resources/portList.json
new file mode 100644
index 0000000..29eb027
--- /dev/null
+++ b/dimensiondata/src/test/resources/portList.json
@@ -0,0 +1,16 @@
+{
+  "id": "c8c92ea3-2da8-4d51-8153-f39bec794d69",
+  "name": "name",
+  "description": "description",
+  "port": [
+    {
+      "begin": 100,
+      "end": 2000
+    },
+    {
+      "begin": 443
+    }
+  ],
+  "state": "NORMAL",
+  "createTime": "2008-09-29T02:49:45"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/portLists.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/portLists.json b/dimensiondata/src/test/resources/portLists.json
new file mode 100644
index 0000000..50d5edd
--- /dev/null
+++ b/dimensiondata/src/test/resources/portLists.json
@@ -0,0 +1,32 @@
+{
+  "portList": {
+    "id": "c8c92ea3-2da8-4d51-8153-f39bec794d69",
+    "name": "name",
+    "description": "description",
+    "port": [
+      {
+        "begin": 100,
+        "end": 2000
+      },
+      {
+        "begin": 443
+      }
+    ],
+    "childPortList": [
+      {
+        "id": "c8c92ea3-2da8-4d51-8153-f39bec794d68",
+        "name": "tomcatPorts"
+      },
+      {
+        "id": "c8c92ea3-2da8-4d51-8153-f39bec794d67",
+        "name": "mySqlPorts"
+      }
+    ],
+    "state": "NORMAL",
+    "createTime": "2008-09-29T02:49:45"
+  },
+  "pageNumber": 1,
+  "pageCount": 1,
+  "totalCount": 1,
+  "pageSize": 250
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/publicIpBlock.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/publicIpBlock.json b/dimensiondata/src/test/resources/publicIpBlock.json
new file mode 100644
index 0000000..789637a
--- /dev/null
+++ b/dimensiondata/src/test/resources/publicIpBlock.json
@@ -0,0 +1,9 @@
+{
+  "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+  "baseIp": "168.128.6.216",
+  "size": 2,
+  "createTime": "2016-03-14T11:49:33.000Z",
+  "state": "NORMAL",
+  "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+  "datacenterId": "NA9"
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/publicIpBlocks-page1.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/publicIpBlocks-page1.json b/dimensiondata/src/test/resources/publicIpBlocks-page1.json
new file mode 100644
index 0000000..1a9eab6
--- /dev/null
+++ b/dimensiondata/src/test/resources/publicIpBlocks-page1.json
@@ -0,0 +1,98 @@
+{
+  "publicIpBlock": [
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    }
+  ],
+  "pageNumber": 1,
+  "pageCount": 10,
+  "totalCount": 20,
+  "pageSize": 10
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/publicIpBlocks-page2.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/publicIpBlocks-page2.json b/dimensiondata/src/test/resources/publicIpBlocks-page2.json
new file mode 100644
index 0000000..4922311
--- /dev/null
+++ b/dimensiondata/src/test/resources/publicIpBlocks-page2.json
@@ -0,0 +1,98 @@
+{
+  "publicIpBlock": [
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    }
+  ],
+  "pageNumber": 2,
+  "pageCount": 10,
+  "totalCount": 2,
+  "pageSize": 10
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/publicIpBlocks.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/publicIpBlocks.json b/dimensiondata/src/test/resources/publicIpBlocks.json
new file mode 100644
index 0000000..d2c8ab6
--- /dev/null
+++ b/dimensiondata/src/test/resources/publicIpBlocks.json
@@ -0,0 +1,17 @@
+{
+  "publicIpBlock": [
+    {
+      "networkDomainId": "690de302-bb80-49c6-b401-8c02bbefb945",
+      "baseIp": "168.128.6.216",
+      "size": 2,
+      "createTime": "2016-03-14T11:49:33.000Z",
+      "state": "NORMAL",
+      "id": "9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8",
+      "datacenterId": "NA9"
+    }
+  ],
+  "pageNumber": 1,
+  "pageCount": 1,
+  "totalCount": 1,
+  "pageSize": 250
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/response.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/response.json b/dimensiondata/src/test/resources/response.json
new file mode 100644
index 0000000..237bd4d
--- /dev/null
+++ b/dimensiondata/src/test/resources/response.json
@@ -0,0 +1,30 @@
+{
+  "operation": "ADD_DISK",
+  "responseCode": "IN_PROGRESS",
+  "message": "Request to add a 3 GB Standard Speed Disk on Server 'Green-SCSI-SATA-IDE-Server2' has been accepted and is being processed.",
+  "info": [
+    {
+      "name": "diskId",
+      "value": "270a0d5d-f9c9-4aa5-94f5-123333cffb3c"
+    },
+    {
+      "name": "scsiId",
+      "value": "11"
+    },
+    {
+      "name": "scsiControllerId",
+      "value": "e461c085-fa98-4f19-818a-65d557182f46"
+    },
+    {
+      "name": "busNumber",
+      "value": "0"
+    },
+    {
+      "name": "speed",
+      "value": "STANDARD"
+    }
+  ],
+  "warning": [],
+  "error": [],
+  "requestId": "devlab1_20170512T065031117-0400_49fd964f-0c2c-44bc-95e3-edd112d98cc9"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/vlan.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/vlan.json b/dimensiondata/src/test/resources/vlan.json
new file mode 100644
index 0000000..ef5cb29
--- /dev/null
+++ b/dimensiondata/src/test/resources/vlan.json
@@ -0,0 +1,22 @@
+{
+  "networkDomain": {
+    "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+    "name": "test"
+  },
+  "name": "vlan1",
+  "description": "",
+  "privateIpv4Range": {
+    "address": "10.0.0.0",
+    "prefixSize": 24
+  },
+  "ipv4GatewayAddress": "10.0.0.1",
+  "ipv6Range": {
+    "address": "2607:f480:111:1575:0:0:0:0",
+    "prefixSize": 64
+  },
+  "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+  "createTime": "2016-03-11T10:41:19.000Z",
+  "state": "NORMAL",
+  "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+  "datacenterId": "NA9"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/vlans-page1.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/vlans-page1.json b/dimensiondata/src/test/resources/vlans-page1.json
new file mode 100644
index 0000000..cb8e36a
--- /dev/null
+++ b/dimensiondata/src/test/resources/vlans-page1.json
@@ -0,0 +1,228 @@
+{
+  "vlan": [
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    }
+  ],
+  "pageNumber": 1,
+  "pageCount": 10,
+  "totalCount": 20,
+  "pageSize": 10
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/vlans-page2.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/vlans-page2.json b/dimensiondata/src/test/resources/vlans-page2.json
new file mode 100644
index 0000000..64775cc
--- /dev/null
+++ b/dimensiondata/src/test/resources/vlans-page2.json
@@ -0,0 +1,228 @@
+{
+  "vlan": [
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    },
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    }
+  ],
+  "pageNumber": 2,
+  "pageCount": 10,
+  "totalCount": 20,
+  "pageSize": 10
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/resources/vlans.json
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/resources/vlans.json b/dimensiondata/src/test/resources/vlans.json
new file mode 100644
index 0000000..5573563
--- /dev/null
+++ b/dimensiondata/src/test/resources/vlans.json
@@ -0,0 +1,30 @@
+{
+  "vlan": [
+    {
+      "networkDomain": {
+        "id": "690de302-bb80-49c6-b401-8c02bbefb945",
+        "name": "test"
+      },
+      "name": "vlan1",
+      "description": "",
+      "privateIpv4Range": {
+        "address": "10.0.0.0",
+        "prefixSize": 24
+      },
+      "ipv4GatewayAddress": "10.0.0.1",
+      "ipv6Range": {
+        "address": "2607:f480:111:1575:0:0:0:0",
+        "prefixSize": 64
+      },
+      "ipv6GatewayAddress": "2607:f480:111:1575:0:0:0:1",
+      "createTime": "2016-03-11T10:41:19.000Z",
+      "state": "NORMAL",
+      "id": "6b25b02e-d3a2-4e69-8ca7-9bab605deebd",
+      "datacenterId": "NA9"
+    }
+  ],
+  "pageNumber": 1,
+  "pageCount": 1,
+  "totalCount": 1,
+  "pageSize": 250
+}
\ No newline at end of file


[2/2] jclouds-labs git commit: JCLOUDS-1255 Dimension Data Network API implementation.

Posted by na...@apache.org.
JCLOUDS-1255 Dimension Data Network API implementation.


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

Branch: refs/heads/master
Commit: 2495dd9a6453450c7341b66043b8ed82bc377600
Parents: 4febcfa
Author: Trevor Flanagan <tr...@itaas.dimensiondata.com>
Authored: Wed Jun 28 13:44:47 2017 +0100
Committer: Ignasi Barrera <na...@apache.org>
Committed: Thu Jul 6 16:14:10 2017 +0200

----------------------------------------------------------------------
 .../DimensionDataCloudControlApi.java           |   4 +
 .../cloudcontrol/domain/NetworkDomain.java      |   6 +-
 .../cloudcontrol/domain/Server.java             |  24 -
 .../cloudcontrol/domain/State.java              |  43 ++
 .../dimensiondata/cloudcontrol/domain/Vlan.java |   6 +-
 .../cloudcontrol/features/NetworkApi.java       | 487 +++++++++++++++++++
 .../predicates/NetworkDomainStatus.java         |  50 ++
 .../cloudcontrol/predicates/VlanStatus.java     |  52 ++
 .../DimensionDataCloudControlResponseUtils.java |  52 ++
 .../cloudcontrol/utils/ParseResponse.java       |  86 ++++
 .../features/NetworkApiLiveTest.java            | 126 +++++
 .../features/NetworkApiMockTest.java            | 392 +++++++++++++++
 .../BaseDimensionDataCloudControlMockTest.java  |   9 +
 .../parse/FirewallRulesParseTest.java           |  52 ++
 .../cloudcontrol/parse/NatRulesParseTest.java   |  49 ++
 .../parse/NetworkDomainsParseTest.java          |  49 ++
 .../parse/PublicIpBlocksParseTest.java          |  46 ++
 .../cloudcontrol/parse/VlansParseTest.java      |  52 ++
 .../cloudcontrol/utils/ResponseParseTest.java   |  56 +++
 .../src/test/resources/firewallRules-page1.json | 283 +++++++++++
 .../src/test/resources/firewallRules-page2.json | 108 ++++
 .../src/test/resources/firewallRules.json       |  33 ++
 dimensiondata/src/test/resources/natRule.json   |   9 +
 .../src/test/resources/natRules-page1.json      |  98 ++++
 .../src/test/resources/natRules-page2.json      |  98 ++++
 dimensiondata/src/test/resources/natRules.json  |  26 +
 .../src/test/resources/networkDomain.json       |  10 +
 .../test/resources/networkDomains-page1.json    | 108 ++++
 .../test/resources/networkDomains-page2.json    | 108 ++++
 .../src/test/resources/networkDomains.json      |  18 +
 dimensiondata/src/test/resources/portList.json  |  16 +
 dimensiondata/src/test/resources/portLists.json |  32 ++
 .../src/test/resources/publicIpBlock.json       |   9 +
 .../test/resources/publicIpBlocks-page1.json    |  98 ++++
 .../test/resources/publicIpBlocks-page2.json    |  98 ++++
 .../src/test/resources/publicIpBlocks.json      |  17 +
 dimensiondata/src/test/resources/response.json  |  30 ++
 dimensiondata/src/test/resources/vlan.json      |  22 +
 .../src/test/resources/vlans-page1.json         | 228 +++++++++
 .../src/test/resources/vlans-page2.json         | 228 +++++++++
 dimensiondata/src/test/resources/vlans.json     |  30 ++
 41 files changed, 3318 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApi.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApi.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApi.java
index 7e21571..5967453 100644
--- a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApi.java
+++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApi.java
@@ -18,6 +18,7 @@ package org.jclouds.dimensiondata.cloudcontrol;
 
 import org.jclouds.dimensiondata.cloudcontrol.features.AccountApi;
 import org.jclouds.dimensiondata.cloudcontrol.features.InfrastructureApi;
+import org.jclouds.dimensiondata.cloudcontrol.features.NetworkApi;
 import org.jclouds.dimensiondata.cloudcontrol.features.ServerImageApi;
 import org.jclouds.rest.annotations.Delegate;
 
@@ -33,4 +34,7 @@ public interface DimensionDataCloudControlApi extends Closeable {
 
    @Delegate
    ServerImageApi getServerImageApi();
+
+   @Delegate
+   NetworkApi getNetworkApi();
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/NetworkDomain.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/NetworkDomain.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/NetworkDomain.java
index eb6c291..acdaf75 100644
--- a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/NetworkDomain.java
+++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/NetworkDomain.java
@@ -47,7 +47,7 @@ public abstract class NetworkDomain {
    public abstract String description();
 
    @Nullable
-   public abstract String state();
+   public abstract State state();
 
    @Nullable
    public abstract Type type();
@@ -59,7 +59,7 @@ public abstract class NetworkDomain {
    public abstract Date createTime();
 
    @SerializedNames({ "id", "datacenterId", "name", "description", "state", "type", "snatIpv4Address", "createTime" })
-   public static NetworkDomain create(String id, String datacenterId, String name, String description, String state,
+   public static NetworkDomain create(String id, String datacenterId, String name, String description, State state,
          Type type, String snatIpv4Address, Date createTime) {
       return builder().id(id).datacenterId(datacenterId).name(name).description(description).state(state).type(type)
             .snatIpv4Address(snatIpv4Address).createTime(createTime).build();
@@ -77,7 +77,7 @@ public abstract class NetworkDomain {
 
       public abstract Builder description(String description);
 
-      public abstract Builder state(String state);
+      public abstract Builder state(State state);
 
       public abstract Builder type(Type type);
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Server.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Server.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Server.java
index 9be5f33..79de501 100644
--- a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Server.java
+++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Server.java
@@ -17,7 +17,6 @@
 package org.jclouds.dimensiondata.cloudcontrol.domain;
 
 import com.google.auto.value.AutoValue;
-import com.google.common.base.CaseFormat;
 import com.google.common.collect.ImmutableList;
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.json.SerializedNames;
@@ -25,32 +24,9 @@ import org.jclouds.json.SerializedNames;
 import java.util.Date;
 import java.util.List;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 @AutoValue
 public abstract class Server {
 
-   public enum State {
-      NORMAL, FAILED_ADD, FAILED_CHANGE, FAILED_DELETE, PENDING_DELETE, DELETED, UNRECOGNIZED;
-
-      @Override
-      public String toString() {
-         return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name());
-      }
-
-      public static State fromValue(String state) {
-         try {
-            return valueOf(CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(state, "state")));
-         } catch (IllegalArgumentException e) {
-            return UNRECOGNIZED;
-         }
-      }
-
-      public boolean isFailed() {
-         return this == FAILED_ADD || this == FAILED_CHANGE || this == FAILED_DELETE;
-      }
-   }
-
    Server() {
    }
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/State.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/State.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/State.java
new file mode 100644
index 0000000..e832264
--- /dev/null
+++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/State.java
@@ -0,0 +1,43 @@
+/*
+ * 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.dimensiondata.cloudcontrol.domain;
+
+import com.google.common.base.CaseFormat;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public enum State {
+
+   NORMAL, FAILED_ADD, FAILED_CHANGE, FAILED_DELETE, PENDING_DELETE, DELETED, UNRECOGNIZED;
+
+   @Override
+   public String toString() {
+      return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name());
+   }
+
+   public static State fromValue(String state) {
+      try {
+         return valueOf(CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(state, "state")));
+      } catch (IllegalArgumentException e) {
+         return UNRECOGNIZED;
+      }
+   }
+
+   public boolean isFailed() {
+      return this == FAILED_ADD || this == FAILED_CHANGE || this == FAILED_DELETE;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Vlan.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Vlan.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Vlan.java
index 7a62543..4e40beb 100644
--- a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Vlan.java
+++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Vlan.java
@@ -39,7 +39,7 @@ public abstract class Vlan {
 
    public abstract String datacenterId();
 
-   public abstract String state();
+   public abstract State state();
 
    public abstract Date createTime();
 
@@ -55,7 +55,7 @@ public abstract class Vlan {
 
    @SerializedNames({ "id", "name", "description", "datacenterId", "state", "createTime", "ipv4GatewayAddress",
          "ipv6GatewayAddress", "networkDomain", "privateIpv4Range", "ipv6Range" })
-   public static Vlan create(String id, String name, String description, String datacenterId, String state,
+   public static Vlan create(String id, String name, String description, String datacenterId, State state,
          Date createTime, String ipv4GatewayAddress, String ipv6GatewayAddress, NetworkDomain networkDomain,
          IpRange privateIpv4Range, IpRange ipv6Range) {
       return builder().id(id).name(name).description(description).datacenterId(datacenterId).state(state)
@@ -75,7 +75,7 @@ public abstract class Vlan {
 
       public abstract Builder datacenterId(String datacenterId);
 
-      public abstract Builder state(String state);
+      public abstract Builder state(State state);
 
       public abstract Builder createTime(Date createTime);
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApi.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApi.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApi.java
new file mode 100644
index 0000000..129fa99
--- /dev/null
+++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApi.java
@@ -0,0 +1,487 @@
+/*
+ * 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.dimensiondata.cloudcontrol.features;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.inject.TypeLiteral;
+import org.jclouds.Fallbacks;
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.PagedIterable;
+import org.jclouds.collect.internal.Arg0ToPagedIterable;
+import org.jclouds.dimensiondata.cloudcontrol.DimensionDataCloudControlApi;
+import org.jclouds.dimensiondata.cloudcontrol.domain.FirewallRule;
+import org.jclouds.dimensiondata.cloudcontrol.domain.FirewallRuleTarget;
+import org.jclouds.dimensiondata.cloudcontrol.domain.FirewallRuleTarget.Port;
+import org.jclouds.dimensiondata.cloudcontrol.domain.FirewallRules;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NatRule;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NatRules;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkDomain;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkDomains;
+import org.jclouds.dimensiondata.cloudcontrol.domain.PaginatedCollection;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Placement;
+import org.jclouds.dimensiondata.cloudcontrol.domain.PublicIpBlock;
+import org.jclouds.dimensiondata.cloudcontrol.domain.PublicIpBlocks;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Response;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Vlan;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Vlans;
+import org.jclouds.dimensiondata.cloudcontrol.filters.OrganisationIdFilter;
+import org.jclouds.dimensiondata.cloudcontrol.options.PaginationOptions;
+import org.jclouds.dimensiondata.cloudcontrol.utils.ParseResponse;
+import org.jclouds.http.filters.BasicAuthentication;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.Transform;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+
+@RequestFilters({ BasicAuthentication.class, OrganisationIdFilter.class })
+@Consumes(MediaType.APPLICATION_JSON)
+@Path("/{jclouds.api-version}/network")
+public interface NetworkApi {
+
+   @Named("network:deployNetworkDomain")
+   @POST
+   @Path("/deployNetworkDomain")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   @ResponseParser(ParseNetworkDomainId.class)
+   String deployNetworkDomain(@PayloadParam("datacenterId") String datacenterId, @PayloadParam("name") String name,
+         @PayloadParam("description") String description, @PayloadParam("type") String type);
+
+   @Named("networkDomain:get")
+   @GET
+   @Path("/networkDomain/{id}")
+   @Fallback(NullOnNotFoundOr404.class)
+   NetworkDomain getNetworkDomain(@PathParam("id") String networkDomainId);
+
+   @Named("networkDomain:listWithDatacenterIdAndName")
+   @GET
+   @Path("/networkDomain")
+   @Transform(ParseNetworkDomains.ToPagedIterable.class)
+   @ResponseParser(ParseNetworkDomains.class)
+   @Fallback(Fallbacks.EmptyPagedIterableOnNotFoundOr404.class)
+   PagedIterable<NetworkDomain> listNetworkDomainsWithDatacenterIdAndName(
+         @QueryParam("datacenterId") String datacenterId, @QueryParam("name") String name);
+
+   @Named("networkDomain:list")
+   @GET
+   @Path("/networkDomain")
+   @ResponseParser(ParseNetworkDomains.class)
+   @Fallback(Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404.class)
+   PaginatedCollection<NetworkDomain> listNetworkDomains(PaginationOptions options);
+
+   @Named("networkDomain:list")
+   @GET
+   @Path("/networkDomain")
+   @Transform(ParseNetworkDomains.ToPagedIterable.class)
+   @ResponseParser(ParseNetworkDomains.class)
+   @Fallback(Fallbacks.EmptyPagedIterableOnNotFoundOr404.class)
+   PagedIterable<NetworkDomain> listNetworkDomains();
+
+   @Named("networkDomain:delete")
+   @POST
+   @Path("/deleteNetworkDomain")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
+   void deleteNetworkDomain(@PayloadParam("id") String networkDomainId);
+
+   @Named("vlan:deploy")
+   @POST
+   @Path("/deployVlan")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   @ResponseParser(ParseVlanId.class)
+   String deployVlan(@PayloadParam("networkDomainId") String networkDomainId, @PayloadParam("name") String name,
+         @PayloadParam("description") String description,
+         @PayloadParam("privateIpv4BaseAddress") String privateIpv4BaseAddress,
+         @PayloadParam("privateIpv4PrefixSize") Integer privateIpv4PrefixSize);
+
+   @Named("vlan:get")
+   @GET
+   @Path("/vlan/{id}")
+   @Fallback(NullOnNotFoundOr404.class)
+   Vlan getVlan(@PathParam("id") String vlanId);
+
+   @Named("vlan:list")
+   @GET
+   @Path("/vlan")
+   @ResponseParser(ParseVlans.class)
+   @Fallback(Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404.class)
+   PaginatedCollection<Vlan> listVlans(@QueryParam("networkDomainId") String networkDomainId,
+         PaginationOptions options);
+
+   @Named("vlan:list")
+   @GET
+   @Path("/vlan")
+   @Transform(ParseVlans.ToPagedIterable.class)
+   @ResponseParser(ParseVlans.class)
+   @Fallback(Fallbacks.EmptyPagedIterableOnNotFoundOr404.class)
+   PagedIterable<Vlan> listVlans(@QueryParam("networkDomainId") String networkDomainId);
+
+   @Named("vlan:delete")
+   @POST
+   @Path("/deleteVlan")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
+   void deleteVlan(@PayloadParam("id") String vlanId);
+
+   @Named("networkDomain:addPublicIpBlock")
+   @POST
+   @Path("/addPublicIpBlock")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   Response addPublicIpBlock(@PayloadParam("networkDomainId") String networkDomainId);
+
+   @Named("networkDomain:listPublicIPv4AddressBlocks")
+   @GET
+   @Path("/publicIpBlock")
+   @ResponseParser(ParsePublicIpBlocks.class)
+   @Fallback(Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404.class)
+   PaginatedCollection<PublicIpBlock> listPublicIPv4AddressBlocks(@QueryParam("networkDomainId") String networkDomainId,
+         PaginationOptions options);
+
+   @Named("networkDomain:listPublicIPv4AddressBlock")
+   @GET
+   @Path("/publicIpBlock")
+   @Transform(ParsePublicIpBlocks.ToPagedIterable.class)
+   @ResponseParser(ParsePublicIpBlocks.class)
+   @Fallback(Fallbacks.EmptyPagedIterableOnNotFoundOr404.class)
+   PagedIterable<PublicIpBlock> listPublicIPv4AddressBlocks(@QueryParam("networkDomainId") String networkDomainId);
+
+   @Named("networkDomain:removePublicIpBlock")
+   @POST
+   @Path("/removePublicIpBlock")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
+   void removePublicIpBlock(@PayloadParam("id") String publicIpBlockId);
+
+   @Named("networkDomain:getPublicIPv4AddressBlock")
+   @GET
+   @Path("/publicIpBlock/{id}")
+   @Fallback(NullOnNotFoundOr404.class)
+   PublicIpBlock getPublicIPv4AddressBlock(@PathParam("id") String publicIPv4AddressBlockId);
+
+   @Named("network:createNatRule")
+   @POST
+   @Path("/createNatRule")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
+   Response createNatRule(@PayloadParam("networkDomainId") String networkDomainId,
+         @PayloadParam("internalIp") String internalIp, @PayloadParam("externalIp") String externalIp);
+
+   @Named("networkDomain:listNatRules")
+   @GET
+   @Path("/natRule")
+   @ResponseParser(ParseNatRules.class)
+   @Fallback(Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404.class)
+   PaginatedCollection<NatRule> listNatRules(@QueryParam("networkDomainId") String networkDomainId,
+         PaginationOptions options);
+
+   @Named("networkDomain:listNatRules")
+   @GET
+   @Path("/natRule")
+   @Transform(ParseNatRules.ToPagedIterable.class)
+   @ResponseParser(ParseNatRules.class)
+   @Fallback(Fallbacks.EmptyPagedIterableOnNotFoundOr404.class)
+   PagedIterable<NatRule> listNatRules(@QueryParam("networkDomainId") String networkDomainId);
+
+   @Named("network:getNatRule")
+   @GET
+   @Path("/natRule/{id}")
+   @Fallback(NullOnNotFoundOr404.class)
+   NatRule getNatRule(@PathParam("id") String natRuleId);
+
+   @Named("network:deleteNatRule")
+   @POST
+   @Path("/deleteNatRule")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
+   void deleteNatRule(@PayloadParam("id") String natRuleId);
+
+   @Named("networkDomain:createFirewallRule")
+   @POST
+   @Path("/createFirewallRule")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   @ResponseParser(FirewallRuleId.class)
+   String createFirewallRule(@PayloadParam("networkDomainId") String networkDomainId, @PayloadParam("name") String name,
+         @PayloadParam("action") String action, @PayloadParam("ipVersion") String ipVersion,
+         @PayloadParam("protocol") String protocol, @PayloadParam("source") FirewallRuleTarget source,
+         @PayloadParam("destination") FirewallRuleTarget destination, @PayloadParam("enabled") Boolean enabled,
+         @PayloadParam("placement") Placement placement);
+
+   @Named("networkDomain:listFirewallRules")
+   @GET
+   @Path("/firewallRule")
+   @ResponseParser(ParseFirewallRules.class)
+   @Fallback(Fallbacks.EmptyIterableWithMarkerOnNotFoundOr404.class)
+   PaginatedCollection<FirewallRule> listFirewallRules(@QueryParam("networkDomainId") String networkDomainId,
+         PaginationOptions options);
+
+   @Named("networkDomain:listFirewallRules")
+   @GET
+   @Path("/firewallRule")
+   @Transform(ParseFirewallRules.ToPagedIterable.class)
+   @ResponseParser(ParseFirewallRules.class)
+   @Fallback(Fallbacks.EmptyPagedIterableOnNotFoundOr404.class)
+   PagedIterable<FirewallRule> listFirewallRules(@QueryParam("networkDomainId") String networkDomainId);
+
+   @Named("networkDomain:deleteFirewallRule")
+   @POST
+   @Path("/deleteFirewallRule")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
+   void deleteFirewallRule(@PayloadParam("id") String firewallRuleId);
+
+   @Named("networkDomain:createPortList")
+   @POST
+   @Path("/createPortList")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   @ResponseParser(PortListId.class)
+   String createPortList(@PayloadParam("networkDomainId") String networkDomainId, @PayloadParam("name") String name,
+         @PayloadParam("description") String description, @PayloadParam("port") List<Port> port,
+         @PayloadParam("childPortListId") List<String> childPortListId);
+
+   @Named("networkDomain:getPortList")
+   @GET
+   @Path("/portList/{id}")
+   @Fallback(NullOnNotFoundOr404.class)
+   FirewallRuleTarget.PortList getPortList(@PathParam("id") String portListId);
+
+   @Named("networkDomain:deletePortList")
+   @POST
+   @Path("/deletePortList")
+   @Produces(MediaType.APPLICATION_JSON)
+   @MapBinder(BindToJsonPayload.class)
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
+   void deletePortList(@PayloadParam("id") String portListId);
+
+   @Singleton
+   final class ParseFirewallRules extends ParseJson<FirewallRules> {
+
+      @Inject
+      ParseFirewallRules(Json json) {
+         super(json, TypeLiteral.get(FirewallRules.class));
+      }
+
+      private static class ToPagedIterable
+            extends Arg0ToPagedIterable<FirewallRule, ParseFirewallRules.ToPagedIterable> {
+
+         private DimensionDataCloudControlApi api;
+
+         @Inject
+         ToPagedIterable(DimensionDataCloudControlApi api) {
+            this.api = api;
+         }
+
+         @Override
+         protected Function<Object, IterableWithMarker<FirewallRule>> markerToNextForArg0(Optional<Object> optional) {
+            return new Function<Object, IterableWithMarker<FirewallRule>>() {
+               @Override
+               public IterableWithMarker<FirewallRule> apply(Object input) {
+                  PaginationOptions paginationOptions = PaginationOptions.class.cast(input);
+                  return api.getNetworkApi().listFirewallRules(getArgs(request).get(0).toString(), paginationOptions);
+               }
+            };
+         }
+      }
+   }
+
+   @Singleton
+   final class ParseNatRules extends ParseJson<NatRules> {
+
+      @Inject
+      ParseNatRules(Json json) {
+         super(json, TypeLiteral.get(NatRules.class));
+      }
+
+      private static class ToPagedIterable extends Arg0ToPagedIterable<NatRule, ToPagedIterable> {
+
+         private DimensionDataCloudControlApi api;
+
+         @Inject
+         ToPagedIterable(DimensionDataCloudControlApi api) {
+            this.api = api;
+         }
+
+         @Override
+         protected Function<Object, IterableWithMarker<NatRule>> markerToNextForArg0(Optional<Object> optional) {
+            return new Function<Object, IterableWithMarker<NatRule>>() {
+               @Override
+               public IterableWithMarker<NatRule> apply(Object input) {
+                  PaginationOptions paginationOptions = PaginationOptions.class.cast(input);
+                  return api.getNetworkApi().listNatRules(getArgs(request).get(0).toString(), paginationOptions);
+               }
+            };
+         }
+      }
+   }
+
+   @Singleton
+   final class ParseNetworkDomains extends ParseJson<NetworkDomains> {
+
+      @Inject
+      ParseNetworkDomains(Json json) {
+         super(json, TypeLiteral.get(NetworkDomains.class));
+      }
+
+      private static class ToPagedIterable extends Arg0ToPagedIterable<NetworkDomain, ToPagedIterable> {
+
+         private DimensionDataCloudControlApi api;
+
+         @Inject
+         ToPagedIterable(DimensionDataCloudControlApi api) {
+            this.api = api;
+         }
+
+         @Override
+         protected Function<Object, IterableWithMarker<NetworkDomain>> markerToNextForArg0(Optional<Object> optional) {
+            return new Function<Object, IterableWithMarker<NetworkDomain>>() {
+               @Override
+               public IterableWithMarker<NetworkDomain> apply(Object input) {
+                  PaginationOptions paginationOptions = PaginationOptions.class.cast(input);
+                  return api.getNetworkApi().listNetworkDomains(paginationOptions);
+               }
+            };
+         }
+      }
+   }
+
+   @Singleton
+   final class ParsePublicIpBlocks extends ParseJson<PublicIpBlocks> {
+
+      @Inject
+      ParsePublicIpBlocks(Json json) {
+         super(json, TypeLiteral.get(PublicIpBlocks.class));
+      }
+
+      private static class ToPagedIterable extends Arg0ToPagedIterable<PublicIpBlock, ToPagedIterable> {
+
+         private DimensionDataCloudControlApi api;
+
+         @Inject
+         ToPagedIterable(DimensionDataCloudControlApi api) {
+            this.api = api;
+         }
+
+         @Override
+         protected Function<Object, IterableWithMarker<PublicIpBlock>> markerToNextForArg0(Optional<Object> optional) {
+            return new Function<Object, IterableWithMarker<PublicIpBlock>>() {
+               @Override
+               public IterableWithMarker<PublicIpBlock> apply(Object input) {
+                  PaginationOptions paginationOptions = PaginationOptions.class.cast(input);
+                  return api.getNetworkApi()
+                        .listPublicIPv4AddressBlocks(getArgs(request).get(0).toString(), paginationOptions);
+               }
+            };
+         }
+      }
+   }
+
+   @Singleton
+   final class ParseVlans extends ParseJson<Vlans> {
+
+      @Inject
+      ParseVlans(Json json) {
+         super(json, TypeLiteral.get(Vlans.class));
+      }
+
+      static class ToPagedIterable extends Arg0ToPagedIterable<Vlan, ToPagedIterable> {
+
+         private DimensionDataCloudControlApi api;
+
+         @Inject
+         ToPagedIterable(DimensionDataCloudControlApi api) {
+            this.api = api;
+         }
+
+         @Override
+         protected Function<Object, IterableWithMarker<Vlan>> markerToNextForArg0(Optional<Object> optional) {
+            return new Function<Object, IterableWithMarker<Vlan>>() {
+               @Override
+               public IterableWithMarker<Vlan> apply(Object input) {
+                  PaginationOptions paginationOptions = PaginationOptions.class.cast(input);
+                  return api.getNetworkApi().listVlans(getArgs(request).get(0).toString(), paginationOptions);
+               }
+            };
+         }
+      }
+   }
+
+   @Singleton
+   final class ParseNetworkDomainId extends ParseResponse {
+
+      @Inject
+      ParseNetworkDomainId(Json json) {
+         super(json, "networkDomainId");
+      }
+   }
+
+   @Singleton
+   final class ParseVlanId extends ParseResponse {
+
+      @Inject
+      ParseVlanId(Json json) {
+         super(json, "vlanId");
+      }
+   }
+
+   @Singleton
+   final class PortListId extends ParseResponse {
+
+      @Inject
+      PortListId(Json json) {
+         super(json, "portListId");
+      }
+   }
+
+   @Singleton
+   final class FirewallRuleId extends ParseResponse {
+
+      @Inject
+      FirewallRuleId(Json json) {
+         super(json, "firewallRuleId");
+      }
+   }
+}
+

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/NetworkDomainStatus.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/NetworkDomainStatus.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/NetworkDomainStatus.java
new file mode 100644
index 0000000..94882d1
--- /dev/null
+++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/NetworkDomainStatus.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.dimensiondata.cloudcontrol.predicates;
+
+import com.google.common.base.Predicate;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkDomain;
+import org.jclouds.dimensiondata.cloudcontrol.domain.State;
+import org.jclouds.dimensiondata.cloudcontrol.features.NetworkApi;
+import org.jclouds.logging.Logger;
+
+import javax.annotation.Resource;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class NetworkDomainStatus implements Predicate<String> {
+
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   private final State state;
+   private final NetworkApi networkApi;
+
+   public NetworkDomainStatus(NetworkApi networkApi, State state) {
+      this.networkApi = networkApi;
+      this.state = state;
+   }
+
+   @Override
+   public boolean apply(String networkDomainId) {
+      checkNotNull(networkDomainId, "networkDomainId");
+      logger.trace("looking for state on network domain %s", networkDomainId);
+      final NetworkDomain networkDomain = networkApi.getNetworkDomain(networkDomainId);
+      final boolean isDeleted = networkDomain == null && state == State.DELETED;
+      return isDeleted || (networkDomain != null && networkDomain.state() == state);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VlanStatus.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VlanStatus.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VlanStatus.java
new file mode 100644
index 0000000..79aa75a
--- /dev/null
+++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/predicates/VlanStatus.java
@@ -0,0 +1,52 @@
+/*
+ * 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.dimensiondata.cloudcontrol.predicates;
+
+import com.google.common.base.Predicate;
+import org.jclouds.dimensiondata.cloudcontrol.domain.State;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Vlan;
+import org.jclouds.dimensiondata.cloudcontrol.features.NetworkApi;
+import org.jclouds.logging.Logger;
+
+import javax.annotation.Resource;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class VlanStatus implements Predicate<String> {
+
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   private final State state;
+   private final NetworkApi networkApi;
+
+   public VlanStatus(NetworkApi networkApi, State state) {
+      this.networkApi = networkApi;
+      this.state = state;
+   }
+
+   @Override
+   public boolean apply(String vlanId) {
+      checkNotNull(vlanId, "vlanId");
+      logger.trace("looking for state on vlan %s", vlanId);
+      final Vlan vlan = networkApi.getVlan(vlanId);
+      final boolean isDeleted = (vlan == null) && (state == State.DELETED);
+      return isDeleted || ((vlan != null) && vlan.state() == state);
+
+   }
+}
+

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/utils/DimensionDataCloudControlResponseUtils.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/utils/DimensionDataCloudControlResponseUtils.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/utils/DimensionDataCloudControlResponseUtils.java
new file mode 100644
index 0000000..2c80d7c
--- /dev/null
+++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/utils/DimensionDataCloudControlResponseUtils.java
@@ -0,0 +1,52 @@
+/*
+ * 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.dimensiondata.cloudcontrol.utils;
+
+import org.jclouds.dimensiondata.cloudcontrol.domain.State;
+import org.jclouds.dimensiondata.cloudcontrol.features.NetworkApi;
+import org.jclouds.dimensiondata.cloudcontrol.predicates.NetworkDomainStatus;
+import org.jclouds.dimensiondata.cloudcontrol.predicates.VlanStatus;
+
+import static org.jclouds.util.Predicates2.retry;
+
+public class DimensionDataCloudControlResponseUtils {
+
+   private static String convertServerId(String serverId) {
+      return serverId.replaceAll("-", "_");
+   }
+
+   public static String generateFirewallRuleName(String serverId) {
+      return String.format("fw.%s", convertServerId(serverId));
+   }
+
+   public static void waitForNetworkDomainStatus(NetworkApi api, String networkDomainId, State state,
+         long timeoutMillis, String message) {
+      boolean isNetworkDomainInState = retry(new NetworkDomainStatus(api, state), timeoutMillis).apply(networkDomainId);
+      if (!isNetworkDomainInState) {
+         throw new IllegalStateException(message);
+      }
+   }
+
+   public static void waitForVlanStatus(NetworkApi api, String vlanId, State state, long timeoutMillis,
+         String message) {
+      boolean isVlanInstate = retry(new VlanStatus(api, state), timeoutMillis).apply(vlanId);
+      if (!isVlanInstate) {
+         throw new IllegalStateException(message);
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/utils/ParseResponse.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/utils/ParseResponse.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/utils/ParseResponse.java
new file mode 100644
index 0000000..6f8b5de
--- /dev/null
+++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/utils/ParseResponse.java
@@ -0,0 +1,86 @@
+/*
+ * 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.dimensiondata.cloudcontrol.utils;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.inject.TypeLiteral;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Property;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Response;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.json.Json;
+import org.jclouds.logging.Logger;
+
+import javax.annotation.Resource;
+import java.io.InputStream;
+
+import static org.jclouds.http.HttpUtils.releasePayload;
+
+public class ParseResponse implements Function<HttpResponse, String> {
+
+   @Resource
+   protected Logger logger = Logger.NULL;
+   protected final Json json;
+   protected final String propertyName;
+
+   protected ParseResponse(Json json, String propertyName) {
+      this.json = json;
+      this.propertyName = propertyName;
+   }
+
+   public String apply(HttpResponse from) {
+      try {
+         InputStream gson = from.getPayload().openStream();
+
+         final Response response = json.fromJson(gson, TypeLiteral.get(Response.class).getType());
+         return tryFindInfoPropertyValue(response);
+      } catch (Exception e) {
+         StringBuilder message = new StringBuilder();
+         message.append("Error parsing input: ");
+         message.append(e.getMessage());
+         logger.error(e, message.toString());
+         throw new HttpResponseException(message.toString() + "\n" + from, null, from, e);
+      } finally {
+         releasePayload(from);
+      }
+   }
+
+   String tryFindInfoPropertyValue(Response response) {
+      if (!response.info().isEmpty()) {
+         Optional<String> optionalPropertyName = FluentIterable.from(response.info())
+               .firstMatch(new Predicate<Property>() {
+                  @Override
+                  public boolean apply(Property input) {
+                     return input.name().equals(propertyName);
+                  }
+               }).transform(new Function<Property, String>() {
+                  @Override
+                  public String apply(Property input) {
+                     return input.value();
+                  }
+               });
+         if (!optionalPropertyName.isPresent()) {
+            throw new IllegalStateException("Could not find expected property name: " + propertyName);
+         }
+         return optionalPropertyName.get();
+      }
+      return "";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApiLiveTest.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApiLiveTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApiLiveTest.java
new file mode 100644
index 0000000..424eecc
--- /dev/null
+++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApiLiveTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.dimensiondata.cloudcontrol.features;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import org.jclouds.dimensiondata.cloudcontrol.domain.FirewallRuleTarget;
+import org.jclouds.dimensiondata.cloudcontrol.domain.IpRange;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Placement;
+import org.jclouds.dimensiondata.cloudcontrol.domain.State;
+import org.jclouds.dimensiondata.cloudcontrol.internal.BaseDimensionDataCloudControlApiLiveTest;
+import org.jclouds.rest.ResourceAlreadyExistsException;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+import static org.jclouds.dimensiondata.cloudcontrol.features.NetworkApiMockTest.DEFAULT_ACTION;
+import static org.jclouds.dimensiondata.cloudcontrol.features.NetworkApiMockTest.DEFAULT_IP_VERSION;
+import static org.jclouds.dimensiondata.cloudcontrol.utils.DimensionDataCloudControlResponseUtils.generateFirewallRuleName;
+import static org.jclouds.dimensiondata.cloudcontrol.utils.DimensionDataCloudControlResponseUtils.waitForNetworkDomainStatus;
+import static org.jclouds.dimensiondata.cloudcontrol.utils.DimensionDataCloudControlResponseUtils.waitForVlanStatus;
+import static org.testng.Assert.assertNotNull;
+
+@Test(groups = "live", testName = "NetworkApiLiveTest", singleThreaded = true)
+public class NetworkApiLiveTest extends BaseDimensionDataCloudControlApiLiveTest {
+
+   private static final String DATACENTER = "NW20-EPC-LAB04";
+
+   private static final String DEFAULT_PRIVATE_IPV4_BASE_ADDRESS = "10.0.0.0";
+   private static final Integer DEFAULT_PRIVATE_IPV4_PREFIX_SIZE = 24;
+   private static final String DEFAULT_PROTOCOL = "TCP";
+
+   private String networkDomainId;
+   private String vlanId;
+   private String portListId;
+   private List<String> firewallRuleIds;
+
+   @BeforeClass
+   public void init() {
+      firewallRuleIds = Lists.newArrayList();
+   }
+
+   @Test(dependsOnMethods = "testDeployVlan")
+   public void testCreatePortList() {
+      portListId = api()
+            .createPortList(networkDomainId, this.getClass().getCanonicalName(), this.getClass().getCanonicalName(),
+                  ImmutableList.of(FirewallRuleTarget.Port.create(22, null)), Lists.<String>newArrayList());
+      assertNotNull(portListId);
+   }
+
+   @Test(dependsOnMethods = "testCreatePortList")
+   public void testCreateFirewallRuleWithPortList() {
+      String id = api().createFirewallRule(networkDomainId, generateFirewallRuleName("server-id"), DEFAULT_ACTION,
+            DEFAULT_IP_VERSION, DEFAULT_PROTOCOL, FirewallRuleTarget.builder().ip(IpRange.create("ANY", null)).build(),
+            FirewallRuleTarget.builder().ip(IpRange.create("ANY", null)).portListId(portListId).build(), Boolean.TRUE,
+            Placement.builder().position("LAST").build());
+      firewallRuleIds.add(id);
+   }
+
+   @Test(dependsOnMethods = "testDeployNetworkDomain")
+   public void testDeployVlan() {
+      vlanId = api().deployVlan(networkDomainId, NetworkApiLiveTest.class.getSimpleName(),
+            NetworkApiLiveTest.class.getSimpleName(), DEFAULT_PRIVATE_IPV4_BASE_ADDRESS,
+            DEFAULT_PRIVATE_IPV4_PREFIX_SIZE);
+      assertNotNull(vlanId);
+      waitForVlanStatus(api(), vlanId, State.NORMAL, 30 * 60 * 1000, "Error - unable to deploy vlan");
+   }
+
+   @Test
+   public void testDeployNetworkDomain() {
+      String networkDomainName = NetworkApiLiveTest.class.getSimpleName();
+      networkDomainId = api()
+            .deployNetworkDomain(DATACENTER, networkDomainName, NetworkApiLiveTest.class.getSimpleName(), "ESSENTIALS");
+      assertNotNull(networkDomainId);
+      waitForNetworkDomainStatus(api(), networkDomainId, State.NORMAL, 30 * 60 * 1000,
+            "Error - unable to deploy network domain");
+   }
+
+   @Test(expectedExceptions = ResourceAlreadyExistsException.class)
+   public void testDeploySameNetworkDomain() {
+      api().deployNetworkDomain(DATACENTER, NetworkApiLiveTest.class.getSimpleName(),
+            NetworkApiLiveTest.class.getSimpleName(), "ESSENTIALS");
+   }
+
+   @AfterClass
+   public void tearDown() {
+      if (!firewallRuleIds.isEmpty()) {
+         for (String firewallRuleId : firewallRuleIds) {
+            api().deleteFirewallRule(firewallRuleId);
+         }
+      }
+      if (portListId != null) {
+         api().deletePortList(portListId);
+      }
+      if (vlanId != null) {
+         api().deleteVlan(vlanId);
+         waitForVlanStatus(api(), vlanId, State.DELETED, 30 * 60 * 1000, "Error deleting vlan");
+      }
+      if (networkDomainId != null) {
+         api().deleteNetworkDomain(networkDomainId);
+         waitForNetworkDomainStatus(api(), networkDomainId, State.DELETED, 30 * 60 * 1000,
+               "Error deleting network domain");
+      }
+   }
+
+   private NetworkApi api() {
+      return api.getNetworkApi();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApiMockTest.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApiMockTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApiMockTest.java
new file mode 100644
index 0000000..6e4fc86
--- /dev/null
+++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/NetworkApiMockTest.java
@@ -0,0 +1,392 @@
+/*
+ * 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.dimensiondata.cloudcontrol.features;
+
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import org.jclouds.dimensiondata.cloudcontrol.domain.FirewallRule;
+import org.jclouds.dimensiondata.cloudcontrol.domain.FirewallRuleTarget;
+import org.jclouds.dimensiondata.cloudcontrol.domain.IpRange;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NatRule;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkDomain;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Placement;
+import org.jclouds.dimensiondata.cloudcontrol.domain.PublicIpBlock;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Vlan;
+import org.jclouds.dimensiondata.cloudcontrol.internal.BaseAccountAwareCloudControlMockTest;
+import org.jclouds.dimensiondata.cloudcontrol.parse.PublicIpBlocksParseTest;
+import org.jclouds.dimensiondata.cloudcontrol.parse.VlansParseTest;
+import org.jclouds.http.Uris;
+import org.testng.annotations.Test;
+
+import javax.ws.rs.HttpMethod;
+
+import static ch.qos.logback.core.net.ssl.SSL.DEFAULT_PROTOCOL;
+import static com.google.common.collect.Iterables.size;
+import static javax.ws.rs.HttpMethod.GET;
+import static javax.ws.rs.HttpMethod.POST;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Mock tests for the {@link org.jclouds.dimensiondata.cloudcontrol.features.NetworkApi} class.
+ */
+@Test(groups = "unit", testName = "NetworkApiMockTest", singleThreaded = true)
+public class NetworkApiMockTest extends BaseAccountAwareCloudControlMockTest {
+
+   public static final String DEFAULT_ACTION = "ACCEPT_DECISIVELY";
+   public static final String DEFAULT_IP_VERSION = "IPV4";
+
+   public void testListNetworkDomains() throws Exception {
+      server.enqueue(jsonResponse("/networkDomains.json"));
+      Iterable<NetworkDomain> networkDomains = api.getNetworkApi().listNetworkDomains().concat();
+      assertEquals(size(networkDomains), 1); // Force the PagedIterable to advance
+      assertEquals(server.getRequestCount(), 2);
+
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/networkDomain");
+   }
+
+   public void testListNetworkDomainsWithPagination() throws Exception {
+      server.enqueue(jsonResponse("/networkDomains-page1.json"));
+      server.enqueue(jsonResponse("/networkDomains-page2.json"));
+      Iterable<NetworkDomain> networkDomains = api.getNetworkApi().listNetworkDomains().concat().toList();
+
+      consumeIterableAndAssertAdditionalPagesRequested(networkDomains, 20, 0);
+
+      assertSent(HttpMethod.GET, expectedListNetworkDomainsUriBuilder().toString());
+      assertSent(HttpMethod.GET, addPageNumberToUriBuilder(expectedListNetworkDomainsUriBuilder(), 2).toString());
+   }
+
+   public void testGetNetworkDomain() throws Exception {
+      server.enqueue(jsonResponse("/networkDomain.json"));
+      api.getNetworkApi().getNetworkDomain("networkDomainId");
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/networkDomain/networkDomainId");
+   }
+
+   public void testGetNetworkDomain_404() throws Exception {
+      server.enqueue(response404());
+      api.getNetworkApi().listNetworkDomainsWithDatacenterIdAndName("testDatacenterId", "testName").concat();
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/networkDomain"
+            + "?datacenterId=testDatacenterId&name=testName");
+   }
+
+   public void testListNetworkDomainsWithName() throws Exception {
+      server.enqueue(jsonResponse("/networkDomains.json"));
+      api.getNetworkApi().listNetworkDomainsWithDatacenterIdAndName("testDatacenterId", "testName").concat();
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/networkDomain"
+            + "?datacenterId=testDatacenterId&name=testName");
+   }
+
+   public void testListNetworkDomainsWithNameWithPagination() throws Exception {
+      server.enqueue(jsonResponse("/networkDomains-page1.json"));
+      server.enqueue(jsonResponse("/networkDomains-page2.json"));
+      Iterable<NetworkDomain> networkDomains = api.getNetworkApi()
+            .listNetworkDomainsWithDatacenterIdAndName("testDatacenterId", "testName").concat();
+
+      consumeIterableAndAssertAdditionalPagesRequested(networkDomains, 20, 1);
+
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/networkDomain"
+            + "?datacenterId=testDatacenterId&name=testName");
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/networkDomain" + "?pageNumber=2");
+   }
+
+   public void testListNetworkDomainsWithName_404() throws Exception {
+      server.enqueue(response404());
+      api.getNetworkApi().listNetworkDomainsWithDatacenterIdAndName("testDatacenterId", "testName").concat();
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/networkDomain"
+            + "?datacenterId=testDatacenterId&name=testName");
+   }
+
+   public void testListVlansWithNetworkDomainId() throws Exception {
+      server.enqueue(jsonResponse("/vlans.json"));
+      api.getNetworkApi().listVlans("testNetworkDomainId");
+      assertSent(GET,
+            "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/vlan?networkDomainId=testNetworkDomainId");
+   }
+
+   public void testListVlansWithNetworkDomainId_404() throws Exception {
+      server.enqueue(response404());
+      api.getNetworkApi().listVlans("testNetworkDomainId");
+      assertSent(GET,
+            "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/vlan?networkDomainId=testNetworkDomainId");
+   }
+
+   public void testListVlanssWithPagination() throws Exception {
+      server.enqueue(jsonResponse("/vlans-page1.json"));
+      server.enqueue(jsonResponse("/vlans-page2.json"));
+      Iterable<Vlan> vlans = api.getNetworkApi().listVlans("12345").concat().toList();
+
+      consumeIterableAndAssertAdditionalPagesRequested(vlans, 20, 0);
+
+      assertSent(HttpMethod.GET, expectedListVlansRulesUriBuilder().toString());
+      assertSent(HttpMethod.GET, addPageNumberToUriBuilder(expectedListVlansRulesUriBuilder(), 2).toString());
+   }
+
+   public void testListVlans() throws Exception {
+      server.enqueue(new MockResponse().setBody(payloadFromResource("/vlans.json")));
+      assertEquals(api.getNetworkApi().listVlans("12345").concat().toList(), new VlansParseTest().expected().toList());
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/vlan?networkDomainId=12345");
+   }
+
+   public void testListVlans_404() throws Exception {
+      server.enqueue(response404());
+      assertTrue(api.getNetworkApi().listVlans("12345").concat().isEmpty());
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/vlan?networkDomainId=12345");
+   }
+
+   public void testGetVlan() throws Exception {
+      server.enqueue(new MockResponse().setBody(payloadFromResource("/vlan.json")));
+      api.getNetworkApi().getVlan("12345");
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/vlan/12345");
+   }
+
+   public void testGetVlan_404() throws Exception {
+      server.enqueue(response404());
+      api.getNetworkApi().getVlan("12345");
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/vlan/12345");
+   }
+
+   public void testListPublicIPv4AddressBlock() throws Exception {
+      server.enqueue(new MockResponse().setBody(payloadFromResource("/publicIpBlocks.json")));
+      assertEquals(api.getNetworkApi().listPublicIPv4AddressBlocks("12345").concat().toList(),
+            new PublicIpBlocksParseTest().expected().toList());
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/publicIpBlock?networkDomainId=12345");
+   }
+
+   public void testListPublicIPv4AddressBlock_404() throws Exception {
+      server.enqueue(response404());
+      assertTrue(api.getNetworkApi().listPublicIPv4AddressBlocks("12345").concat().isEmpty());
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/publicIpBlock?networkDomainId=12345");
+   }
+
+   public void testListPublicIPv4AddressBlockWithPagination() throws Exception {
+      server.enqueue(jsonResponse("/publicIpBlocks-page1.json"));
+      server.enqueue(jsonResponse("/publicIpBlocks-page2.json"));
+      Iterable<PublicIpBlock> ipBlocks = api.getNetworkApi().listPublicIPv4AddressBlocks("12345").concat().toList();
+
+      consumeIterableAndAssertAdditionalPagesRequested(ipBlocks, 20, 0);
+
+      assertSent(HttpMethod.GET, expectedListPublicIpBlockUriBuilder().toString());
+      assertSent(HttpMethod.GET, addPageNumberToUriBuilder(expectedListPublicIpBlockUriBuilder(), 2).toString());
+   }
+
+   public void testCreateFirewallRule() throws Exception {
+      server.enqueue(new MockResponse().setResponseCode(200).setBody(
+            "{\n" + "\"operation\": \"CREATE_FIREWALL_RULE\",\n" + "\"responseCode\": \"OK\",\n"
+                  + "\"message\": \"Request create Firewall Rule 'My.Rule' successful\", \"info\": [\n" + "{\n"
+                  + "\"name\": \"firewallRuleId\",\n" + "\"value\": \"dc545f3e-823c-4500-93c9-8d7f576311de\"\n"
+                  + "} ],\n" + "\"warning\": [],\n" + "\"error\": [],\n"
+                  + "\"requestId\": \"NA9/2015-03-05T13:46:34.848-05:00/f8fdef24-8a12-45ea-a831-\n"
+                  + "d5463212ef6a\" }"));
+      api.getNetworkApi().createFirewallRule("123456", "test", DEFAULT_ACTION, DEFAULT_IP_VERSION, DEFAULT_PROTOCOL,
+            FirewallRuleTarget.builder().ip(IpRange.create("ANY", null)).build(),
+            FirewallRuleTarget.builder().ip(IpRange.create("ANY", null)).build(), true,
+            Placement.builder().position("LAST").build());
+      assertSent(POST, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/createFirewallRule");
+   }
+
+   public void testDeleteNetworkDomain() throws Exception {
+      server.enqueue(new MockResponse().setResponseCode(200).setBody(
+            "{\n" + "\"operation\": \"DELETE_NETWORK_DOMAIN\",\n" + "\"responseCode\": \"IN_PROGRESS\",\n"
+                  + "\"message\": \"Request to Delete Network Domain (Id:12623a68-ebdb-11e3-9153-001b21cfdbe0)"
+                  + " has been accepted and is being processed\", \"info\": [],\n" + "\"warning\": [],\n"
+                  + "\"error\": [],\n" + "\"requestId\": \"NA9/2015-03-05T13:46:34.848-05:00/f8fdef24-8a12-45ea-a831-\n"
+                  + "d5463212ef6a\" }"));
+      api.getNetworkApi().deleteNetworkDomain("networkDomainId");
+      assertSent(POST, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/deleteNetworkDomain");
+   }
+
+   public void testDeleteNetworkDomain_404() throws Exception {
+      server.enqueue(response404());
+      api.getNetworkApi().deleteNetworkDomain("networkDomainId");
+      assertSent(POST, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/deleteNetworkDomain");
+   }
+
+   public void testRemovePublicIpBlock() throws Exception {
+      server.enqueue(new MockResponse().setResponseCode(200).setBody(
+            "{\n" + "\"operation\": \"REMOVE_PUBLIC_IP_BLOCK\",\n" + "\"responseCode\": \"OK\",\n"
+                  + "\"message\": \"Public Ip Block (Id:12623a68-ebdb-11e3-9153-001b21cfdbe0) has been removed successfully\","
+                  + " \"info\": [],\n" + "\"warning\": [],\n" + "\"error\": [],\n"
+                  + "\"requestId\": \"NA9/2015-03-05T13:46:34.848-05:00/f8fdef24-8a12-45ea-a831-\n"
+                  + "d5463212ef6a\" }"));
+      api.getNetworkApi().removePublicIpBlock("publicIpBlockId");
+      assertSent(POST, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/removePublicIpBlock");
+   }
+
+   public void testRemovePublicIpBlock_404() throws Exception {
+      server.enqueue(response404());
+      api.getNetworkApi().removePublicIpBlock("publicIpBlockId");
+      assertSent(POST, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/removePublicIpBlock");
+   }
+
+   public void testGetPublicIpBlock() throws Exception {
+      server.enqueue(jsonResponse("/publicIpBlock.json"));
+      api.getNetworkApi().getPublicIPv4AddressBlock("publicIpBlockId");
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/publicIpBlock/publicIpBlockId");
+   }
+
+   public void testGetPublicIpBlock_404() throws Exception {
+      server.enqueue(response404());
+      api.getNetworkApi().getPublicIPv4AddressBlock("publicIpBlockId");
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/publicIpBlock/publicIpBlockId");
+   }
+
+   public void testCreateNatRule() throws Exception {
+      server.enqueue(new MockResponse().setResponseCode(200).setBody(
+            "{\n" + "\"operation\": \"CREATE_NAT_RULE\",\n" + "\"responseCode\": \"OK\",\n"
+                  + "\"message\": \"Create Nat Rule Complete\", \"info\": [\n" + "{\n" + "\"name\": \"natRuleId\",\n"
+                  + "\"value\": \"dc545f3e-823c-4500-93c9-8d7f576311de\"\n" + "} ],\n" + "\"warning\": [],\n"
+                  + "\"error\": [],\n" + "\"requestId\": \"NA9/2015-03-05T13:46:34.848-05:00/f8fdef24-8a12-45ea-a831-\n"
+                  + "d5463212ef6a\" }"));
+      api.getNetworkApi().createNatRule("networkDomainId", "10.0.0.5", "155.143.0.54");
+      assertSent(POST, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/createNatRule");
+   }
+
+   public void testListNatRules() throws Exception {
+      server.enqueue(new MockResponse().setBody(payloadFromResource("/natRules.json")));
+      api.getNetworkApi().listNatRules("12345").concat().toList();
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/natRule?networkDomainId=12345");
+   }
+
+   public void testListNatRulesWithPagination() throws Exception {
+      server.enqueue(jsonResponse("/natRules-page1.json"));
+      server.enqueue(jsonResponse("/natRules-page2.json"));
+      Iterable<NatRule> natRules = api.getNetworkApi().listNatRules("12345").concat().toList();
+
+      consumeIterableAndAssertAdditionalPagesRequested(natRules, 20, 0);
+
+      assertSent(HttpMethod.GET, expectedListNatRulesUriBuilder().toString());
+      assertSent(HttpMethod.GET, addPageNumberToUriBuilder(expectedListNatRulesUriBuilder(), 2).toString());
+   }
+
+   public void testListNatRules_404() throws Exception {
+      server.enqueue(response404());
+      assertTrue(api.getNetworkApi().listNatRules("12345").concat().isEmpty());
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/natRule?networkDomainId=12345");
+   }
+
+   public void testGetNatRule() throws Exception {
+      server.enqueue(jsonResponse("/natRule.json"));
+      api.getNetworkApi().getNatRule("natRuleId");
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/natRule/natRuleId");
+   }
+
+   public void testGetNatRule_404() throws Exception {
+      server.enqueue(response404());
+      api.getNetworkApi().getNatRule("natRuleId");
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/natRule/natRuleId");
+   }
+
+   public void testListFirewallRules() throws Exception {
+      server.enqueue(new MockResponse().setBody(payloadFromResource("/firewallRules.json")));
+      api.getNetworkApi().listFirewallRules("12345").concat().toList();
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/firewallRule?networkDomainId=12345");
+   }
+
+   public void testListFirewallRules_404() throws Exception {
+      server.enqueue(response404());
+      api.getNetworkApi().listFirewallRules("12345").concat().toList();
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/firewallRule?networkDomainId=12345");
+   }
+
+   public void testListFirewallRulesWithPagination() throws Exception {
+      server.enqueue(jsonResponse("/firewallRules-page1.json"));
+      server.enqueue(jsonResponse("/firewallRules-page2.json"));
+      Iterable<FirewallRule> firewallRules = api.getNetworkApi().listFirewallRules("12345").concat().toList();
+
+      consumeIterableAndAssertAdditionalPagesRequested(firewallRules, 15, 0);
+
+      assertSent(HttpMethod.GET, expectedListFirewallRulesUriBuilder().toString());
+      assertSent(HttpMethod.GET, addPageNumberToUriBuilder(expectedListFirewallRulesUriBuilder(), 2).toString());
+   }
+
+   public void testDeleteFirewallRule() throws Exception {
+      server.enqueue(new MockResponse().setResponseCode(200).setBody(
+            "{\n" + "\"operation\": \"DELETE_FIREWALL_RULE\",\n" + "\"responseCode\": \"IN_PROGRESS\",\n"
+                  + "\"message\": \"Delete Firewall Rule (Id:12623a68-ebdb-11e3-9153-001b21cfdbe0) complete\", "
+                  + "\"info\": [],\n" + "\"warning\": [],\n" + "\"error\": [],\n"
+                  + "\"requestId\": \"NA9/2015-03-05T13:46:34.848-05:00/f8fdef24-8a12-45ea-a831-\n"
+                  + "d5463212ef6a\" }"));
+      api.getNetworkApi().deleteFirewallRule("firewallRuleId");
+      assertSent(POST, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/deleteFirewallRule");
+   }
+
+   public void testDeleteFirewallRule_404() throws Exception {
+      server.enqueue(response404());
+      api.getNetworkApi().deleteFirewallRule("firewallRuleId");
+      assertSent(POST, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/deleteFirewallRule");
+   }
+
+   public void testGetPortList() throws Exception {
+      server.enqueue(new MockResponse().setBody(payloadFromResource("/portList.json")));
+      api.getNetworkApi().getPortList("portListId");
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/portList/portListId");
+   }
+
+   public void testGetPortList_404() throws Exception {
+      server.enqueue(response404());
+      api.getNetworkApi().getPortList("portListId");
+      assertSent(GET, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/portList/portListId");
+   }
+
+   public void testDeletePortList() throws Exception {
+      server.enqueue(new MockResponse().setResponseCode(200).setBody(
+            "{\n" + "\"operation\": \"DELETE_PORT_LIST\",\n" + "\"responseCode\": \"IN_PROGRESS\",\n"
+                  + "\"message\": \"Port List with id portListId has been deleted.\", " + "\"info\": [],\n"
+                  + "\"warning\": [],\n" + "\"error\": [],\n"
+                  + "\"requestId\": \"NA9/2015-03-05T13:46:34.848-05:00/f8fdef24-8a12-45ea-a831-\n"
+                  + "d5463212ef6a\" }"));
+      api.getNetworkApi().deletePortList("portListId");
+      assertSent(POST, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/deletePortList");
+   }
+
+   public void testDeletePortList_404() throws Exception {
+      server.enqueue(response404());
+      api.getNetworkApi().deletePortList("portListId");
+      assertSent(POST, "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/deletePortList");
+   }
+
+   private Uris.UriBuilder expectedListFirewallRulesUriBuilder() {
+      Uris.UriBuilder uriBuilder = Uris
+            .uriBuilder("/caas/" + VERSION + "/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/firewallRule");
+      uriBuilder.addQuery("networkDomainId", "12345");
+      return uriBuilder;
+   }
+
+   private Uris.UriBuilder expectedListNatRulesUriBuilder() {
+      Uris.UriBuilder uriBuilder = Uris
+            .uriBuilder("/caas/" + VERSION + "/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/natRule");
+      uriBuilder.addQuery("networkDomainId", "12345");
+      return uriBuilder;
+   }
+
+   private Uris.UriBuilder expectedListNetworkDomainsUriBuilder() {
+      return Uris.uriBuilder("/caas/" + VERSION + "/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/networkDomain");
+   }
+
+   private Uris.UriBuilder expectedListVlansRulesUriBuilder() {
+      Uris.UriBuilder uriBuilder = Uris
+            .uriBuilder("/caas/" + VERSION + "/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/vlan");
+      uriBuilder.addQuery("networkDomainId", "12345");
+      return uriBuilder;
+   }
+
+   private Uris.UriBuilder expectedListPublicIpBlockUriBuilder() {
+      Uris.UriBuilder uriBuilder = Uris
+            .uriBuilder("/caas/" + VERSION + "/6ac1e746-b1ea-4da5-a24e-caf1a978789d/network/publicIpBlock");
+      uriBuilder.addQuery("networkDomainId", "12345");
+      return uriBuilder;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlMockTest.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlMockTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlMockTest.java
index 92079a0..7856524 100644
--- a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlMockTest.java
+++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlMockTest.java
@@ -47,6 +47,7 @@ import java.util.Set;
 import static com.google.common.collect.Iterables.size;
 import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.jclouds.util.Strings2.toStringAndClose;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.fail;
 
@@ -208,4 +209,12 @@ public class BaseDimensionDataCloudControlMockTest implements IHookable {
       uriBuilder.addQuery("pageNumber", Integer.toString(pageNumber));
       return uriBuilder;
    }
+
+   public byte[] payloadFromResource(String resource) {
+      try {
+         return toStringAndClose(getClass().getResourceAsStream(resource)).getBytes(Charsets.UTF_8);
+      } catch (IOException e) {
+         throw Throwables.propagate(e);
+      }
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/FirewallRulesParseTest.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/FirewallRulesParseTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/FirewallRulesParseTest.java
new file mode 100644
index 0000000..2fe920c
--- /dev/null
+++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/FirewallRulesParseTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.dimensiondata.cloudcontrol.parse;
+
+import com.google.common.collect.ImmutableList;
+import org.jclouds.dimensiondata.cloudcontrol.domain.FirewallRule;
+import org.jclouds.dimensiondata.cloudcontrol.domain.FirewallRuleTarget;
+import org.jclouds.dimensiondata.cloudcontrol.domain.FirewallRules;
+import org.jclouds.dimensiondata.cloudcontrol.domain.IpRange;
+import org.jclouds.dimensiondata.cloudcontrol.internal.BaseDimensionDataCloudControlParseTest;
+import org.testng.annotations.Test;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+
+@Test(groups = "unit")
+public class FirewallRulesParseTest extends BaseDimensionDataCloudControlParseTest<FirewallRules> {
+
+   @Override
+   public String resource() {
+      return "/firewallRules.json";
+   }
+
+   @Override
+   @Consumes(MediaType.APPLICATION_JSON)
+   public FirewallRules expected() {
+      List<FirewallRule> firewallRules = ImmutableList
+            .of(FirewallRule.builder().id("1aa3d0ce-d95d-4296-8338-9717e0d37ff9")
+                  .name("CCDEFAULT.BlockOutboundMailIPv6Secure").state("NORMAL").action("DROP").ipVersion("IPV6")
+                  .protocol("TCP").source(FirewallRuleTarget.builder().ip(IpRange.create("ANY", null)).build())
+                  .destination(FirewallRuleTarget.builder().ip(IpRange.create("ANY", null))
+                        .port(FirewallRuleTarget.Port.create(587, null)).build()).ruleType("DEFAULT_RULE")
+                  .networkDomainId("484174a2-ae74-4658-9e56-50fc90e086cf").enabled(Boolean.TRUE).datacenterId("NA9")
+                  .build());
+      return new FirewallRules(firewallRules, 1, 2, 2, 250);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/NatRulesParseTest.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/NatRulesParseTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/NatRulesParseTest.java
new file mode 100644
index 0000000..7858a0e
--- /dev/null
+++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/NatRulesParseTest.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.dimensiondata.cloudcontrol.parse;
+
+import com.google.common.collect.ImmutableList;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NatRule;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NatRules;
+import org.jclouds.dimensiondata.cloudcontrol.internal.BaseDimensionDataCloudControlParseTest;
+import org.testng.annotations.Test;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+
+@Test(groups = "unit")
+public class NatRulesParseTest extends BaseDimensionDataCloudControlParseTest<NatRules> {
+
+   @Override
+   public String resource() {
+      return "/natRules.json";
+   }
+
+   @Override
+   @Consumes(MediaType.APPLICATION_JSON)
+   public NatRules expected() {
+      List<NatRule> natRules = ImmutableList.of(NatRule.builder().id("2187a636-7ebb-49a1-a2ff-5d617f496dce")
+            .createTime(parseDate("2015-03-06T13:43:45.000Z")).state("NORMAL").externalIp("165.180.12.18")
+            .internalIp("10.0.0.15").networkDomainId("484174a2-ae74-4658-9e56-50fc90e086cf").datacenterId("NA9")
+            .build(), NatRule.builder().id("2169a38e-5692-497e-a22a-701a838a6539")
+            .createTime(parseDate("2015-03-06T13:45:10.000Z")).state("NORMAL").externalIp("165.180.12.19")
+            .internalIp("10.0.0.16").networkDomainId("484174a2-ae74-4658-9e56-50fc90e086cf").datacenterId("NA9")
+            .build());
+      return new NatRules(natRules, 1, 2, 2, 250);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/NetworkDomainsParseTest.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/NetworkDomainsParseTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/NetworkDomainsParseTest.java
new file mode 100644
index 0000000..c1eec7f
--- /dev/null
+++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/NetworkDomainsParseTest.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.dimensiondata.cloudcontrol.parse;
+
+import com.google.common.collect.ImmutableList;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkDomain;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkDomains;
+import org.jclouds.dimensiondata.cloudcontrol.domain.State;
+import org.jclouds.dimensiondata.cloudcontrol.internal.BaseDimensionDataCloudControlParseTest;
+import org.testng.annotations.Test;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+
+import static org.jclouds.dimensiondata.cloudcontrol.domain.NetworkDomain.Type.ESSENTIALS;
+
+@Test(groups = "unit")
+public class NetworkDomainsParseTest extends BaseDimensionDataCloudControlParseTest<NetworkDomains> {
+
+   @Override
+   public String resource() {
+      return "/networkDomains.json";
+   }
+
+   @Override
+   @Consumes(MediaType.APPLICATION_JSON)
+   public NetworkDomains expected() {
+      List<NetworkDomain> networkDomains = ImmutableList
+            .of(NetworkDomain.builder().id("8e082ed6-c198-4eff-97cb-aeac6f9685d8").datacenterId("NA9").name("test")
+                  .description("").state(State.NORMAL).type(ESSENTIALS).snatIpv4Address("168.128.3.44")
+                  .createTime(parseDate("2016-03-08T14:39:47.000Z")).build());
+      return new NetworkDomains(networkDomains, 1, 5, 5, 250);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/PublicIpBlocksParseTest.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/PublicIpBlocksParseTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/PublicIpBlocksParseTest.java
new file mode 100644
index 0000000..97c9512
--- /dev/null
+++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/PublicIpBlocksParseTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.dimensiondata.cloudcontrol.parse;
+
+import com.google.common.collect.ImmutableList;
+import org.jclouds.dimensiondata.cloudcontrol.domain.PublicIpBlock;
+import org.jclouds.dimensiondata.cloudcontrol.domain.PublicIpBlocks;
+import org.jclouds.dimensiondata.cloudcontrol.internal.BaseDimensionDataCloudControlParseTest;
+import org.testng.annotations.Test;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+
+@Test(groups = "unit")
+public class PublicIpBlocksParseTest extends BaseDimensionDataCloudControlParseTest<PublicIpBlocks> {
+
+   @Override
+   public String resource() {
+      return "/publicIpBlocks.json";
+   }
+
+   @Override
+   @Consumes(MediaType.APPLICATION_JSON)
+   public PublicIpBlocks expected() {
+      List<PublicIpBlock> publicIpBlocks = ImmutableList
+            .of(PublicIpBlock.builder().networkDomainId("690de302-bb80-49c6-b401-8c02bbefb945")
+                  .id("9993e5fc-bdce-11e4-8c14-b8ca3a5d9ef8").createTime(parseDate("2016-03-14T11:49:33.000Z"))
+                  .state("NORMAL").datacenterId("NA9").size(2).baseIp("168.128.6.216").build());
+      return new PublicIpBlocks(publicIpBlocks, 1, 5, 5, 250);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/2495dd9a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/VlansParseTest.java
----------------------------------------------------------------------
diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/VlansParseTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/VlansParseTest.java
new file mode 100644
index 0000000..cb74939
--- /dev/null
+++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/parse/VlansParseTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.dimensiondata.cloudcontrol.parse;
+
+import com.google.common.collect.ImmutableList;
+import org.jclouds.dimensiondata.cloudcontrol.domain.IpRange;
+import org.jclouds.dimensiondata.cloudcontrol.domain.NetworkDomain;
+import org.jclouds.dimensiondata.cloudcontrol.domain.State;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Vlan;
+import org.jclouds.dimensiondata.cloudcontrol.domain.Vlans;
+import org.jclouds.dimensiondata.cloudcontrol.internal.BaseDimensionDataCloudControlParseTest;
+import org.testng.annotations.Test;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+
+@Test(groups = "unit")
+public class VlansParseTest extends BaseDimensionDataCloudControlParseTest<Vlans> {
+
+   @Override
+   public String resource() {
+      return "/vlans.json";
+   }
+
+   @Override
+   @Consumes(MediaType.APPLICATION_JSON)
+   public Vlans expected() {
+      List<Vlan> vlans = ImmutableList.of(Vlan.builder()
+            .networkDomain(NetworkDomain.builder().id("690de302-bb80-49c6-b401-8c02bbefb945").name("test").build())
+            .id("6b25b02e-d3a2-4e69-8ca7-9bab605deebd").name("vlan1").description("")
+            .privateIpv4Range(IpRange.create("10.0.0.0", 24))
+            .ipv6Range(IpRange.create("2607:f480:111:1575:0:0:0:0", 64)).ipv4GatewayAddress("10.0.0.1")
+            .ipv6GatewayAddress("2607:f480:111:1575:0:0:0:1").createTime(parseDate("2016-03-11T10:41:19.000Z"))
+            .state(State.NORMAL).datacenterId("NA9").build());
+      return new Vlans(vlans, 1, 5, 5, 250);
+   }
+}