HONEYCOMB-64: Add ipv4 netmask support
authorMarek Gradzki <[email protected]>
Tue, 21 Jun 2016 08:21:39 +0000 (10:21 +0200)
committerMarek Gradzki <[email protected]>
Tue, 21 Jun 2016 13:12:00 +0000 (15:12 +0200)
Supported contiguous netmask only
(strictly, only leading 1s are allowed)
Update postman collection

Change-Id: I989bbd013227bc3e1eda0861241543db0cdbf656
Signed-off-by: Tibor Sirovatka <[email protected]>
Signed-off-by: Marek Gradzki <[email protected]>
v3po/postman_rest_collection.json
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/AddressCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4Customizer.java
v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/AddressCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtilsTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizerTest.java
v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtils.java
v3po/vpp-translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtilsTest.java

index 0a31f7b..192f9ec 100644 (file)
                        "name": "IP",
                        "description": "",
                        "order": [
-                               "945138cf-d1f0-4674-b221-7b271010be42",
-                               "a95120a1-5661-edc4-30cf-53afeb104440",
-                               "6c5c9786-3619-ccaf-c276-0ada45711b70",
-                               "3a93e78e-21ec-e0c9-94df-c69b60d9edcd"
+                               "69a05849-026d-f120-5c6a-f3e2b0884d88",
+                               "b10169c2-ae0e-bb1c-3dea-ca06839c6c9c",
+                               "8d49cf41-facc-c4ac-cee7-475d50e2a0be",
+                               "70835949-7252-a3cc-491b-f8aa69286399",
+                               "d5a90cfd-fd7e-63b6-e1f1-16fc0671b0e1",
+                               "3f7ee49b-ae11-b032-915f-a14bf838246f"
                        ],
                        "owner": "45557"
                },
                        "responses": [],
                        "rawModeData": "{\r\n    \r\n        \"interface\": [\r\n            {\r\n                \"name\": \"testInterface\",\r\n                \"description\": \"for testing purposes\",\r\n                \"type\": \"iana-if-type:ethernetCsmacd\",\r\n                \"enabled\": \"true\",\r\n                \"link-up-down-trap-enable\": \"enabled\",\r\n                \"ietf-ip:ipv4\": {\r\n                    \"enabled\": \"true\",\r\n                    \"mtu\": \"1500\",\r\n                    \"address\": [\r\n                        {\r\n                            \"ip\": \"1.2.3.0\",\r\n                            \"netmask\": \"255.255.255.0\"\r\n                        }\r\n                    ]\r\n                }\r\n            }\r\n        ]\r\n    \r\n}"
                },
-               {
-                       "id": "3a93e78e-21ec-e0c9-94df-c69b60d9edcd",
-                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
-                       "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4",
-                       "preRequestScript": "",
-                       "pathVariables": {},
-                       "method": "GET",
-                       "data": [],
-                       "dataMode": "raw",
-                       "version": 2,
-                       "tests": "",
-                       "currentHelper": "normal",
-                       "helperAttributes": {},
-                       "time": 1465473589796,
-                       "name": "Read local0/ipv4 - cfg",
-                       "description": "",
-                       "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
-                       "responses": [],
-                       "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
-                       "rawModeData": "{\r\n    \r\n        \"interface\": [\r\n            {\r\n                \"name\": \"testInterface\",\r\n                \"description\": \"for testing purposes\",\r\n                \"type\": \"iana-if-type:ethernetCsmacd\",\r\n                \"enabled\": \"true\",\r\n                \"link-up-down-trap-enable\": \"enabled\",\r\n                \"ietf-ip:ipv4\": {\r\n                    \"enabled\": \"true\",\r\n                    \"mtu\": \"1500\",\r\n                    \"address\": [\r\n                        {\r\n                            \"ip\": \"1.2.3.0\",\r\n                            \"netmask\": \"255.255.255.0\"\r\n                        }\r\n                    ]\r\n                }\r\n            }\r\n        ]\r\n    \r\n}"
-               },
                {
                        "id": "76e9ee89-1594-ff38-ffff-ffc8de5d4054",
                        "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
                        "responses": [],
                        "rawModeData": "{\r\n    \r\n        \"interface\": [\r\n            {\r\n                \"name\": \"testInterface\",\r\n                \"description\": \"for testing purposes\",\r\n                \"type\": \"iana-if-type:ethernetCsmacd\",\r\n                \"enabled\": \"true\",\r\n                \"link-up-down-trap-enable\": \"enabled\",\r\n                \"ietf-ip:ipv4\": {\r\n                    \"enabled\": \"true\",\r\n                    \"mtu\": \"1500\",\r\n                    \"address\": [\r\n                        {\r\n                            \"ip\": \"1.2.3.0\",\r\n                            \"netmask\": \"255.255.255.0\"\r\n                        }\r\n                    ]\r\n                }\r\n            }\r\n        ]\r\n    \r\n}"
                },
-               {
-                       "id": "6c5c9786-3619-ccaf-c276-0ada45711b70",
-                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
-                       "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/interface/local0/ipv4",
-                       "preRequestScript": "",
-                       "pathVariables": {},
-                       "method": "GET",
-                       "data": [],
-                       "dataMode": "raw",
-                       "version": 2,
-                       "tests": "",
-                       "currentHelper": "normal",
-                       "helperAttributes": {},
-                       "time": 1465473594194,
-                       "name": "Read local0/ipv4 - oper",
-                       "description": "",
-                       "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
-                       "responses": [],
-                       "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
-                       "rawModeData": "{\r\n    \r\n        \"interface\": [\r\n            {\r\n                \"name\": \"testInterface\",\r\n                \"description\": \"for testing purposes\",\r\n                \"type\": \"iana-if-type:ethernetCsmacd\",\r\n                \"enabled\": \"true\",\r\n                \"link-up-down-trap-enable\": \"enabled\",\r\n                \"ietf-ip:ipv4\": {\r\n                    \"enabled\": \"true\",\r\n                    \"mtu\": \"1500\",\r\n                    \"address\": [\r\n                        {\r\n                            \"ip\": \"1.2.3.0\",\r\n                            \"netmask\": \"255.255.255.0\"\r\n                        }\r\n                    ]\r\n                }\r\n            }\r\n        ]\r\n    \r\n}"
-               },
                {
                        "id": "7f312f15-a81e-b513-83b7-a5f7755eae67",
                        "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
                        "rawModeData": "{\r\n    \r\n        \"interface\": [\r\n            {\r\n                \"name\": \"testInterface\",\r\n                \"description\": \"for testing purposes\",\r\n                \"type\": \"iana-if-type:ethernetCsmacd\",\r\n                \"enabled\": \"true\",\r\n                \"link-up-down-trap-enable\": \"enabled\",\r\n                \"ietf-ip:ipv4\": {\r\n                    \"enabled\": \"true\",\r\n                    \"mtu\": \"1500\",\r\n                    \"address\": [\r\n                        {\r\n                            \"ip\": \"1.2.3.0\",\r\n                            \"netmask\": \"255.255.255.0\"\r\n                        }\r\n                    ]\r\n                }\r\n            }\r\n        ]\r\n    \r\n}"
                },
                {
-                       "id": "945138cf-d1f0-4674-b221-7b271010be42",
+                       "id": "69a05849-026d-f120-5c6a-f3e2b0884d88",
                        "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
                        "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/interface/local0",
                        "preRequestScript": "",
                        "rawModeData": "{\r\n    \r\n        \"interface\": [\r\n            {\r\n                \"name\": \"testInterface\",\r\n                \"description\": \"for testing purposes\",\r\n                \"type\": \"iana-if-type:ethernetCsmacd\",\r\n                \"enabled\": \"true\",\r\n                \"link-up-down-trap-enable\": \"enabled\",\r\n                \"ietf-ip:ipv4\": {\r\n                    \"enabled\": \"true\",\r\n                    \"mtu\": \"1500\",\r\n                    \"address\": [\r\n                        {\r\n                            \"ip\": \"1.2.3.0\",\r\n                            \"netmask\": \"255.255.255.0\"\r\n                        }\r\n                    ]\r\n                }\r\n            }\r\n        ]\r\n    \r\n}"
                },
                {
-                       "id": "a95120a1-5661-edc4-30cf-53afeb104440",
+                       "id": "b10169c2-ae0e-bb1c-3dea-ca06839c6c9c",
                        "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
-                       "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4",
+                       "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4/address/127.0.0.1",
                        "preRequestScript": "",
                        "pathVariables": {},
                        "method": "PUT",
                        "tests": "",
                        "currentHelper": "normal",
                        "helperAttributes": {},
-                       "time": 1465472513661,
+                       "time": 1466496859574,
                        "name": "Set ipv4 local0 interface - cfg",
                        "description": "",
                        "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
                        "responses": [],
                        "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
-                       "rawModeData": "{\r\n\r\n        \"ipv4\" : {\r\n            \"address\": [{\r\n                \"ip\" : \"127.0.0.1\",\r\n                \"prefix-length\" : \"24\"\r\n            }]\r\n        }\r\n}"
+                       "rawModeData": "{\r\n            \"address\": [{\r\n                \"ip\" : \"127.0.0.1\",\r\n                \"prefix-length\" : \"24\"\r\n            }]\r\n}"
+               },
+               {
+                       "id": "8d49cf41-facc-c4ac-cee7-475d50e2a0be",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4/address/127.0.0.1",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "DELETE",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1466497187475,
+                       "name": "Remove ipv4 from local0 interface - cfg",
+                       "description": "",
+                       "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+                       "responses": [],
+                       "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
+                       "rawModeData": ""
+               },
+               {
+                       "id": "70835949-7252-a3cc-491b-f8aa69286399",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4/address/127.0.0.1",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1466497176571,
+                       "name": "Set ipv4 local0 interface - cfg netmask",
+                       "description": "",
+                       "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+                       "responses": [],
+                       "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
+                       "rawModeData": "{\r\n            \"address\": [{\r\n                \"ip\" : \"127.0.0.1\",\r\n                \"netmask\": \"255.255.255.128\"\r\n            }]\r\n}"
+               },
+               {
+                       "id": "d5a90cfd-fd7e-63b6-e1f1-16fc0671b0e1",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/interface/local0/ipv4",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1465473594194,
+                       "name": "Read local0/ipv4 - oper",
+                       "description": "",
+                       "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+                       "responses": [],
+                       "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
+                       "rawModeData": "{\r\n    \r\n        \"interface\": [\r\n            {\r\n                \"name\": \"testInterface\",\r\n                \"description\": \"for testing purposes\",\r\n                \"type\": \"iana-if-type:ethernetCsmacd\",\r\n                \"enabled\": \"true\",\r\n                \"link-up-down-trap-enable\": \"enabled\",\r\n                \"ietf-ip:ipv4\": {\r\n                    \"enabled\": \"true\",\r\n                    \"mtu\": \"1500\",\r\n                    \"address\": [\r\n                        {\r\n                            \"ip\": \"1.2.3.0\",\r\n                            \"netmask\": \"255.255.255.0\"\r\n                        }\r\n                    ]\r\n                }\r\n            }\r\n        ]\r\n    \r\n}"
+               },
+               {
+                       "id": "3f7ee49b-ae11-b032-915f-a14bf838246f",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1466497212835,
+                       "name": "Read local0/ipv4 - cfg",
+                       "description": "",
+                       "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+                       "responses": [],
+                       "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
+                       "rawModeData": "{\r\n    \r\n        \"interface\": [\r\n            {\r\n                \"name\": \"testInterface\",\r\n                \"description\": \"for testing purposes\",\r\n                \"type\": \"iana-if-type:ethernetCsmacd\",\r\n                \"enabled\": \"true\",\r\n                \"link-up-down-trap-enable\": \"enabled\",\r\n                \"ietf-ip:ipv4\": {\r\n                    \"enabled\": \"true\",\r\n                    \"mtu\": \"1500\",\r\n                    \"address\": [\r\n                        {\r\n                            \"ip\": \"1.2.3.0\",\r\n                            \"netmask\": \"255.255.255.0\"\r\n                        }\r\n                    ]\r\n                }\r\n            }\r\n        ]\r\n    \r\n}"
                },
+
                {
                        "id": "ac161bec-e046-4bb7-d695-60bdfb0c6cea",
                        "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
index c99fcd2..0b62bc0 100644 (file)
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package io.fd.honeycomb.v3po.translate.v3po.interfaces.ip;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -34,6 +35,8 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev14061
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.Subnet;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.Netmask;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.openvpp.jvpp.VppBaseCallException;
@@ -45,8 +48,6 @@ import org.slf4j.LoggerFactory;
 
 /**
  * Customizer for writing {@link Address}
- *
- * @author jsrnicek
  */
 public class AddressCustomizer extends FutureJVppCustomizer implements ListWriterCustomizer<Address, AddressKey> {
 
@@ -60,29 +61,30 @@ public class AddressCustomizer extends FutureJVppCustomizer implements ListWrite
 
     @Override
     public void writeCurrentAttributes(InstanceIdentifier<Address> id, Address dataAfter, WriteContext writeContext)
-            throws WriteFailedException {
+        throws WriteFailedException {
         setAddress(true, id, dataAfter, writeContext);
     }
 
     @Override
     public void updateCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, Address dataAfter,
-            WriteContext writeContext) throws WriteFailedException {
-        throw new WriteFailedException.UpdateFailedException(id,dataBefore,dataAfter,new UnsupportedOperationException("Operation not supported"));
+                                        WriteContext writeContext) throws WriteFailedException {
+        throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+            new UnsupportedOperationException("Operation not supported"));
     }
 
     @Override
     public void deleteCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, WriteContext writeContext)
-            throws WriteFailedException {
+        throws WriteFailedException {
         setAddress(false, id, dataBefore, writeContext);
     }
 
     @Override
     public Optional<List<Address>> extract(InstanceIdentifier<Address> currentId, DataObject parentData) {
-        return Optional.fromNullable((((Ipv4)parentData).getAddress()));
+        return Optional.fromNullable((((Ipv4) parentData).getAddress()));
     }
 
-    private void setAddress(boolean add,final InstanceIdentifier<Address> id,  final Address address,
-            final WriteContext writeContext) throws WriteFailedException {
+    private void setAddress(boolean add, final InstanceIdentifier<Address> id, final Address address,
+                            final WriteContext writeContext) throws WriteFailedException {
 
         final String interfaceName = id.firstKeyOf(Interface.class).getName();
         final int swIfc = interfaceContext.getIndex(interfaceName, writeContext.getMappingContext());
@@ -90,9 +92,9 @@ public class AddressCustomizer extends FutureJVppCustomizer implements ListWrite
         Subnet subnet = address.getSubnet();
 
         if (subnet instanceof PrefixLength) {
-            setPrefixLengthSubnet(add,id, interfaceName, swIfc, address, (PrefixLength) subnet);
+            setPrefixLengthSubnet(add, id, interfaceName, swIfc, address, (PrefixLength) subnet);
         } else if (subnet instanceof Netmask) {
-            setNetmaskSubnet();
+            setNetmaskSubnet(add, id, interfaceName, swIfc, address, (Netmask) subnet);
         } else {
             // FIXME how does choice extensibility work
             // FIXME it is not even possible to create a dedicated
@@ -105,40 +107,95 @@ public class AddressCustomizer extends FutureJVppCustomizer implements ListWrite
         }
     }
 
-    private void setNetmaskSubnet() {
-        // FIXME
-        throw new UnsupportedOperationException("Unimplemented");
+    private void setNetmaskSubnet(final boolean add, final InstanceIdentifier<Address> id, final String name,
+                                  final int swIfc,
+                                  final Address ipv4Addr, final Netmask subnet) throws WriteFailedException {
+        LOG.debug("Setting Subnet(subnet-mask) for interface: {}, {}. Subnet: {}, Ipv4: {}", name, swIfc, subnet,
+            ipv4Addr);
+
+        byte[] addr = TranslateUtils.ipv4AddressNoZoneToArray(ipv4Addr.getIp());
+        final DottedQuad netmask = subnet.getNetmask();
+
+        checkNotNull(addr, "Null address");
+        checkNotNull(netmask, "Null netmask");
+
+        // find netmask bit-length
+        final short subnetLength = getSubnetMaskLength(netmask.getValue());
+        PrefixLengthBuilder lengthBuilder = new PrefixLengthBuilder().setPrefixLength(subnetLength);
+
+        setPrefixLengthSubnet(add, id, name, swIfc, ipv4Addr, lengthBuilder.build());
+    }
+
+    /**
+     * Returns the prefix size in bits of the specified subnet mask. Example: For the subnet mask 255.255.255.128 it
+     * returns 25 while for 255.0.0.0 it returns 8. If the passed subnetMask array is not complete or contains not only
+     * leading ones, IllegalArgumentExpression is thrown
+     *
+     * @param mask the subnet mask in dot notation 255.255.255.255
+     * @return the prefix length as number of bits
+     */
+    private static short getSubnetMaskLength(final String mask) {
+        String[] maskParts = mask.split("\\.");
+
+        final int DOTTED_QUAD_MASK_LENGHT = 4;
+        final int IPV4_ADDRESS_PART_BITS_COUNT = 8;
+        final int NETMASK_PART_LIMIT = 256; // 2 power to 8
+
+        checkArgument(maskParts.length == DOTTED_QUAD_MASK_LENGHT,
+            "Network mask %s is not in Quad Dotted Decimal notation!", mask);
+
+        long maskAsNumber = 0;
+        for (int i = 0; i < DOTTED_QUAD_MASK_LENGHT; i++) {
+            maskAsNumber <<= IPV4_ADDRESS_PART_BITS_COUNT;
+            int value = Integer.parseInt(maskParts[i]);
+            checkArgument(value < NETMASK_PART_LIMIT, "Network mask %s contains invalid number(s) over 255!", mask);
+            checkArgument(value >= 0, "Network mask %s contains invalid negative number(s)!", mask);
+            maskAsNumber += value;
+        }
+
+        String bits = Long.toBinaryString(maskAsNumber);
+        checkArgument(bits.length() == IPV4_ADDRESS_PART_BITS_COUNT * DOTTED_QUAD_MASK_LENGHT,
+            "Incorrect network mask %s", mask);
+        final int leadingOnes = bits.indexOf('0');
+        checkArgument(leadingOnes != -1, "Broadcast address %s is not allowed!", mask);
+        checkArgument(bits.substring(leadingOnes).indexOf('1') == -1,
+            "Non-contiguous network mask %s is not allowed!", mask);
+        return (short) leadingOnes;
     }
 
-    private void setPrefixLengthSubnet(boolean add,final InstanceIdentifier<Address> id, final String name, final int swIfc,
-            final Address address, final PrefixLength subnet) throws WriteFailedException {
+    private void setPrefixLengthSubnet(boolean add, final InstanceIdentifier<Address> id, final String name,
+                                       final int swIfc,
+                                       final Address address, final PrefixLength subnet) throws WriteFailedException {
         try {
-            Short plen = subnet.getPrefixLength();
             LOG.debug("Setting Subnet(prefix-length) for interface: {}, {}. Subnet: {}, Address: {}", name, swIfc,
-                    subnet, address);
-
-            byte[] addr = TranslateUtils.ipv4AddressNoZoneToArray(address.getIp());
+                subnet, address);
 
+            final Short plen = subnet.getPrefixLength();
             checkArgument(plen > 0, "Invalid length");
+
+            final byte[] addr = TranslateUtils.ipv4AddressNoZoneToArray(address.getIp());
             checkNotNull(addr, "Null address");
 
-            final CompletionStage<SwInterfaceAddDelAddressReply> swInterfaceAddDelAddressReplyCompletionStage = getFutureJVpp()
-                    .swInterfaceAddDelAddress(getSwInterfaceAddDelAddressRequest(swIfc, TranslateUtils.booleanToByte(add) /* isAdd */,
+            final CompletionStage<SwInterfaceAddDelAddressReply> swInterfaceAddDelAddressReplyCompletionStage =
+                getFutureJVpp()
+                    .swInterfaceAddDelAddress(
+                        getSwInterfaceAddDelAddressRequest(swIfc, TranslateUtils.booleanToByte(add) /* isAdd */,
                             (byte) 0 /* isIpv6 */, (byte) 0 /* delAll */, plen.byteValue(), addr));
 
             TranslateUtils.getReply(swInterfaceAddDelAddressReplyCompletionStage.toCompletableFuture());
 
             LOG.debug("Subnet(prefix-length) set successfully for interface: {}, {},  Subnet: {}, Address: {}", name,
-                    swIfc, subnet, address);
+                swIfc, subnet, address);
         } catch (VppBaseCallException e) {
             LOG.warn("Failed to set Subnet(prefix-length) for interface: {}, {},  Subnet: {}, Address: {}", name, swIfc,
-                    subnet, address);
+                subnet, address);
             throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e);
         }
     }
 
     private SwInterfaceAddDelAddress getSwInterfaceAddDelAddressRequest(final int swIfc, final byte isAdd,
-            final byte ipv6, final byte deleteAll, final byte length, final byte[] addr) {
+                                                                        final byte ipv6, final byte deleteAll,
+                                                                        final byte length, final byte[] addr) {
         final SwInterfaceAddDelAddress swInterfaceAddDelAddress = new SwInterfaceAddDelAddress();
         swInterfaceAddDelAddress.swIfIndex = swIfc;
         swInterfaceAddDelAddress.isAdd = isAdd;
index e2d3002..01a315a 100644 (file)
 
 package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
 
+import static com.google.common.base.Preconditions.checkArgument;
 import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceCustomizer.getCachedInterfaceDump;
 import static java.util.Objects.requireNonNull;
 
-import com.google.common.base.Preconditions;
 import io.fd.honeycomb.v3po.translate.ModificationCache;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.util.RWUtils;
@@ -120,7 +120,7 @@ public final class InterfaceUtils {
     public static String vppPhysAddrToYang(@Nonnull final byte[] vppPhysAddress, int startIndex) {
         Objects.requireNonNull(vppPhysAddress, "Empty physical address bytes");
         final int endIndex = startIndex + PHYSICAL_ADDRESS_LENGTH;
-        Preconditions.checkArgument(endIndex <= vppPhysAddress.length,
+        checkArgument(endIndex <= vppPhysAddress.length,
             "Invalid physical address size (%s) for given startIndex (%d), expected >= %d", vppPhysAddress.length,
             startIndex, endIndex);
         StringBuilder physAddr = new StringBuilder();
@@ -152,7 +152,7 @@ public final class InterfaceUtils {
      * @return VPP's representation of the if-index
      */
     public static int yangIfIndexToVpp(int yangIfIndex) {
-        Preconditions.checkArgument(yangIfIndex >= 1, "YANG if-index has invalid value %s", yangIfIndex);
+        checkArgument(yangIfIndex >= 1, "YANG if-index has invalid value %s", yangIfIndex);
         return yangIfIndex - 1;
     }
 
index b52b055..6c8bb94 100644 (file)
 package io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip;
 
 import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.MappingContext;
 import io.fd.honeycomb.v3po.translate.ModificationCache;
 import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.util.RWUtils;
 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address;
@@ -50,17 +52,21 @@ import org.slf4j.LoggerFactory;
  * Customizer for read operations for {@link Address} of {@link Ipv4}
  */
 public class Ipv4AddressCustomizer extends FutureJVppCustomizer
-        implements ListReaderCustomizer<Address, AddressKey, AddressBuilder> {
+    implements ListReaderCustomizer<Address, AddressKey, AddressBuilder> {
 
     private static final Logger LOG = LoggerFactory.getLogger(Ipv4AddressCustomizer.class);
 
     private static final String CACHE_KEY = Ipv4AddressCustomizer.class.getName();
 
-    public Ipv4AddressCustomizer(FutureJVpp futureJvpp) {
+    private final NamingContext interfaceContext;
+
+    public Ipv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext interfaceContext) {
         super(futureJvpp);
+        this.interfaceContext = interfaceContext;
     }
 
     @Override
+    @Nonnull
     public AddressBuilder getBuilder(@Nonnull InstanceIdentifier<Address> id) {
         return new AddressBuilder();
     }
@@ -68,7 +74,7 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer
     @Override
     public void readCurrentAttributes(@Nonnull InstanceIdentifier<Address> id, @Nonnull AddressBuilder builder,
                                       @Nonnull ReadContext ctx)
-            throws ReadFailedException {
+        throws ReadFailedException {
         LOG.debug("Reading attributes...");
 
         Optional<IpAddressDetailsReplyDump> dumpOptional = dumpAddresses(id, ctx);
@@ -77,15 +83,14 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer
             List<IpAddressDetails> details = dumpOptional.get().ipAddressDetails;
 
             AddressKey key = id.firstKeyOf(Address.class);
-            byte[] identifingIpBytes = TranslateUtils.ipv4AddressNoZoneToArray(key.getIp());
 
             IpAddressDetails detail = details.stream()
-                    .filter(singleDetail -> Arrays.equals(identifingIpBytes, singleDetail.ip))
-                    .collect(RWUtils.singleItemCollector());
+                .filter(singleDetail -> key.getIp().equals(TranslateUtils.arrayToIpv4AddressNoZone(singleDetail.ip)))
+                .collect(RWUtils.singleItemCollector());
 
             builder.setIp(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip))
-                    .setSubnet(new PrefixLengthBuilder()
-                            .setPrefixLength(Short.valueOf(detail.prefixLength)).build());
+                .setSubnet(new PrefixLengthBuilder()
+                    .setPrefixLength(Short.valueOf(detail.prefixLength)).build());
             LOG.info("Address read successfull");
 
         } else {
@@ -95,7 +100,7 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer
 
     @Override
     public List<AddressKey> getAllIds(@Nonnull InstanceIdentifier<Address> id, @Nonnull ReadContext context)
-            throws ReadFailedException {
+        throws ReadFailedException {
         LOG.debug("Extracting keys..");
 
         Optional<IpAddressDetailsReplyDump> dumpOptional = dumpAddresses(id, context);
@@ -105,8 +110,8 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer
             List<IpAddressDetails> details = dumpOptional.get().ipAddressDetails;
 
             return details.stream()
-                    .map(detail -> new AddressKey(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip)))
-                    .collect(Collectors.toList());
+                .map(detail -> new AddressKey(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip)))
+                .collect(Collectors.toList());
         } else {
             LOG.warn("No dump present");
             return Collections.emptyList();
@@ -121,7 +126,7 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer
     // TODO refactor after there is an more generic implementation of cache
     // operations
     private Optional<IpAddressDetailsReplyDump> dumpAddresses(InstanceIdentifier<Address> id, ReadContext ctx)
-            throws ReadFailedException {
+        throws ReadFailedException {
         Optional<IpAddressDetailsReplyDump> dumpFromCache = dumpAddressFromCache(ctx.getModificationCache());
 
         if (dumpFromCache.isPresent()) {
@@ -130,7 +135,7 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer
 
         Optional<IpAddressDetailsReplyDump> dumpFromOperational;
         try {
-            dumpFromOperational = dumpAddressFromOperationalData();
+            dumpFromOperational = dumpAddressFromOperationalData(id, ctx.getMappingContext());
         } catch (VppBaseCallException e) {
             throw new ReadFailedException(id, e);
         }
@@ -147,10 +152,15 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer
         return Optional.fromNullable((IpAddressDetailsReplyDump) cache.get(CACHE_KEY));
     }
 
-    private Optional<IpAddressDetailsReplyDump> dumpAddressFromOperationalData() throws VppBaseCallException {
+    private Optional<IpAddressDetailsReplyDump> dumpAddressFromOperationalData(final InstanceIdentifier<Address> id,
+                                                                               final MappingContext mappingContext)
+        throws VppBaseCallException {
         LOG.debug("Dumping from operational data...");
+        final IpAddressDump dumpRequest = new IpAddressDump();
+        dumpRequest.isIpv6 = 0;
+        dumpRequest.swIfIndex = interfaceContext.getIndex(id.firstKeyOf(Interface.class).getName(), mappingContext);
         return Optional.fromNullable(
-                TranslateUtils.getReply(getFutureJVpp().ipAddressDump(new IpAddressDump()).toCompletableFuture()));
+            TranslateUtils.getReply(getFutureJVpp().ipAddressDump(dumpRequest).toCompletableFuture()));
     }
 
 }
index a10ad3b..8e61627 100644 (file)
@@ -20,7 +20,6 @@ import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
 import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer;
 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
-import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
 import javax.annotation.Nonnull;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2Builder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4;
@@ -36,12 +35,8 @@ public class Ipv4Customizer extends FutureJVppCustomizer implements ChildReaderC
 
     private static final Logger LOG = LoggerFactory.getLogger(Ipv4Customizer.class);
 
-    //do not remove,it will be needed in future implementation
-    private final NamingContext interfaceContext;
-
-    public Ipv4Customizer(@Nonnull final FutureJVpp futureJvpp, final NamingContext interfaceContext) {
+    public Ipv4Customizer(@Nonnull final FutureJVpp futureJvpp) {
         super(futureJvpp);
-        this.interfaceContext = interfaceContext;
     }
 
     @Override
index 733942e..644a272 100644 (file)
@@ -101,11 +101,11 @@ public class InterfacesStateHoneycombReaderModule extends
     private ChildReader<? extends Augmentation<Interface>> getInterface1AugmentationReader() {
 
         final ChildReader<Address> addressReader = new CompositeListReader<>(Address.class,
-                new Ipv4AddressCustomizer(getVppJvppDependency()));
+                new Ipv4AddressCustomizer(getVppJvppDependency(), getInterfaceContextIfcStateDependency()));
 
         final ChildReader<? extends ChildOf<Interface2>> ipv4Reader = new CompositeChildReader<>(Ipv4.class,
                 RWUtils.singletonChildReaderList(addressReader),
-                new Ipv4Customizer(getVppJvppDependency(), getInterfaceContextIfcStateDependency()));
+                new Ipv4Customizer(getVppJvppDependency()));
         final ChildReader<? extends ChildOf<Interface2>> ipv6Reader = new CompositeChildReader<>(Ipv6.class,
                 new Ipv6Customizer(getVppJvppDependency(), getInterfaceContextIfcStateDependency()));
 
index 9924e31..3ad12e0 100644 (file)
@@ -1,23 +1,44 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed 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 io.fd.honeycomb.v3po.translate.v3po.interfaces.ip;
 
+import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.mockMapping;
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
 
 import com.google.common.base.Optional;
 import io.fd.honeycomb.v3po.translate.MappingContext;
+import io.fd.honeycomb.v3po.translate.v3po.test.TestHelperUtils;
 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.v3po.translate.write.WriteContext;
 import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
+import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
-import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
+import org.mockito.Mock;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
@@ -28,126 +49,262 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev14061
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4Builder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.Netmask;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.NetmaskBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.VppInvocationException;
 import org.openvpp.jvpp.dto.SwInterfaceAddDelAddress;
 import org.openvpp.jvpp.dto.SwInterfaceAddDelAddressReply;
 import org.openvpp.jvpp.future.FutureJVpp;
 
 public class AddressCustomizerTest {
 
-    @Test
-    public void testWriteCurrentAttributes() throws WriteFailedException {
+    private static final String IFC_CTX_NAME = "ifc-test-instance";
+    private static final String IFACE_NAME = "eth0";
+    private static final int IFACE_ID = 123;
 
-        ArgumentCaptor<SwInterfaceAddDelAddress> requestCaptor = ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class);
+    @Mock
+    private WriteContext writeContext;
+    @Mock
+    private MappingContext mappingContext;
+    @Mock
+    private FutureJVpp api;
 
-        FutureJVpp jvpp = mock(FutureJVpp.class);
-        WriteContext context = mock(WriteContext.class);
-        MappingContext mappingContext = mock(MappingContext.class);
-        NamingContext namingContext = new NamingContext("prefix", "instance");
+    private NamingContext interfaceContext;
+    private AddressCustomizer customizer;
 
-        namingContext.addName(5, "parent", mappingContext);
+    @Before
+    public void setUp() throws Exception {
+        initMocks(this);
+        doReturn(mappingContext).when(writeContext).getMappingContext();
+        interfaceContext = new NamingContext("generatedlIfaceName", IFC_CTX_NAME);
 
-        InterfaceKey key = new InterfaceKey("local0");
+        customizer = new AddressCustomizer(api, interfaceContext);
+    }
 
-        InstanceIdentifier<Address> id = InstanceIdentifier.builder(Interfaces.class)
-                .child(Interface.class,key)
-                .augmentation(Interface1.class)
-                .child(Ipv4.class)
-                .child(Address.class)
-                .build();
+    private static InstanceIdentifier<Address> getAddressId(final String ifaceName) {
+        return InstanceIdentifier.builder(Interfaces.class)
+            .child(Interface.class, new InterfaceKey(ifaceName))
+            .augmentation(Interface1.class)
+            .child(Ipv4.class)
+            .child(Address.class)
+            .build();
+    }
 
-        Mapping mapping = mock(Mapping.class);
+    private void whenSwInterfaceAddDelAddressThenSuccess() {
+        final CompletableFuture<SwInterfaceAddDelAddressReply> replyFuture = new CompletableFuture<>();
+        final SwInterfaceAddDelAddressReply reply = new SwInterfaceAddDelAddressReply();
+        replyFuture.complete(reply);
+        doReturn(replyFuture).when(api).swInterfaceAddDelAddress(any(SwInterfaceAddDelAddress.class));
+    }
 
-        Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
+    private void whenSwInterfaceAddDelAddressThenFailure() {
+        doReturn(TestHelperUtils.createFutureException()).when(api)
+            .swInterfaceAddDelAddress(any(SwInterfaceAddDelAddress.class));
+    }
 
-        PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build();
-        Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build();
+    private void verifySwInterfaceAddDelAddressWasInvoked(final SwInterfaceAddDelAddress expected) throws
+        VppInvocationException {
+        ArgumentCaptor<SwInterfaceAddDelAddress> argumentCaptor =
+            ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class);
+        verify(api).swInterfaceAddDelAddress(argumentCaptor.capture());
+        verifySwInterfaceAddDelAddressWasInvoked(expected, argumentCaptor.getValue());
+    }
 
-        CompletableFuture<SwInterfaceAddDelAddressReply> future = new CompletableFuture<>();
-        future.complete(new SwInterfaceAddDelAddressReply());
+    private void verifySwInterfaceAddDelAddressWasInvoked(final SwInterfaceAddDelAddress expected,
+                                                          final SwInterfaceAddDelAddress actual) throws
+        VppInvocationException {
+        assertArrayEquals(expected.address, actual.address);
+        assertEquals(expected.addressLength, actual.addressLength);
+        assertEquals(expected.delAll, actual.delAll);
+        assertEquals(expected.isAdd, actual.isAdd);
+        assertEquals(expected.isIpv6, actual.isIpv6);
+        assertEquals(expected.swIfIndex, actual.swIfIndex);
+    }
 
-        when(context.getMappingContext()).thenReturn(mappingContext);
-        when(mapping.getIndex()).thenReturn(5);
-        when(mapping.getName()).thenReturn("local0");
-        when(mappingContext.read(Mockito.any())).thenReturn(Optional.fromNullable(mapping));
-        when(jvpp.swInterfaceAddDelAddress(Mockito.any(SwInterfaceAddDelAddress.class))).thenReturn(future);
+    @Test
+    public void testAddPrefixLengthIpv4Address() throws Exception {
+        final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME);
 
-        new AddressCustomizer(jvpp, namingContext).writeCurrentAttributes(id, data, context);
+        Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
+        PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build();
+        Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build();
 
-        verify(jvpp, times(1)).swInterfaceAddDelAddress(requestCaptor.capture());
+        mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME);
+        whenSwInterfaceAddDelAddressThenSuccess();
 
-        SwInterfaceAddDelAddress request = requestCaptor.getValue();
+        customizer.writeCurrentAttributes(id, data, writeContext);
 
-        assertEquals(0, request.isIpv6);
-        assertEquals(1, request.isAdd);
-        assertEquals(0, request.delAll);
-        assertEquals(5, request.swIfIndex);
-        assertEquals(24, request.addressLength);
-        assertEquals(true,Arrays.equals(new byte[]{-64, -88, 2, 1}, request.address));
+        verifySwInterfaceAddDelAddressWasInvoked(generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1},
+            (byte) 1, (byte) 24));
     }
 
     @Test
-    public void testDeleteCurrentAttributes() throws WriteFailedException {
-        ArgumentCaptor<SwInterfaceAddDelAddress> requestCaptor = ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class);
-
-        FutureJVpp jvpp = mock(FutureJVpp.class);
-        WriteContext context = mock(WriteContext.class);
-        MappingContext mappingContext = mock(MappingContext.class);
-        NamingContext namingContext = new NamingContext("prefix", "instance");
+    public void testAddPrefixLengthIpv4AddressFailed() throws Exception {
+        final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME);
 
-        namingContext.addName(5, "parent", mappingContext);
+        Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
+        PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build();
+        Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build();
 
-        InterfaceKey key = new InterfaceKey("local0");
+        mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME);
+        whenSwInterfaceAddDelAddressThenFailure();
+
+        try {
+            customizer.writeCurrentAttributes(id, data, writeContext);
+        } catch (WriteFailedException e) {
+            assertTrue(e.getCause() instanceof VppBaseCallException);
+            verifySwInterfaceAddDelAddressWasInvoked(
+                generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1},
+                    (byte) 1, (byte) 24));
+            return;
+        }
+        fail("WriteFailedException was expected");
+    }
 
-        InstanceIdentifier<Address> id = InstanceIdentifier.builder(Interfaces.class)
-                .child(Interface.class,key)
-                .augmentation(Interface1.class)
-                .child(Ipv4.class)
-                .child(Address.class)
-                .build();
+    private SwInterfaceAddDelAddress generateSwInterfaceAddDelAddressRequest(final byte[] address, final byte isAdd,
+                                                                             final byte prefixLength) {
+        final SwInterfaceAddDelAddress request = new SwInterfaceAddDelAddress();
+        request.swIfIndex = IFACE_ID;
+        request.isAdd = isAdd;
+        request.isIpv6 = 0;
+        request.delAll = 0;
+        request.addressLength = prefixLength;
+        request.address = address;
+        return request;
+    }
 
-        Mapping mapping = mock(Mapping.class);
+    @Test
+    public void testDeletePrefixLengthIpv4Address() throws Exception {
+        final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME);
 
         Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
-
         PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build();
         Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build();
 
-        CompletableFuture<SwInterfaceAddDelAddressReply> future = new CompletableFuture<>();
-        future.complete(new SwInterfaceAddDelAddressReply());
+        mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME);
+        whenSwInterfaceAddDelAddressThenSuccess();
 
-        when(context.getMappingContext()).thenReturn(mappingContext);
-        when(mapping.getIndex()).thenReturn(5);
-        when(mapping.getName()).thenReturn("local0");
-        when(mappingContext.read(Mockito.any())).thenReturn(Optional.fromNullable(mapping));
-        when(jvpp.swInterfaceAddDelAddress(Mockito.any(SwInterfaceAddDelAddress.class))).thenReturn(future);
+        customizer.deleteCurrentAttributes(id, data, writeContext);
 
-        new AddressCustomizer(jvpp, namingContext).deleteCurrentAttributes(id, data, context);
+        verifySwInterfaceAddDelAddressWasInvoked(generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1},
+            (byte) 0, (byte) 24));
+    }
 
-        verify(jvpp, times(1)).swInterfaceAddDelAddress(requestCaptor.capture());
+    @Test
+    public void testDeletePrefixLengthIpv4AddressFailed() throws Exception {
+        final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME);
 
-        SwInterfaceAddDelAddress request = requestCaptor.getValue();
+        Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
+        PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build();
+        Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build();
 
-        assertEquals(0, request.isIpv6);
-        assertEquals(0, request.isAdd);
-        assertEquals(0, request.delAll);
-        assertEquals(5, request.swIfIndex);
-        assertEquals(24, request.addressLength);
-        assertEquals(true,Arrays.equals(new byte[]{-64, -88, 2, 1}, request.address));
+        mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME);
+        whenSwInterfaceAddDelAddressThenFailure();
+
+        try {
+            customizer.deleteCurrentAttributes(id, data, writeContext);
+        } catch (WriteFailedException e) {
+            assertTrue(e.getCause() instanceof VppBaseCallException);
+            verifySwInterfaceAddDelAddressWasInvoked(
+                generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1},
+                    (byte) 0, (byte) 24));
+            return;
+        }
+        fail("WriteFailedException was expec16ted");
     }
 
     @Test
     public void testExtract() {
+        final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME);
+
         Address address = new AddressBuilder().build();
         Ipv4 parentData = new Ipv4Builder().setAddress(Arrays.asList(address)).build();
 
-        Optional<List<Address>> addressesOptional = new AddressCustomizer(mock(FutureJVpp.class),null).extract(null, parentData);
+        Optional<List<Address>> addressesOptional = customizer.extract(id, parentData);
+
+        assertEquals(true, addressesOptional.isPresent());
+        assertEquals(1, addressesOptional.get().size());
+        assertEquals(true, addressesOptional.get().contains(address));
+    }
+
+    private void testSingleNetmask(final int expectedPrefixLength, final String stringMask) throws Exception {
+        final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME);
 
-        assertEquals(true,addressesOptional.isPresent());
-        assertEquals(1,addressesOptional.get().size());
-        assertEquals(true,addressesOptional.get().contains(address));
+        Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
+        Netmask subnet = new NetmaskBuilder().setNetmask(new DottedQuad(stringMask)).build();
+        Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(subnet).build();
+
+        mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME);
+
+        final CompletableFuture<SwInterfaceAddDelAddressReply> replyFuture = new CompletableFuture<>();
+        replyFuture.complete(new SwInterfaceAddDelAddressReply());
+        ArgumentCaptor<SwInterfaceAddDelAddress> argumentCaptor =
+            ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class);
+        doReturn(replyFuture).when(api).swInterfaceAddDelAddress(argumentCaptor.capture());
+
+        customizer.writeCurrentAttributes(id, data, writeContext);
+
+        verifySwInterfaceAddDelAddressWasInvoked(generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1},
+            (byte) 1, (byte) expectedPrefixLength), argumentCaptor.getValue());
+    }
+
+    private void testSingleIllegalNetmask(final String stringMask) throws Exception {
+        try {
+            final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME);
+
+            Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
+            Netmask subnet = new NetmaskBuilder().setNetmask(new DottedQuad(stringMask)).build();
+            Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(subnet).build();
+
+            mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME);
+
+            final CompletableFuture<SwInterfaceAddDelAddressReply> replyFuture = new CompletableFuture<>();
+            replyFuture.complete(new SwInterfaceAddDelAddressReply());
+            ArgumentCaptor<SwInterfaceAddDelAddress> argumentCaptor =
+                ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class);
+            doReturn(replyFuture).when(api).swInterfaceAddDelAddress(argumentCaptor.capture());
+
+            customizer.writeCurrentAttributes(id, data, writeContext);
+        } catch (IllegalArgumentException e) {
+            return;
+        }
+        fail("IllegalArgumentException expected");
+
+    }
+
+    /**
+     * Test contiguous netmask length from QuadDotted notation
+     */
+    @Test
+    public void testNetmaskLength() throws Exception {
+        testSingleNetmask(1, "128.0.0.0");
+        testSingleNetmask(2, "192.0.0.0");
+        testSingleNetmask(8, "255.0.0.0");
+        testSingleNetmask(9, "255.128.0.0");
+        testSingleNetmask(16, "255.255.0.0");
+        testSingleNetmask(24, "255.255.255.0");
+    }
+
+    @Test
+    public void testNetmaskIllegal() throws Exception {
+        testSingleIllegalNetmask("");
+        testSingleIllegalNetmask(".");
+        testSingleIllegalNetmask(".255");
+        testSingleIllegalNetmask("255");
+        testSingleIllegalNetmask("255.");
+        testSingleIllegalNetmask("255.255");
+        testSingleIllegalNetmask("255.255.0");
+        testSingleIllegalNetmask("255.255.255.");
+        testSingleIllegalNetmask("255.255.255.256");
+        testSingleIllegalNetmask("0.0.0.0");
+        testSingleIllegalNetmask("10.10.10.10");
+        testSingleIllegalNetmask("255.1.255.0");
+        testSingleIllegalNetmask("255.255.255.255");
     }
 
 }
index 0f45f1c..c578162 100644 (file)
@@ -22,8 +22,8 @@ import org.junit.Test;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel;
 
 public class InterfaceUtilsTest {
 
index 8008ba5..85f528e 100644 (file)
 
 package io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip;
 
+import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping;
+import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid;
+import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.reverseBytes;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
 import io.fd.honeycomb.v3po.translate.ModificationCache;
-import io.fd.honeycomb.v3po.translate.read.ReadContext;
 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import io.fd.honeycomb.v3po.translate.spi.read.RootReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.v3po.test.ListReaderCustomizerTest;
+import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils;
 import java.util.Arrays;
 import java.util.List;
@@ -34,10 +40,15 @@ import java.util.concurrent.CompletableFuture;
 import java.util.stream.Collectors;
 import org.junit.Test;
 import org.mockito.Mockito;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder;
@@ -45,64 +56,93 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev14061
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.openvpp.jvpp.dto.IpAddressDetails;
 import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump;
 import org.openvpp.jvpp.dto.IpAddressDump;
-import org.openvpp.jvpp.future.FutureJVpp;
 
-public class Ipv4AddressCustomizerTest {
+public class Ipv4AddressCustomizerTest extends ListReaderCustomizerTest<Address, AddressKey, AddressBuilder> {
 
-    @Test
-    public void testGetBuilder() {
-        assertNotNull(new Ipv4AddressCustomizer(mock(FutureJVpp.class)).getBuilder(null));
+    private static final String IFACE_NAME = "eth0";
+    private static final int IFACE_ID = 1;
+
+    private NamingContext interfacesContext;
+
+    public Ipv4AddressCustomizerTest() {
+        super(Address.class);
+    }
+
+    @Override
+    public void setUpBefore() {
+        interfacesContext = new NamingContext("generatedIfaceName", "test-instance");
+    }
+
+    @Override
+    protected RootReaderCustomizer<Address, AddressBuilder> initCustomizer() {
+        final KeyedInstanceIdentifier<Mapping, MappingKey> eth0Id = getMappingIid(IFACE_NAME, "test-instance");
+        final Optional<Mapping> eth0 = getMapping(IFACE_NAME, IFACE_ID);
+
+        final List<Mapping> allMappings = Lists.newArrayList(getMapping(IFACE_NAME, IFACE_ID).get());
+        final Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build();
+        doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(eth0Id.firstIdentifierOf(Mappings.class));
+
+        doReturn(eth0).when(mappingContext).read(eth0Id);
+
+        return new Ipv4AddressCustomizer(api, interfacesContext);
+    }
+
+    private static InstanceIdentifier<Address> getId(final String address) {
+        return InstanceIdentifier.builder(InterfacesState.class)
+            .child(Interface.class, new InterfaceKey(IFACE_NAME))
+            .augmentation(Interface2.class)
+            .child(Ipv4.class)
+            .child(Address.class, new AddressKey(new Ipv4AddressNoZone(new Ipv4Address(address))))
+            .build();
     }
 
     @Test
     public void testReadCurrentAttributesFromCache() throws ReadFailedException {
-        ReadContext context = mock(ReadContext.class);
         ModificationCache cache = new ModificationCache();
-        FutureJVpp jvpp = mock(FutureJVpp.class);
 
         IpAddressDetails detail1 = new IpAddressDetails();
         IpAddressDetails detail2 = new IpAddressDetails();
         IpAddressDetails detail3 = new IpAddressDetails();
 
-        detail1.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")));
-        detail2.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")));
-        detail3.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")));
+        detail1.ip = reverseBytes(
+            TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"))));
+        detail2.ip = reverseBytes(
+            TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2"))));
+        detail3.ip = reverseBytes(
+            TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3"))));
 
         IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump();
         reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3);
 
         cache.put(Ipv4AddressCustomizer.class.getName(), reply);
-        when(context.getModificationCache()).thenReturn(cache);
+        when(ctx.getModificationCache()).thenReturn(cache);
 
-        AddressBuilder builder = new AddressBuilder();
-        InstanceIdentifier<Address> id = InstanceIdentifier.builder(InterfacesState.class)
-                .child(Interface.class)
-                .augmentation(Interface2.class)
-                .child(Ipv4.class)
-                .child(Address.class, new AddressKey(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"))))
-                .build();
+        final AddressBuilder builder = new AddressBuilder();
+        final InstanceIdentifier<Address> id = getId("192.168.2.1");
 
-        new Ipv4AddressCustomizer(jvpp).readCurrentAttributes(id, builder, context);
+        getCustomizer().readCurrentAttributes(id, builder, ctx);
 
-        assertEquals("1.2.168.192", builder.getIp().getValue());
+        assertEquals("192.168.2.1", builder.getIp().getValue());
     }
 
     @Test
     public void testReadCurrentAttributesFromOperationalData() throws ReadFailedException {
-        ReadContext context = mock(ReadContext.class);
         ModificationCache cache = new ModificationCache();
-        FutureJVpp jvpp = mock(FutureJVpp.class);
 
         IpAddressDetails detail1 = new IpAddressDetails();
         IpAddressDetails detail2 = new IpAddressDetails();
         IpAddressDetails detail3 = new IpAddressDetails();
 
-        detail1.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")));
-        detail2.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")));
-        detail3.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")));
+        detail1.ip = reverseBytes(
+            TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"))));
+        detail2.ip = reverseBytes(
+            TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2"))));
+        detail3.ip = reverseBytes(
+            TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3"))));
 
         IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump();
         reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3);
@@ -110,65 +150,66 @@ public class Ipv4AddressCustomizerTest {
         CompletableFuture<IpAddressDetailsReplyDump> future = new CompletableFuture<>();
         future.complete(reply);
 
-        when(jvpp.ipAddressDump(Mockito.any(IpAddressDump.class))).thenReturn(future);
-        when(context.getModificationCache()).thenReturn(cache);
+        when(api.ipAddressDump(Mockito.any(IpAddressDump.class))).thenReturn(future);
+        when(ctx.getModificationCache()).thenReturn(cache);
+
 
-        AddressBuilder builder = new AddressBuilder();
-        InstanceIdentifier<Address> id = InstanceIdentifier.builder(InterfacesState.class)
-                .child(Interface.class)
-                .augmentation(Interface2.class)
-                .child(Ipv4.class)
-                .child(Address.class, new AddressKey(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"))))
-                .build();
+        final AddressBuilder builder = new AddressBuilder();
+        final InstanceIdentifier<Address> id = getId("192.168.2.1");
 
-        new Ipv4AddressCustomizer(jvpp).readCurrentAttributes(id, builder, context);
+        getCustomizer().readCurrentAttributes(id, builder, ctx);
 
-        assertEquals("1.2.168.192", builder.getIp().getValue());
+        assertEquals("192.168.2.1", builder.getIp().getValue());
     }
 
     @Test
     public void testGetAllIdsFromCache() throws ReadFailedException {
-        ReadContext context = mock(ReadContext.class);
         ModificationCache cache = new ModificationCache();
-        FutureJVpp jvpp = mock(FutureJVpp.class);
 
         IpAddressDetails detail1 = new IpAddressDetails();
         IpAddressDetails detail2 = new IpAddressDetails();
         IpAddressDetails detail3 = new IpAddressDetails();
 
-        detail1.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")));
-        detail2.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")));
-        detail3.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")));
+        detail1.ip = reverseBytes(
+            TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"))));
+        detail2.ip = reverseBytes(
+            TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2"))));
+        detail3.ip = reverseBytes(
+            TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3"))));
 
         IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump();
         reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3);
 
         cache.put(Ipv4AddressCustomizer.class.getName(), reply);
-        when(context.getModificationCache()).thenReturn(cache);
-        List<Ipv4AddressNoZone> ids = new Ipv4AddressCustomizer(jvpp).getAllIds(null, context).stream()
-                .map(id -> id.getIp())
-                .collect(Collectors.toList());
+        when(ctx.getModificationCache()).thenReturn(cache);
 
-        verify(jvpp, times(0)).ipAddressDump(Mockito.any(IpAddressDump.class));
+        final InstanceIdentifier<Address> id = getId("192.168.2.1");
+
+        List<Ipv4AddressNoZone> ids = getCustomizer().getAllIds(id, ctx).stream()
+            .map(key -> key.getIp())
+            .collect(Collectors.toList());
+
+        verify(api, times(0)).ipAddressDump(Mockito.any(IpAddressDump.class));
         assertEquals(3, ids.size());
-        assertEquals(true, "1.2.168.192".equals(ids.get(0).getValue()));
-        assertEquals(true, "2.2.168.192".equals(ids.get(1).getValue()));
-        assertEquals(true, "3.2.168.192".equals(ids.get(2).getValue()));
+        assertEquals(true, "192.168.2.1".equals(ids.get(0).getValue()));
+        assertEquals(true, "192.168.2.2".equals(ids.get(1).getValue()));
+        assertEquals(true, "192.168.2.3".equals(ids.get(2).getValue()));
     }
 
     @Test
     public void testGetAllIdsFromOperationalData() throws ReadFailedException {
-        ReadContext context = mock(ReadContext.class);
         ModificationCache cache = new ModificationCache();
-        FutureJVpp jvpp = mock(FutureJVpp.class);
 
         IpAddressDetails detail1 = new IpAddressDetails();
         IpAddressDetails detail2 = new IpAddressDetails();
         IpAddressDetails detail3 = new IpAddressDetails();
 
-        detail1.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")));
-        detail2.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")));
-        detail3.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")));
+        detail1.ip = reverseBytes(
+            TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"))));
+        detail2.ip = reverseBytes(
+            TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2"))));
+        detail3.ip = reverseBytes(
+            TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3"))));
 
         IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump();
         reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3);
@@ -176,16 +217,19 @@ public class Ipv4AddressCustomizerTest {
         CompletableFuture<IpAddressDetailsReplyDump> future = new CompletableFuture<>();
         future.complete(reply);
 
-        when(jvpp.ipAddressDump(Mockito.any(IpAddressDump.class))).thenReturn(future);
-        when(context.getModificationCache()).thenReturn(cache);
-        List<Ipv4AddressNoZone> ids = new Ipv4AddressCustomizer(jvpp).getAllIds(null, context).stream()
-                .map(id -> id.getIp())
-                .collect(Collectors.toList());
+        when(api.ipAddressDump(Mockito.any(IpAddressDump.class))).thenReturn(future);
+        when(ctx.getModificationCache()).thenReturn(cache);
+
+        final InstanceIdentifier<Address> id = getId("192.168.2.1");
+
+        List<Ipv4AddressNoZone> ids = getCustomizer().getAllIds(id, ctx).stream()
+            .map(key -> key.getIp())
+            .collect(Collectors.toList());
 
         assertEquals(3, ids.size());
-        assertEquals(true, "1.2.168.192".equals(ids.get(0).getValue()));
-        assertEquals(true, "2.2.168.192".equals(ids.get(1).getValue()));
-        assertEquals(true, "3.2.168.192".equals(ids.get(2).getValue()));
+        assertEquals(true, "192.168.2.1".equals(ids.get(0).getValue()));
+        assertEquals(true, "192.168.2.2".equals(ids.get(1).getValue()));
+        assertEquals(true, "192.168.2.3".equals(ids.get(2).getValue()));
     }
 
     @Test
@@ -193,7 +237,7 @@ public class Ipv4AddressCustomizerTest {
 
         Address address = new AddressBuilder().build();
         Ipv4Builder ipv4Builder = new Ipv4Builder();
-        new Ipv4AddressCustomizer(mock(FutureJVpp.class)).merge(ipv4Builder, Arrays.asList(address));
+        getCustomizer().merge(ipv4Builder, Arrays.asList(address));
 
         assertEquals(1, ipv4Builder.getAddress().size());
         assertEquals(true, ipv4Builder.getAddress().contains(address));
index 77e6087..d44bf8f 100644 (file)
@@ -185,4 +185,19 @@ public final class TranslateUtils {
         }
         throw new IllegalArgumentException(String.format("0 or 1 was expected but was %d", value));
     }
+
+    /**
+     * Reverses bytes in the byte array
+     * @param bytes input array
+     * @return reversed array
+     */
+    public static byte[] reverseBytes(final byte[] bytes) {
+        final byte[] reversed = new byte[bytes.length];
+        int i = 1;
+        for (byte aByte : bytes) {
+            reversed[bytes.length - i++] = aByte;
+        }
+
+        return reversed;
+    }
 }
index ba3861b..89e7d9d 100644 (file)
@@ -1,5 +1,6 @@
 package io.fd.honeycomb.v3po.translate.v3po.util;
 
+import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.reverseBytes;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 
@@ -19,16 +20,6 @@ public class TranslateUtilsTest {
         assertEquals(ipv4Addr, ipv4AddressNoZone);
     }
 
-    private byte[] reverseBytes(final byte[] bytes) {
-        final byte[] reversed = new byte[bytes.length];
-        int i = 1;
-        for (byte aByte : bytes) {
-            reversed[bytes.length - i++] = aByte;
-        }
-
-        return reversed;
-    }
-
     @Test
     public void testToString() {
         final byte[] expected = "test".getBytes();