8f3c9ad8d1b9265ea3721807cc9945be3550eeb7
[honeycomb.git] / v3po / v3po2vpp / src / test / java / io / fd / honeycomb / translate / v3po / interfaces / ip / Ipv4AddressCustomizerTest.java
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package io.fd.honeycomb.translate.v3po.interfaces.ip;
18
19 import static org.junit.Assert.assertArrayEquals;
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23 import static org.mockito.Matchers.any;
24 import static org.mockito.Mockito.doReturn;
25 import static org.mockito.Mockito.verify;
26 import static org.mockito.MockitoAnnotations.initMocks;
27
28 import io.fd.honeycomb.translate.v3po.test.ContextTestUtils;
29 import io.fd.honeycomb.translate.write.WriteContext;
30 import io.fd.honeycomb.translate.MappingContext;
31 import io.fd.honeycomb.translate.v3po.test.TestHelperUtils;
32 import io.fd.honeycomb.translate.v3po.util.NamingContext;
33 import io.fd.honeycomb.translate.write.WriteFailedException;
34 import java.util.concurrent.CompletableFuture;
35 import org.junit.Before;
36 import org.junit.Test;
37 import org.mockito.ArgumentCaptor;
38 import org.mockito.Mock;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressBuilder;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.Netmask;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.NetmaskBuilder;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
53 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
54 import org.openvpp.jvpp.VppBaseCallException;
55 import org.openvpp.jvpp.VppInvocationException;
56 import org.openvpp.jvpp.dto.SwInterfaceAddDelAddress;
57 import org.openvpp.jvpp.dto.SwInterfaceAddDelAddressReply;
58 import org.openvpp.jvpp.future.FutureJVpp;
59
60 public class Ipv4AddressCustomizerTest {
61
62     private static final String IFC_CTX_NAME = "ifc-test-instance";
63     private static final String IFACE_NAME = "eth0";
64     private static final int IFACE_ID = 123;
65
66     @Mock
67     private WriteContext writeContext;
68     @Mock
69     private MappingContext mappingContext;
70     @Mock
71     private FutureJVpp api;
72
73     private NamingContext interfaceContext;
74     private Ipv4AddressCustomizer customizer;
75
76     @Before
77     public void setUp() throws Exception {
78         initMocks(this);
79         doReturn(mappingContext).when(writeContext).getMappingContext();
80         interfaceContext = new NamingContext("generatedlIfaceName", IFC_CTX_NAME);
81
82         customizer = new Ipv4AddressCustomizer(api, interfaceContext);
83     }
84
85     private static InstanceIdentifier<Address> getAddressId(final String ifaceName) {
86         return InstanceIdentifier.builder(Interfaces.class)
87             .child(Interface.class, new InterfaceKey(ifaceName))
88             .augmentation(Interface1.class)
89             .child(Ipv4.class)
90             .child(Address.class)
91             .build();
92     }
93
94     private void whenSwInterfaceAddDelAddressThenSuccess() {
95         final CompletableFuture<SwInterfaceAddDelAddressReply> replyFuture = new CompletableFuture<>();
96         final SwInterfaceAddDelAddressReply reply = new SwInterfaceAddDelAddressReply();
97         replyFuture.complete(reply);
98         doReturn(replyFuture).when(api).swInterfaceAddDelAddress(any(SwInterfaceAddDelAddress.class));
99     }
100
101     private void whenSwInterfaceAddDelAddressThenFailure() {
102         doReturn(TestHelperUtils.createFutureException()).when(api)
103             .swInterfaceAddDelAddress(any(SwInterfaceAddDelAddress.class));
104     }
105
106     private void verifySwInterfaceAddDelAddressWasInvoked(final SwInterfaceAddDelAddress expected) throws
107         VppInvocationException {
108         ArgumentCaptor<SwInterfaceAddDelAddress> argumentCaptor =
109             ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class);
110         verify(api).swInterfaceAddDelAddress(argumentCaptor.capture());
111         verifySwInterfaceAddDelAddressWasInvoked(expected, argumentCaptor.getValue());
112     }
113
114     private void verifySwInterfaceAddDelAddressWasInvoked(final SwInterfaceAddDelAddress expected,
115                                                           final SwInterfaceAddDelAddress actual) throws
116         VppInvocationException {
117         assertArrayEquals(expected.address, actual.address);
118         assertEquals(expected.addressLength, actual.addressLength);
119         assertEquals(expected.delAll, actual.delAll);
120         assertEquals(expected.isAdd, actual.isAdd);
121         assertEquals(expected.isIpv6, actual.isIpv6);
122         assertEquals(expected.swIfIndex, actual.swIfIndex);
123     }
124
125     @Test
126     public void testAddPrefixLengthIpv4Address() throws Exception {
127         final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME);
128
129         Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
130         PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build();
131         Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build();
132
133         ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME);
134         whenSwInterfaceAddDelAddressThenSuccess();
135
136         customizer.writeCurrentAttributes(id, data, writeContext);
137
138         verifySwInterfaceAddDelAddressWasInvoked(generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1},
139             (byte) 1, (byte) 24));
140     }
141
142     @Test
143     public void testAddPrefixLengthIpv4AddressFailed() throws Exception {
144         final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME);
145
146         Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
147         PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build();
148         Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build();
149
150         ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME);
151         whenSwInterfaceAddDelAddressThenFailure();
152
153         try {
154             customizer.writeCurrentAttributes(id, data, writeContext);
155         } catch (WriteFailedException e) {
156             assertTrue(e.getCause() instanceof VppBaseCallException);
157             verifySwInterfaceAddDelAddressWasInvoked(
158                 generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1},
159                     (byte) 1, (byte) 24));
160             return;
161         }
162         fail("WriteFailedException was expected");
163     }
164
165     private SwInterfaceAddDelAddress generateSwInterfaceAddDelAddressRequest(final byte[] address, final byte isAdd,
166                                                                              final byte prefixLength) {
167         final SwInterfaceAddDelAddress request = new SwInterfaceAddDelAddress();
168         request.swIfIndex = IFACE_ID;
169         request.isAdd = isAdd;
170         request.isIpv6 = 0;
171         request.delAll = 0;
172         request.addressLength = prefixLength;
173         request.address = address;
174         return request;
175     }
176
177     @Test
178     public void testDeletePrefixLengthIpv4Address() throws Exception {
179         final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME);
180
181         Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
182         PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build();
183         Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build();
184
185         ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME);
186         whenSwInterfaceAddDelAddressThenSuccess();
187
188         customizer.deleteCurrentAttributes(id, data, writeContext);
189
190         verifySwInterfaceAddDelAddressWasInvoked(generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1},
191             (byte) 0, (byte) 24));
192     }
193
194     @Test
195     public void testDeletePrefixLengthIpv4AddressFailed() throws Exception {
196         final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME);
197
198         Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
199         PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build();
200         Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build();
201
202         ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME);
203         whenSwInterfaceAddDelAddressThenFailure();
204
205         try {
206             customizer.deleteCurrentAttributes(id, data, writeContext);
207         } catch (WriteFailedException e) {
208             assertTrue(e.getCause() instanceof VppBaseCallException);
209             verifySwInterfaceAddDelAddressWasInvoked(
210                 generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1},
211                     (byte) 0, (byte) 24));
212             return;
213         }
214         fail("WriteFailedException was expec16ted");
215     }
216
217     private void testSingleNetmask(final int expectedPrefixLength, final String stringMask) throws Exception {
218         final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME);
219
220         Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
221         Netmask subnet = new NetmaskBuilder().setNetmask(new DottedQuad(stringMask)).build();
222         Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(subnet).build();
223
224         ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME);
225
226         final CompletableFuture<SwInterfaceAddDelAddressReply> replyFuture = new CompletableFuture<>();
227         replyFuture.complete(new SwInterfaceAddDelAddressReply());
228         ArgumentCaptor<SwInterfaceAddDelAddress> argumentCaptor =
229             ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class);
230         doReturn(replyFuture).when(api).swInterfaceAddDelAddress(argumentCaptor.capture());
231
232         customizer.writeCurrentAttributes(id, data, writeContext);
233
234         verifySwInterfaceAddDelAddressWasInvoked(generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1},
235             (byte) 1, (byte) expectedPrefixLength), argumentCaptor.getValue());
236     }
237
238     private void testSingleIllegalNetmask(final String stringMask) throws Exception {
239         try {
240             final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME);
241
242             Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"));
243             Netmask subnet = new NetmaskBuilder().setNetmask(new DottedQuad(stringMask)).build();
244             Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(subnet).build();
245
246             ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME);
247
248             final CompletableFuture<SwInterfaceAddDelAddressReply> replyFuture = new CompletableFuture<>();
249             replyFuture.complete(new SwInterfaceAddDelAddressReply());
250             ArgumentCaptor<SwInterfaceAddDelAddress> argumentCaptor =
251                 ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class);
252             doReturn(replyFuture).when(api).swInterfaceAddDelAddress(argumentCaptor.capture());
253
254             customizer.writeCurrentAttributes(id, data, writeContext);
255         } catch (IllegalArgumentException e) {
256             return;
257         }
258         fail("IllegalArgumentException expected");
259
260     }
261
262     /**
263      * Test contiguous netmask length from QuadDotted notation
264      */
265     @Test
266     public void testNetmaskLength() throws Exception {
267         testSingleNetmask(1, "128.0.0.0");
268         testSingleNetmask(2, "192.0.0.0");
269         testSingleNetmask(8, "255.0.0.0");
270         testSingleNetmask(9, "255.128.0.0");
271         testSingleNetmask(16, "255.255.0.0");
272         testSingleNetmask(24, "255.255.255.0");
273     }
274
275     @Test
276     public void testNetmaskIllegal() throws Exception {
277         testSingleIllegalNetmask("");
278         testSingleIllegalNetmask(".");
279         testSingleIllegalNetmask(".255");
280         testSingleIllegalNetmask("255");
281         testSingleIllegalNetmask("255.");
282         testSingleIllegalNetmask("255.255");
283         testSingleIllegalNetmask("255.255.0");
284         testSingleIllegalNetmask("255.255.255.");
285         testSingleIllegalNetmask("255.255.255.256");
286         testSingleIllegalNetmask("0.0.0.0");
287         testSingleIllegalNetmask("10.10.10.10");
288         testSingleIllegalNetmask("255.1.255.0");
289         testSingleIllegalNetmask("255.255.255.255");
290     }
291
292 }