HONEYCOMB-195: increase v3po coverage over 80%. WIP
authorMarek Gradzki <[email protected]>
Mon, 26 Sep 2016 06:28:20 +0000 (08:28 +0200)
committerMarek Gradzki <[email protected]>
Mon, 26 Sep 2016 06:28:40 +0000 (08:28 +0200)
Change-Id: Ibe14d7203bdaf53b925e4d16b598942b62b65bae
Signed-off-by: Marek Gradzki <[email protected]>
12 files changed:
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/InterfacesWriterFactory.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ProxyArpCustomizer.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceCustomizerTest.java [new file with mode: 0644]
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/L2CustomizerTest.java [new file with mode: 0644]
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/ProxyArpCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/RoutingCustomizerTest.java [new file with mode: 0644]
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizerTest.java [new file with mode: 0644]
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceL2CustomizerTest.java [new file with mode: 0644]
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizerTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizerTest.java [new file with mode: 0644]
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4CustomizerTest.java [new file with mode: 0644]

index 39e328a..baccf61 100644 (file)
@@ -176,7 +176,7 @@ public final class InterfacesWriterFactory implements WriterFactory {
                 SubinterfaceAugmentationWriterFactory.SUB_IFC_ID);
         // Proxy Arp (execute after specific interface customizers)
         registry.addAfter(
-                new GenericWriter<>(VPP_IFC_AUG_ID.child(ProxyArp.class), new ProxyArpCustomizer(jvpp, ifcNamingContext)),
+                new GenericWriter<>(VPP_IFC_AUG_ID.child(ProxyArp.class), new ProxyArpCustomizer(jvpp)),
                 specificIfcTypes);
         // ACL (execute after classify table and session writers)
         // also handles L2Acl, Ip4Acl and Ip6Acl:
index 002cc4c..229902c 100644 (file)
@@ -20,7 +20,6 @@ import com.google.common.net.InetAddresses;
 import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
 import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
 import io.fd.honeycomb.translate.v3po.util.JvppReplyConsumer;
-import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.write.WriteFailedException;
 import java.net.InetAddress;
@@ -37,15 +36,12 @@ import org.openvpp.jvpp.core.future.FutureJVppCore;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
 public class ProxyArpCustomizer extends FutureJVppCustomizer implements WriterCustomizer<ProxyArp>, JvppReplyConsumer {
 
     private static final Logger LOG = LoggerFactory.getLogger(ProxyArpCustomizer.class);
-    private final NamingContext interfaceContext;
 
-    public ProxyArpCustomizer(final FutureJVppCore vppApi, final NamingContext interfaceContext) {
+    public ProxyArpCustomizer(final FutureJVppCore vppApi) {
         super(vppApi);
-        this.interfaceContext = interfaceContext;
     }
 
     @Override
@@ -54,10 +50,10 @@ public class ProxyArpCustomizer extends FutureJVppCustomizer implements WriterCu
         final String swIfName = id.firstKeyOf(Interface.class).getName();
 
         try {
-            setProxyArp(id, swIfName, dataAfter, writeContext, (byte) 1 /* 1 is add */);
+            setProxyArp(id, swIfName, dataAfter, (byte) 1 /* 1 is add */);
         } catch (VppBaseCallException e) {
             LOG.error("Failed to set Proxy ARP settings: {}, for interface: {}", dataAfter, swIfName);
-            throw new WriteFailedException(id, dataAfter.toString(), e);
+            throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
         }
     }
 
@@ -75,16 +71,15 @@ public class ProxyArpCustomizer extends FutureJVppCustomizer implements WriterCu
 
         final String swIfName = id.firstKeyOf(Interface.class).getName();
         try {
-            setProxyArp(id, swIfName, dataBefore, writeContext, (byte) 0 /* 0 is delete */);
+            setProxyArp(id, swIfName, dataBefore, (byte) 0 /* 0 is delete */);
         } catch (VppBaseCallException e) {
             LOG.debug("Failed to delete Proxy ARP settings: {}, for interface: {}", dataBefore, swIfName);
             throw new WriteFailedException.DeleteFailedException(id, e);
         }
     }
 
-    private void setProxyArp(InstanceIdentifier<ProxyArp> id, String swIfName, ProxyArp proxyArp, WriteContext
-            writeContext, byte operation) throws VppBaseCallException, WriteFailedException {
-
+    private void setProxyArp(InstanceIdentifier<ProxyArp> id, String swIfName, ProxyArp proxyArp, byte operation)
+        throws VppBaseCallException, WriteFailedException {
         LOG.debug("Setting Proxy ARP settings for interface: {}", swIfName);
         final InetAddress srcAddress = InetAddresses.forString(getv4AddressString(proxyArp.getLowAddr()));
         final InetAddress dstAddress = InetAddresses.forString(getv4AddressString(proxyArp.getHighAddr()));
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceCustomizerTest.java
new file mode 100644 (file)
index 0000000..fc3dd83
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import io.fd.honeycomb.translate.v3po.util.ByteDataTranslator;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.vpp.test.write.WriterCustomizerTest;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.core.dto.SwInterfaceSetFlags;
+import org.openvpp.jvpp.core.dto.SwInterfaceSetFlagsReply;
+
+public class InterfaceCustomizerTest extends WriterCustomizerTest implements ByteDataTranslator {
+    private static final String IFACE_CTX_NAME = "interface-ctx";
+    private static final String IF_NAME = "eth1";
+    private static final int IF_INDEX = 1;
+
+    private InterfaceCustomizer customizer;
+    private InstanceIdentifier<Interface> IID =
+        InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(IF_NAME));
+
+    @Override
+    protected void setUp() throws Exception {
+        customizer = new InterfaceCustomizer(api, new NamingContext("ifacePrefix", IFACE_CTX_NAME));
+        defineMapping(mappingContext, IF_NAME, IF_INDEX, IFACE_CTX_NAME);
+    }
+
+    @Test
+    public void testWrite() throws WriteFailedException {
+        final boolean enabled = true;
+        when(api.swInterfaceSetFlags(any())).thenReturn(future(new SwInterfaceSetFlagsReply()));
+        customizer.writeCurrentAttributes(IID, iface(enabled), writeContext);
+        verify(api).swInterfaceSetFlags(expectedRequest(enabled));
+    }
+
+    @Test
+    public void testWriteFailed() {
+        final boolean enabled = false;
+        when(api.swInterfaceSetFlags(any())).thenReturn(failedFuture());
+        try {
+            customizer.writeCurrentAttributes(IID, iface(enabled), writeContext);
+        } catch (WriteFailedException e) {
+            assertTrue(e.getCause() instanceof VppBaseCallException);
+            verify(api).swInterfaceSetFlags(expectedRequest(enabled));
+            return;
+        }
+        fail("WriteFailedException expected");
+    }
+
+    @Test
+    public void testUpdate() throws WriteFailedException {
+        when(api.swInterfaceSetFlags(any())).thenReturn(future(new SwInterfaceSetFlagsReply()));
+        customizer.updateCurrentAttributes(IID, iface(false), iface(true), writeContext);
+        verify(api).swInterfaceSetFlags(expectedRequest(true));
+    }
+
+    @Test
+    public void testUpdateFailed() {
+        when(api.swInterfaceSetFlags(any())).thenReturn(failedFuture());
+        try {
+            customizer.updateCurrentAttributes(IID, iface(false), iface(true), writeContext);
+        } catch (WriteFailedException e) {
+            assertTrue(e.getCause() instanceof VppBaseCallException);
+            verify(api).swInterfaceSetFlags(expectedRequest(true));
+            return;
+        }
+        fail("WriteFailedException expected");
+    }
+
+    @Test
+    public void testDelete() throws WriteFailedException {
+        customizer.deleteCurrentAttributes(IID, mock(Interface.class), writeContext);
+        verifyZeroInteractions(api);
+    }
+
+    private Interface iface(final boolean enabled) {
+        return new InterfaceBuilder().setName(IF_NAME).setEnabled(enabled).build();
+    }
+
+    private SwInterfaceSetFlags expectedRequest(final boolean enabled) {
+        final SwInterfaceSetFlags request = new SwInterfaceSetFlags();
+        request.deleted = 0;
+        request.adminUpDown = booleanToByte(enabled);
+        request.linkUpDown = booleanToByte(enabled);
+        request.swIfIndex = IF_INDEX;
+        return request;
+    }
+}
\ No newline at end of file
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/L2CustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/L2CustomizerTest.java
new file mode 100644 (file)
index 0000000..7f9ba11
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import io.fd.honeycomb.translate.v3po.util.ByteDataTranslator;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.vpp.test.write.WriterCustomizerTest;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBased;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBasedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.XconnectBased;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.XconnectBasedBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.core.dto.SwInterfaceSetL2Bridge;
+import org.openvpp.jvpp.core.dto.SwInterfaceSetL2BridgeReply;
+import org.openvpp.jvpp.core.dto.SwInterfaceSetL2Xconnect;
+import org.openvpp.jvpp.core.dto.SwInterfaceSetL2XconnectReply;
+
+public class L2CustomizerTest extends WriterCustomizerTest implements ByteDataTranslator {
+    private static final String IFACE_CTX_NAME = "interface-ctx";
+    private static final String BD_CTX_NAME = "bd-ctx";
+    private static final String IF1_NAME = "eth1";
+    private static final int IF1_INDEX = 1;
+    private static final String IF2_NAME = "eth2";
+    private static final int IF2_INDEX = 2;
+    private static final InstanceIdentifier<L2> IID =
+        InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(IF1_NAME))
+            .augmentation(VppInterfaceAugmentation.class).child(L2.class);
+    private static final String BD_NAME = "test_bd";
+    private static final int BD_INDEX = 13;
+
+    private L2Customizer customizer;
+
+    @Override
+    protected void setUp() throws Exception {
+        customizer = new L2Customizer(api, new NamingContext("ifacePrefix", IFACE_CTX_NAME),
+            new NamingContext("bdPrefix", BD_CTX_NAME));
+        defineMapping(mappingContext, IF1_NAME, IF1_INDEX, IFACE_CTX_NAME);
+        defineMapping(mappingContext, IF2_NAME, IF2_INDEX, IFACE_CTX_NAME);
+        defineMapping(mappingContext, BD_NAME, BD_INDEX, BD_CTX_NAME);
+    }
+
+    @Test
+    public void testWrite() throws WriteFailedException {
+        when(api.swInterfaceSetL2Xconnect(any())).thenReturn(future(new SwInterfaceSetL2XconnectReply()));
+        customizer.writeCurrentAttributes(IID, l2(xconnectBased()), writeContext);
+        verify(api).swInterfaceSetL2Xconnect(xconnectRequest(true));
+    }
+
+    @Test
+    public void testWriteFailed() {
+        when(api.swInterfaceSetL2Bridge(any())).thenReturn(failedFuture());
+        try {
+            customizer.writeCurrentAttributes(IID, l2(bridgeBased(false)), writeContext);
+        } catch (WriteFailedException e) {
+            assertTrue(e.getCause() instanceof VppBaseCallException);
+            verify(api).swInterfaceSetL2Bridge(bridgeRequest(false, true));
+            return;
+        }
+        fail("WriteFailedException expected");
+    }
+
+    @Test
+    public void testUpdate() throws WriteFailedException {
+        when(api.swInterfaceSetL2Bridge(any())).thenReturn(future(new SwInterfaceSetL2BridgeReply()));
+        customizer.updateCurrentAttributes(IID, l2(bridgeBased(false)), l2(bridgeBased(true)), writeContext);
+        verify(api).swInterfaceSetL2Bridge(bridgeRequest(true, true));
+    }
+
+    @Test
+    public void testDelete() throws WriteFailedException {
+        when(api.swInterfaceSetL2Xconnect(any())).thenReturn(future(new SwInterfaceSetL2XconnectReply()));
+        customizer.deleteCurrentAttributes(IID, l2(xconnectBased()), writeContext);
+        verify(api).swInterfaceSetL2Xconnect(xconnectRequest(false));
+    }
+
+    @Test
+    public void testDeleteFailed() {
+        when(api.swInterfaceSetL2Bridge(any())).thenReturn(failedFuture());
+        try {
+            customizer.deleteCurrentAttributes(IID, l2(bridgeBased(true)), writeContext);
+        } catch (WriteFailedException e) {
+            assertTrue(e.getCause() instanceof VppBaseCallException);
+            verify(api).swInterfaceSetL2Bridge(bridgeRequest(true, false));
+            return;
+        }
+        fail("WriteFailedException expected");
+    }
+
+    private XconnectBased xconnectBased() {
+        return new XconnectBasedBuilder().setXconnectOutgoingInterface(IF2_NAME).build();
+    }
+
+    private SwInterfaceSetL2Xconnect xconnectRequest(final boolean enable) {
+        final SwInterfaceSetL2Xconnect request = new SwInterfaceSetL2Xconnect();
+        request.rxSwIfIndex = IF1_INDEX;
+        request.txSwIfIndex = IF2_INDEX;
+        request.enable = booleanToByte(enable);
+        return request;
+    }
+
+    private BridgeBased bridgeBased(final boolean bvi) {
+        return new BridgeBasedBuilder().setBridgedVirtualInterface(bvi)
+            .setBridgeDomain(BD_NAME).setSplitHorizonGroup((short) 123).build();
+    }
+
+    private SwInterfaceSetL2Bridge bridgeRequest(final boolean bvi, final boolean enable) {
+        final SwInterfaceSetL2Bridge request = new SwInterfaceSetL2Bridge();
+        request.bdId = BD_INDEX;
+        request.rxSwIfIndex = IF1_INDEX;
+        request.bvi = booleanToByte(bvi);
+        request.enable = booleanToByte(enable);
+        request.shg = 123;
+        return request;
+    }
+
+
+    private L2 l2(final Interconnection interconnection) {
+        return new L2Builder().setInterconnection(interconnection).build();
+    }
+}
\ No newline at end of file
index caac8a3..8156178 100644 (file)
 
 package io.fd.honeycomb.translate.v3po.interfaces;
 
-import static org.mockito.Mockito.mock;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
-import io.fd.honeycomb.vpp.test.write.WriterCustomizerTest;
-import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.ByteDataTranslator;
 import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.vpp.test.write.WriterCustomizerTest;
 import org.junit.Test;
+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;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.ProxyArp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.ProxyArpBuilder;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.core.dto.ProxyArpAddDel;
+import org.openvpp.jvpp.core.dto.ProxyArpAddDelReply;
 
-public class ProxyArpCustomizerTest extends WriterCustomizerTest {
+public class ProxyArpCustomizerTest extends WriterCustomizerTest implements ByteDataTranslator {
+    private static final String IF_NAME = "eth1";
 
     private ProxyArpCustomizer customizer;
 
     @Override
     public void setUp() throws Exception {
-        customizer = new ProxyArpCustomizer(api, new NamingContext("generatedSubInterfaceName", "test-instance"));
+        customizer = new ProxyArpCustomizer(api);
+    }
+
+    @Test
+    public void testWrite() throws WriteFailedException {
+        when(api.proxyArpAddDel(any())).thenReturn(future(new ProxyArpAddDelReply()));
+        customizer.writeCurrentAttributes(getProxyArpId(IF_NAME), proxyArp(), writeContext);
+        verify(api).proxyArpAddDel(expectedRequest(true));
+    }
+
+    @Test(expected = WriteFailedException.class)
+    public void testWriteFailed() throws WriteFailedException {
+        when(api.proxyArpAddDel(any())).thenReturn(failedFuture());
+        customizer.writeCurrentAttributes(getProxyArpId(IF_NAME), proxyArp(), writeContext);
     }
 
     @Test(expected = WriteFailedException.UpdateFailedException.class)
-    public void testUpdate() throws Exception {
-        final ProxyArp dataBefore = mock(ProxyArp.class);
-        final ProxyArp dataAfter = mock(ProxyArp.class);
-        customizer.updateCurrentAttributes(getProxyArpId("eth0"), dataBefore, dataAfter, writeContext);
+    public void testUpdate() throws WriteFailedException.UpdateFailedException {
+        customizer.updateCurrentAttributes(getProxyArpId(IF_NAME), proxyArp(), proxyArp(), writeContext);
+    }
+
+    @Test
+    public void testDelete() throws WriteFailedException {
+        when(api.proxyArpAddDel(any())).thenReturn(future(new ProxyArpAddDelReply()));
+        customizer.deleteCurrentAttributes(getProxyArpId(IF_NAME), proxyArp(), writeContext);
+        verify(api).proxyArpAddDel(expectedRequest(false));
+    }
+
+    @Test(expected = WriteFailedException.DeleteFailedException.class)
+    public void testDeleteFailed() throws WriteFailedException {
+        when(api.proxyArpAddDel(any())).thenReturn(failedFuture());
+        customizer.deleteCurrentAttributes(getProxyArpId(IF_NAME), proxyArp(), writeContext);
+    }
+
+    private ProxyArp proxyArp() {
+        return new ProxyArpBuilder().setVrfId(123L).setHighAddr(new Ipv4AddressNoZone("10.1.1.2"))
+            .setLowAddr(new Ipv4AddressNoZone("10.1.1.1")).build();
+    }
+
+    private ProxyArpAddDel expectedRequest(final boolean isAdd) {
+        final ProxyArpAddDel request = new ProxyArpAddDel();
+        request.isAdd = booleanToByte(isAdd);
+        request.vrfId = 123;
+        request.lowAddress = new byte[]{10,1,1,1};
+        request.hiAddress = new byte[]{10,1,1,2};
+        return request;
     }
 
     private InstanceIdentifier<ProxyArp> getProxyArpId(final String eth0) {
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/RoutingCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/RoutingCustomizerTest.java
new file mode 100644 (file)
index 0000000..d0db97f
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.vpp.test.write.WriterCustomizerTest;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Routing;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.RoutingBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.core.dto.SwInterfaceSetTable;
+import org.openvpp.jvpp.core.dto.SwInterfaceSetTableReply;
+
+public class RoutingCustomizerTest extends WriterCustomizerTest {
+    private static final String IFACE_CTX_NAME = "interface-ctx";
+    private static final String IF_NAME = "eth1";
+    private static final int IF_INDEX = 1;
+    private static final InstanceIdentifier<Routing> IID =
+        InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(IF_NAME))
+            .augmentation(VppInterfaceAugmentation.class).child(Routing.class);
+
+    private RoutingCustomizer customizer;
+
+    @Override
+    protected void setUp() throws Exception {
+        customizer = new RoutingCustomizer(api, new NamingContext("ifacePrefix", IFACE_CTX_NAME));
+        defineMapping(mappingContext, IF_NAME, IF_INDEX, IFACE_CTX_NAME);
+    }
+
+    @Test
+    public void testWrite() throws WriteFailedException {
+        final int vrfId = 123;
+        when(api.swInterfaceSetTable(any())).thenReturn(future(new SwInterfaceSetTableReply()));
+        customizer.writeCurrentAttributes(IID, routing(vrfId), writeContext);
+        verify(api).swInterfaceSetTable(expectedRequest(vrfId));
+    }
+
+    @Test(expected = WriteFailedException.CreateFailedException.class)
+    public void testWriteFailed() throws WriteFailedException {
+        when(api.swInterfaceSetTable(any())).thenReturn(failedFuture());
+        customizer.writeCurrentAttributes(IID, routing(213), writeContext);
+    }
+
+    @Test
+    public void testUpdate() throws WriteFailedException {
+        when(api.swInterfaceSetTable(any())).thenReturn(future(new SwInterfaceSetTableReply()));
+        customizer.updateCurrentAttributes(IID, routing(123L), null, writeContext);
+        verifyZeroInteractions(api);
+    }
+
+    @Test(expected = WriteFailedException.UpdateFailedException.class)
+    public void testUpdateFailed() throws WriteFailedException {
+        when(api.swInterfaceSetTable(any())).thenReturn(failedFuture());
+        customizer.updateCurrentAttributes(IID, routing(123L), routing(321L), writeContext);
+    }
+
+    @Test
+    public void testDelete() throws WriteFailedException {
+        customizer.deleteCurrentAttributes(IID, routing(123), writeContext);
+        verifyZeroInteractions(api);
+    }
+
+    private Routing routing(final long vrfId) {
+        return new RoutingBuilder().setVrfId(vrfId).build();
+    }
+
+    private SwInterfaceSetTable expectedRequest(final int vrfId) {
+        final SwInterfaceSetTable request = new SwInterfaceSetTable();
+        request.isIpv6 = 0;
+        request.swIfIndex = IF_INDEX;
+        request.vrfId = vrfId;
+        return request;
+    }
+}
\ No newline at end of file
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizerTest.java
new file mode 100644 (file)
index 0000000..779cdc6
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.vpp.test.write.WriterCustomizerTest;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6AclBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Acl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.AclBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.core.dto.InputAclSetInterface;
+import org.openvpp.jvpp.core.dto.InputAclSetInterfaceReply;
+
+public class SubInterfaceAclCustomizerTest extends WriterCustomizerTest {
+    private static final String IFC_TEST_INSTANCE = "ifc-test-instance";
+    private static final String IF_NAME = "local0";
+    private static final int IF_INDEX = 1;
+    private static final String SUBIF_NAME = "local0.0";
+    private static final int SUBIF_INDEX = 11;
+    private static final long SUBIF_ID = 0;
+    private static final String TABLE_NAME = "table0";
+    private static final int TABLE_INDEX = 123;
+
+    private static final InstanceIdentifier<Acl> IID =
+        InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(IF_NAME)).augmentation(
+            SubinterfaceAugmentation.class).child(SubInterfaces.class)
+            .child(SubInterface.class, new SubInterfaceKey(SUBIF_ID)).child(Acl.class);
+
+    @Mock
+    private VppClassifierContextManager classifyTableContext;
+
+    private SubInterfaceAclCustomizer customizer;
+
+    @Override
+    protected void setUp() throws Exception {
+        customizer = new SubInterfaceAclCustomizer(api, new NamingContext("prefix", IFC_TEST_INSTANCE),
+            classifyTableContext);
+        defineMapping(mappingContext, IF_NAME, IF_INDEX, IFC_TEST_INSTANCE);
+        defineMapping(mappingContext, SUBIF_NAME, SUBIF_INDEX, IFC_TEST_INSTANCE);
+        when(classifyTableContext.getTableIndex(TABLE_NAME, mappingContext)).thenReturn(TABLE_INDEX);
+    }
+
+    @Test
+    public void testCreate() throws WriteFailedException {
+        when(api.inputAclSetInterface(any())).thenReturn(future(new InputAclSetInterfaceReply()));
+        customizer.writeCurrentAttributes(IID, ip4Acl(), writeContext);
+        verify(api).inputAclSetInterface(expectedIp4AclRequest());
+    }
+
+    @Test(expected = WriteFailedException.CreateFailedException.class)
+    public void testCreateFailed() throws WriteFailedException {
+        when(api.inputAclSetInterface(any())).thenReturn(failedFuture());
+        customizer.writeCurrentAttributes(IID, ip4Acl(), writeContext);
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testUpdate() throws WriteFailedException {
+        customizer.updateCurrentAttributes(IID, ip4Acl(), ip6Acl(), writeContext);
+    }
+
+    @Test
+    public void testDelete() throws Exception {
+        when(api.inputAclSetInterface(any())).thenReturn(future(new InputAclSetInterfaceReply()));
+        customizer.deleteCurrentAttributes(IID, ip6Acl(), writeContext);
+        verify(api).inputAclSetInterface(expectedIp6AclRequest());
+    }
+
+    @Test(expected = WriteFailedException.DeleteFailedException.class)
+    public void testDeleteFailed() throws WriteFailedException {
+        when(api.inputAclSetInterface(any())).thenReturn(failedFuture());
+        customizer.deleteCurrentAttributes(IID, ip4Acl(), writeContext);
+    }
+
+    private Acl ip4Acl() {
+        final AclBuilder builder = new AclBuilder();
+        final Ip4Acl acl = new Ip4AclBuilder().setClassifyTable(TABLE_NAME).build();
+        builder.setIp4Acl(acl);
+        return builder.build();
+    }
+
+    private InputAclSetInterface expectedIp4AclRequest() {
+        final InputAclSetInterface request = new InputAclSetInterface();
+        request.isAdd = 1;
+        request.l2TableIndex = -1;
+        request.ip4TableIndex = TABLE_INDEX;
+        request.ip6TableIndex = -1;
+        request.swIfIndex = SUBIF_INDEX;
+        return request;
+    }
+
+    private Acl ip6Acl() {
+        final AclBuilder builder = new AclBuilder();
+        final Ip6Acl acl = new Ip6AclBuilder().setClassifyTable(TABLE_NAME).build();
+        builder.setIp6Acl(acl);
+        return builder.build();
+    }
+
+    private InputAclSetInterface expectedIp6AclRequest() {
+        final InputAclSetInterface request = new InputAclSetInterface();
+        request.isAdd = 0;
+        request.l2TableIndex = -1;
+        request.ip4TableIndex = -1;
+        request.ip6TableIndex = TABLE_INDEX;
+        request.swIfIndex = SUBIF_INDEX;
+        return request;
+    }
+}
\ No newline at end of file
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceL2CustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceL2CustomizerTest.java
new file mode 100644 (file)
index 0000000..0fa380e
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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.translate.v3po.interfaces;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import io.fd.honeycomb.translate.v3po.util.ByteDataTranslator;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.vpp.test.write.WriterCustomizerTest;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBasedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2Builder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.core.dto.SwInterfaceSetL2Bridge;
+import org.openvpp.jvpp.core.dto.SwInterfaceSetL2BridgeReply;
+
+public class SubInterfaceL2CustomizerTest extends WriterCustomizerTest implements ByteDataTranslator {
+    private static final String IFACE_CTX_NAME = "interface-ctx";
+    private static final String IF_NAME = "local0";
+    private static final int IF_INDEX = 1;
+    private static final String SUBIF_NAME = "local0.0";
+    private static final int SUBIF_INDEX = 11;
+    private static final long SUBIF_ID = 0;
+
+    private static final InstanceIdentifier<L2> IID =
+        InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(IF_NAME)).augmentation(
+            SubinterfaceAugmentation.class).child(SubInterfaces.class)
+            .child(SubInterface.class, new SubInterfaceKey(SUBIF_ID)).child(L2.class);
+
+
+    private static final String BD_CTX_NAME = "bd-ctx";
+    private static final String BD_NAME = "test_bd";
+    private static final int BD_INDEX = 13;
+
+    private SubInterfaceL2Customizer customizer;
+
+    @Override
+    protected void setUp() throws Exception {
+        customizer = new SubInterfaceL2Customizer(api, new NamingContext("ifacePrefix", IFACE_CTX_NAME),
+            new NamingContext("bdPrefix", BD_CTX_NAME));
+        defineMapping(mappingContext, IF_NAME, IF_INDEX, IFACE_CTX_NAME);
+        defineMapping(mappingContext, SUBIF_NAME, SUBIF_INDEX, IFACE_CTX_NAME);
+        defineMapping(mappingContext, BD_NAME, BD_INDEX, BD_CTX_NAME);
+    }
+
+    @Test
+    public void testWrite() throws WriteFailedException {
+        final boolean bvi = true;
+        when(api.swInterfaceSetL2Bridge(any())).thenReturn(future(new SwInterfaceSetL2BridgeReply()));
+        customizer.writeCurrentAttributes(IID, l2(bvi), writeContext);
+        verify(api).swInterfaceSetL2Bridge(bridgeRequest(bvi, true));
+    }
+
+    @Test
+    public void testUpdate() throws WriteFailedException {
+        final boolean bvi = false;
+        when(api.swInterfaceSetL2Bridge(any())).thenReturn(future(new SwInterfaceSetL2BridgeReply()));
+        customizer.updateCurrentAttributes(IID, l2(true), l2(bvi), writeContext);
+        verify(api).swInterfaceSetL2Bridge(bridgeRequest(bvi, true));
+    }
+
+    @Test
+    public void testDelete() throws WriteFailedException {
+        final boolean bvi = true;
+        when(api.swInterfaceSetL2Bridge(any())).thenReturn(future(new SwInterfaceSetL2BridgeReply()));
+        customizer.deleteCurrentAttributes(IID, l2(bvi), writeContext);
+        verify(api).swInterfaceSetL2Bridge(bridgeRequest(bvi, false));
+    }
+
+    private L2 l2(final boolean bvi) {
+        return new L2Builder().setInterconnection(new BridgeBasedBuilder().setBridgedVirtualInterface(bvi)
+            .setBridgeDomain(BD_NAME).setSplitHorizonGroup((short) 123).build()).build();
+    }
+
+    private SwInterfaceSetL2Bridge bridgeRequest(final boolean bvi, final boolean enable) {
+        final SwInterfaceSetL2Bridge request = new SwInterfaceSetL2Bridge();
+        request.bdId = BD_INDEX;
+        request.rxSwIfIndex = SUBIF_INDEX;
+        request.bvi = booleanToByte(bvi);
+        request.enable = booleanToByte(enable);
+        request.shg = 123;
+        return request;
+    }
+}
\ No newline at end of file
index 56430cd..e3857b9 100644 (file)
@@ -23,6 +23,7 @@ import static org.mockito.Matchers.argThat;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -189,6 +190,12 @@ public class Ipv4AddressCustomizerTest extends WriterCustomizerTest {
         };
     }
 
+    @Test(expected =  WriteFailedException.UpdateFailedException.class)
+    public void testUpdate() throws Exception {
+        final Address data = mock(Address.class);
+        customizer.updateCurrentAttributes(getAddressId(IFACE_NAME), data, data, writeContext);
+    }
+
     private SwInterfaceAddDelAddress generateSwInterfaceAddDelAddressRequest(final byte[] address, final byte isAdd,
                                                                              final byte prefixLength) {
         final SwInterfaceAddDelAddress request = new SwInterfaceAddDelAddress();
@@ -241,6 +248,32 @@ public class Ipv4AddressCustomizerTest extends WriterCustomizerTest {
         fail("WriteFailedException was expec16ted");
     }
 
+    @Test
+    public void testNetmaskFailed() {
+        final int expectedPrefixLength = 1;
+        final String stringMask = "128.0.0.0";
+        final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME);
+        when(writeContext.readBefore(id)).thenReturn(Optional.absent());
+
+        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();
+
+        defineMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME);
+        whenSwInterfaceAddDelAddressThenFailure();
+
+        try {
+            customizer.writeCurrentAttributes(id, data, writeContext);
+        } catch (WriteFailedException e) {
+            assertTrue(e.getCause() instanceof VppBaseCallException);
+            verify(api).swInterfaceAddDelAddress(generateSwInterfaceAddDelAddressRequest(new byte[]{-64, -88, 2, 1},
+                (byte) 1, (byte) expectedPrefixLength));
+            return;
+        }
+        fail("WriteFailedException was expec16ted");
+
+    }
+
     private void testSingleNetmask(final int expectedPrefixLength, final String stringMask) throws Exception {
         final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME);
         when(writeContext.readBefore(id)).thenReturn(Optional.absent());
@@ -255,7 +288,7 @@ public class Ipv4AddressCustomizerTest extends WriterCustomizerTest {
         customizer.writeCurrentAttributes(id, data, writeContext);
 
         verify(api).swInterfaceAddDelAddress(generateSwInterfaceAddDelAddressRequest(new byte[]{-64, -88, 2, 1},
-                (byte) 1, (byte) expectedPrefixLength));
+            (byte) 1, (byte) expectedPrefixLength));
     }
 
     private void testSingleIllegalNetmask(final String stringMask) throws Exception {
index e9acdbe..a3fff08 100644 (file)
 
 package io.fd.honeycomb.translate.v3po.interfaces.ip;
 
-import static org.junit.Assert.assertEquals;
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-
-import com.google.common.io.BaseEncoding;
 import io.fd.honeycomb.translate.v3po.util.Ipv4Translator;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.write.WriteFailedException;
 import io.fd.honeycomb.vpp.test.write.WriterCustomizerTest;
-import org.junit.Before;
 import org.junit.Test;
-import org.mockito.ArgumentCaptor;
 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;
@@ -41,6 +37,7 @@ 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.NeighborBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
 import org.openvpp.jvpp.core.dto.IpNeighborAddDel;
 import org.openvpp.jvpp.core.dto.IpNeighborAddDelReply;
 
@@ -49,70 +46,75 @@ public class Ipv4NeighbourCustomizerTest extends WriterCustomizerTest implements
     private static final String IFC_CTX_NAME = "ifc-test-instance";
     private static final String IFACE_NAME = "parent";
     private static final int IFACE_ID = 5;
+    private static final InstanceIdentifier<Neighbor> IID =
+        InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(IFACE_NAME))
+            .augmentation(Interface1.class).child(Ipv4.class).child(Neighbor.class);
 
-    private ArgumentCaptor<IpNeighborAddDel> requestCaptor;
     private Ipv4NeighbourCustomizer customizer;
 
-    @Before
-    public void init() {
+    @Override
+    public void setUp() {
         defineMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME);
         customizer = new Ipv4NeighbourCustomizer(api, new NamingContext("prefix", IFC_CTX_NAME));
-
-        requestCaptor = ArgumentCaptor.forClass(IpNeighborAddDel.class);
-        when(api.ipNeighborAddDel(any())).thenReturn(future(new IpNeighborAddDelReply()));
     }
 
     @Test
     public void testWriteCurrentAttributes() throws WriteFailedException {
+        when(api.ipNeighborAddDel(any())).thenReturn(future(new IpNeighborAddDelReply()));
+        customizer.writeCurrentAttributes(IID, getData(), writeContext);
+        verify(api).ipNeighborAddDel(getExpectedRequest(true));
+    }
 
-        InterfaceKey intfKey = new InterfaceKey(IFACE_NAME);
-
-        InstanceIdentifier<Neighbor> id = InstanceIdentifier.builder(Interfaces.class).child(Interface.class, intfKey)
-                .augmentation(Interface1.class).child(Ipv4.class).child(Neighbor.class).build();
-
-        Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
-        PhysAddress mac = new PhysAddress("aa:bb:cc:ee:11:22");
-
-        Neighbor data = new NeighborBuilder().setIp(noZoneIp).setLinkLayerAddress(mac).build();
-
-        customizer.writeCurrentAttributes(id, data, writeContext);
-
-        verify(api, times(1)).ipNeighborAddDel(requestCaptor.capture());
-
-        IpNeighborAddDel request = requestCaptor.getValue();
-
-        assertEquals(0, request.isIpv6);
-        assertEquals(1, request.isAdd);
-        assertEquals(1, request.isStatic);
-        assertEquals("1.2.168.192", arrayToIpv4AddressNoZone(request.dstAddress).getValue());
-        assertEquals("aabbccee1122", BaseEncoding.base16().lowerCase().encode(request.macAddress));
-        assertEquals(5, request.swIfIndex);
+    @Test
+    public void testWriteCurrentAttributesFailed() {
+        when(api.ipNeighborAddDel(any())).thenReturn(failedFuture());
+        try {
+            customizer.writeCurrentAttributes(IID, getData(), writeContext);
+        } catch (WriteFailedException e) {
+            assertTrue(e.getCause() instanceof VppBaseCallException);
+            verify(api).ipNeighborAddDel(getExpectedRequest(true));
+            return;
+        }
+        fail("WriteFailedException expected");
+    }
+    @Test(expected = UnsupportedOperationException.class)
+    public void testUpdateCurrentAttributes() throws WriteFailedException {
+        customizer.updateCurrentAttributes(IID, getData(), getData(), writeContext);
     }
 
     @Test
     public void testDeleteCurrentAttributes() throws WriteFailedException {
-        InterfaceKey intfKey = new InterfaceKey(IFACE_NAME);
-
-        InstanceIdentifier<Neighbor> id = InstanceIdentifier.builder(Interfaces.class).child(Interface.class, intfKey)
-                .augmentation(Interface1.class).child(Ipv4.class).child(Neighbor.class).build();
-
-        Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
-        PhysAddress mac = new PhysAddress("aa:bb:cc:ee:11:22");
-
-        Neighbor data = new NeighborBuilder().setIp(noZoneIp).setLinkLayerAddress(mac).build();
-
-        customizer.deleteCurrentAttributes(id, data, writeContext);
-
-        verify(api, times(1)).ipNeighborAddDel(requestCaptor.capture());
-
-        IpNeighborAddDel request = requestCaptor.getValue();
+        when(api.ipNeighborAddDel(any())).thenReturn(future(new IpNeighborAddDelReply()));
+        customizer.deleteCurrentAttributes(IID, getData(), writeContext);
+        verify(api).ipNeighborAddDel(getExpectedRequest(false));
+    }
 
-        assertEquals(0, request.isIpv6);
-        assertEquals(0, request.isAdd);
-        assertEquals(1, request.isStatic);
-        assertEquals("1.2.168.192", arrayToIpv4AddressNoZone(request.dstAddress).getValue());
-        assertEquals("aabbccee1122", BaseEncoding.base16().lowerCase().encode(request.macAddress));
-        assertEquals(5, request.swIfIndex);
+    @Test
+    public void testDeleteCurrentAttributesFailed() {
+        when(api.ipNeighborAddDel(any())).thenReturn(failedFuture());
+        try {
+            customizer.deleteCurrentAttributes(IID, getData(), writeContext);
+        } catch (WriteFailedException e) {
+            assertTrue(e.getCause() instanceof VppBaseCallException);
+            verify(api).ipNeighborAddDel(getExpectedRequest(false));
+            return;
+        }
+        fail("WriteFailedException expected");
     }
 
+    private Neighbor getData() {
+        final Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
+        final PhysAddress mac = new PhysAddress("aa:bb:cc:ee:11:22");
+        return new NeighborBuilder().setIp(noZoneIp).setLinkLayerAddress(mac).build();
+    }
+    private IpNeighborAddDel getExpectedRequest(final boolean isAdd) {
+        final IpNeighborAddDel request = new IpNeighborAddDel();
+        request.isIpv6 = 0;
+        request.isAdd = booleanToByte(isAdd);
+        request.isStatic = 1;
+        request.dstAddress = new byte[] {(byte) 192, (byte) 168, 2, 1};
+        request.macAddress = new byte[] {(byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xee, 0x11, 0x22};
+        request.swIfIndex = IFACE_ID;
+        return request;
+    }
 }
\ No newline at end of file
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizerTest.java
new file mode 100644 (file)
index 0000000..b5cb009
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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.translate.v3po.interfaces.ip;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import io.fd.honeycomb.translate.v3po.util.ByteDataTranslator;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.vpp.test.write.WriterCustomizerTest;
+import org.junit.Test;
+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;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.Netmask;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.NetmaskBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.PrefixLength;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.PrefixLengthBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.core.dto.SwInterfaceAddDelAddress;
+import org.openvpp.jvpp.core.dto.SwInterfaceAddDelAddressReply;
+
+public class SubInterfaceIpv4AddressCustomizerTest extends WriterCustomizerTest implements ByteDataTranslator {
+
+    private static final String IFC_CTX_NAME = "ifc-test-instance";
+    private static final String IFACE_NAME = "eth0";
+    private static final int IFACE_INDEX = 0;
+    private static final String SUBIF_NAME = "eth0.1";
+    private static final long SUBIF_ID = 1;
+    private static final int SUBIF_INDEX = 123;
+    private static final InstanceIdentifier<Address> IID =
+        InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(IFACE_NAME))
+            .augmentation(SubinterfaceAugmentation.class).child(SubInterfaces.class)
+            .child(SubInterface.class, new SubInterfaceKey(SUBIF_ID)).child(Ipv4.class).child(Address.class);
+
+    private SubInterfaceIpv4AddressCustomizer customizer;
+
+    @Override
+    protected void setUp() {
+        customizer = new SubInterfaceIpv4AddressCustomizer(api, new NamingContext("prefix", IFC_CTX_NAME));
+        defineMapping(mappingContext, IFACE_NAME, IFACE_INDEX, IFC_CTX_NAME);
+        defineMapping(mappingContext, SUBIF_NAME, SUBIF_INDEX, IFC_CTX_NAME);
+    }
+
+    @Test
+    public void testWrite() throws WriteFailedException {
+        when(api.swInterfaceAddDelAddress(any())).thenReturn(future(new SwInterfaceAddDelAddressReply()));
+        customizer.writeCurrentAttributes(IID, address(prefixLength()), writeContext);
+        verify(api).swInterfaceAddDelAddress(expectedRequest(true));
+    }
+
+    @Test
+    public void testWriteFailed() {
+        when(api.swInterfaceAddDelAddress(any())).thenReturn(failedFuture());
+        try {
+            customizer.writeCurrentAttributes(IID, address(prefixLength()), writeContext);
+        } catch (WriteFailedException e) {
+            assertTrue(e.getCause() instanceof VppBaseCallException);
+            verify(api).swInterfaceAddDelAddress(expectedRequest(true));
+            return;
+        }
+        fail("WriteFailedException expected");
+    }
+
+    @Test
+    public void testDelete() throws WriteFailedException {
+        when(api.swInterfaceAddDelAddress(any())).thenReturn(future(new SwInterfaceAddDelAddressReply()));
+        customizer.deleteCurrentAttributes(IID, address(netmask()), writeContext);
+        verify(api).swInterfaceAddDelAddress(expectedRequest(false));
+    }
+
+    @Test
+    public void testDeleteFailed() {
+        when(api.swInterfaceAddDelAddress(any())).thenReturn(failedFuture());
+        try {
+            customizer.deleteCurrentAttributes(IID, address(netmask()), writeContext);
+        } catch (WriteFailedException e) {
+            assertTrue(e.getCause() instanceof VppBaseCallException);
+            verify(api).swInterfaceAddDelAddress(expectedRequest(false));
+            return;
+        }
+        fail("WriteFailedException expected");
+    }
+
+    private SwInterfaceAddDelAddress expectedRequest(boolean isAdd) {
+        final SwInterfaceAddDelAddress request = new SwInterfaceAddDelAddress();
+        request.isAdd = booleanToByte(isAdd);
+        request.swIfIndex = SUBIF_INDEX;
+        request.isIpv6 = 0;
+        request.delAll = 0;
+        request.addressLength = 24;
+        request.address = new byte[] {(byte) 192, (byte) 168, 2, 1};
+        return request;
+    }
+
+    @Test(expected = WriteFailedException.UpdateFailedException.class)
+    public void testUpdate() throws Exception {
+        final Address address = address(prefixLength());
+        customizer.updateCurrentAttributes(IID, address, address, writeContext);
+    }
+
+    private Address address(final Subnet subnet) {
+        final Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
+        return new AddressBuilder().setIp(noZoneIp).setSubnet(subnet).build();
+    }
+
+    private PrefixLength prefixLength() {
+        return new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build();
+    }
+
+    private Netmask netmask() {
+        return new NetmaskBuilder().setNetmask(new DottedQuad("255.255.255.0")).build();
+    }
+}
\ No newline at end of file
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4CustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4CustomizerTest.java
new file mode 100644 (file)
index 0000000..f536a37
--- /dev/null
@@ -0,0 +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.translate.v3po.interfacesstate.ip;
+
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.vpp.test.read.ReaderCustomizerTest;
+import org.junit.Test;
+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;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder;
+
+public class Ipv4CustomizerTest extends ReaderCustomizerTest<Ipv4, Ipv4Builder> {
+
+    public Ipv4CustomizerTest() {
+        super(Ipv4.class, Interface2Builder.class);
+    }
+
+    @Test
+    public void testReadCurrentAttributes() throws Exception {
+        customizer.readCurrentAttributes(null, null, ctx);
+        verifyZeroInteractions(api);
+    }
+
+    @Override
+    protected ReaderCustomizer<Ipv4, Ipv4Builder> initCustomizer() {
+        return new Ipv4Customizer(api);
+    }
+}
\ No newline at end of file