BUG-5404 Dangling Distributed ARP flows for DHCP
[ovsdb.git] / openstack / net-virt / src / test / java / org / opendaylight / ovsdb / openstack / netvirt / impl / DistributedArpServiceTest.java
1 /*
2  * Copyright (c) 2016 NEC Corporation and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.ovsdb.openstack.netvirt.impl;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.mockito.Matchers.any;
13 import static org.mockito.Matchers.anyLong;
14 import static org.mockito.Matchers.anyString;
15 import static org.mockito.Matchers.eq;
16 import static org.mockito.Mockito.mock;
17 import static org.mockito.Mockito.times;
18 import static org.mockito.Mockito.when;
19
20 import java.lang.reflect.Field;
21 import java.net.InetAddress;
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import org.junit.Before;
26 import org.junit.Test;
27 import org.junit.runner.RunWith;
28 import org.mockito.Mock;
29 import org.mockito.Mockito;
30 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
31 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
32 import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
33 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
34 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
35 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
36 import org.opendaylight.ovsdb.openstack.netvirt.api.ArpProvider;
37 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
38 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
39 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
40 import org.opendaylight.ovsdb.openstack.netvirt.api.Status;
41 import org.opendaylight.ovsdb.openstack.netvirt.api.StatusCode;
42 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
43 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
47 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
48
49 import org.osgi.framework.ServiceReference;
50 import org.powermock.api.mockito.PowerMockito;
51 import org.powermock.api.support.membermodification.MemberMatcher;
52 import org.powermock.api.support.membermodification.MemberModifier;
53 import org.powermock.core.classloader.annotations.PrepareForTest;
54 import org.powermock.modules.junit4.PowerMockRunner;
55 import org.powermock.reflect.Whitebox;
56
57 /**
58  * Unit test for {@link DistributedArpService}
59  */
60 @PrepareForTest({ServiceHelper.class, InetAddress.class, DistributedArpService.class})
61 @RunWith(PowerMockRunner.class)
62 public class DistributedArpServiceTest {
63
64     @Mock private DistributedArpService distributedArpService;
65     /**
66      * ID used for testing different scenarios.
67      */
68     private static final String ID = "45";
69     /**
70      * IP used for testing different scenarios.
71      */
72     private static final String IP = "127.0.0.1";
73     /**
74      * MALFORM_IP used for testing different scenarios.
75      */
76     private static final String MALFORM_IP = "127.0.0.1.5";
77     /**
78      * INTF_NAME used for testing different scenarios.
79      */
80     private static final String INTF_NAME = "br-int";
81     /**
82      * UUID used for testing different scenarios.
83      */
84     private static final String UUID = "7da709ff-397f-4778-a0e8-994811272fdb";
85     /**
86      * FIXED_IP_ADDRESS used for testing different scenarios.
87      */
88     private static final String FIXED_IP_ADDRESS = "192.168.1.0";
89     /**
90      * MAC_ADDRESS used for testing different scenarios.
91      */
92     private static final String MAC_ADDRESS = "00:00:5E:00:02:01";
93     /**
94      * MAC_ADDRESS_2 used for testing different scenarios.
95      */
96     private static final String MAC_ADDRESS_2 = "00:00:5E:00:02:02";
97     /**
98      * PORT_INT used for testing different scenarios.
99      */
100     private static final String PORT_INT = "port_int";
101
102     @Before
103     public void setUp() throws Exception{
104         distributedArpService = PowerMockito.spy(new DistributedArpService());
105     }
106
107     /**
108      * Test that checks if @{DistributedArpService#handlePortEvent} is called
109      * and then checks that the port event process to write arp rules for neutron ports based on action.
110      */
111     @Test
112     public void testHandlePortEvent() throws Exception {
113         NeutronPort neutronPortOne = PowerMockito.mock(NeutronPort.class);
114         NeutronPort neutronPortTwo = PowerMockito.mock(NeutronPort.class);
115         List<NeutronPort> list_neutronPort = new ArrayList<>();
116         list_neutronPort.add(neutronPortOne);
117         list_neutronPort.add(neutronPortTwo);
118         INeutronPortCRUD neutronPortCache = PowerMockito.mock(INeutronPortCRUD.class);
119         MemberModifier.field(DistributedArpService.class, "neutronPortCache").set(distributedArpService, neutronPortCache);
120         PowerMockito.when(neutronPortCache, "getAllPorts").thenReturn(list_neutronPort);
121
122         // Suppress the called to these functions.
123         MemberModifier.suppress(MemberMatcher.method(DistributedArpService.class, "handleNeutronPortForArp", NeutronPort.class, Action.class));
124
125         //Case 1: Delete Action.
126         Whitebox.invokeMethod(distributedArpService, "handlePortEvent", neutronPortOne, Action.DELETE);
127         PowerMockito.verifyPrivate(distributedArpService, times(1)).invoke("handleNeutronPortForArp", any(NeutronPort.class), eq(Action.DELETE));
128
129         //Case 2: Add Action.
130         Whitebox.invokeMethod(distributedArpService, "handlePortEvent", neutronPortOne, Action.ADD);
131         PowerMockito.verifyPrivate(distributedArpService, times(2)).invoke("handleNeutronPortForArp", any(NeutronPort.class), eq(Action.ADD));
132     }
133
134     /**
135      * Test that checks if @{DistributedArpService#programStaticRuleStage1} is called
136      * and then checks that the arp rules are added/removed based on neutron port event.
137      */
138     @Test
139     public void testProgramStaticRuleStage1() throws Exception {
140         MemberModifier.suppress(MemberMatcher.method(DistributedArpService.class, "programStaticRuleStage2", Long.class, String.class, String.class, String.class, Action.class));
141         PowerMockito.when(distributedArpService, "programStaticRuleStage2", anyLong(), anyString(), anyString(), anyString(), any(Action.class)).thenReturn(new Status(StatusCode.SUCCESS));
142
143         //Case 1: Add Action.
144         Whitebox.invokeMethod(distributedArpService, "programStaticRuleStage1", Long.valueOf(12), PORT_INT, MAC_ADDRESS, IP, Action.ADD);
145         PowerMockito.verifyPrivate(distributedArpService, times(1)).invoke("programStaticRuleStage2", anyLong(), anyString(), anyString(), anyString(), eq(Action.ADD));
146
147         //Case 2: Delete Action.
148         Whitebox.invokeMethod(distributedArpService, "programStaticRuleStage1", Long.valueOf(12), PORT_INT, MAC_ADDRESS, IP, Action.DELETE);
149         PowerMockito.verifyPrivate(distributedArpService, times(1)).invoke("programStaticRuleStage2", anyLong(), anyString(), anyString(), anyString(), eq(Action.DELETE));
150     }
151
152     /**
153      * Test that checks if @{DistributedArpService#programStaticRuleStage2} is called
154      * and then checks that the arp rules are programmed by invoke arpProvider.
155      */
156     @Test
157     public void testProgramStaticRuleStage2() throws Exception {
158         //Case 1: StatusCode BADREQUEST.
159         assertEquals("Error, this not return the correct status code", new Status(StatusCode.BADREQUEST), Whitebox.invokeMethod(distributedArpService, "programStaticRuleStage2", Long.valueOf(45), PORT_INT, MAC_ADDRESS, MALFORM_IP, Action.ADD));
160         PowerMockito.mockStatic(InetAddress.class);
161         InetAddress inetAddress = mock(InetAddress.class);
162         PowerMockito.when(InetAddress.getByName(anyString())).thenReturn(inetAddress);
163
164         //Case 2: StatusCode SUCCESS.
165         assertEquals("Error, this not return the correct status code", new Status(StatusCode.SUCCESS), Whitebox.invokeMethod(distributedArpService, "programStaticRuleStage2", Long.valueOf(45), PORT_INT, MAC_ADDRESS, IP, Action.DELETE));
166     }
167
168     /**
169      * Test that checks if @{DistributedArpService#handleNeutornPortForArp} is called
170      * and then checks that the arp rules are written based on event for neutron port.
171      */
172     @Test
173     public void testHandleNeutornPortForArp() throws Exception {
174         Neutron_IPs neutronIp = mock(Neutron_IPs.class);
175         when(neutronIp.getIpAddress()).thenReturn(FIXED_IP_ADDRESS);
176         List<Neutron_IPs> neutronIps = new ArrayList<>();
177         neutronIps.add(neutronIp);
178         NeutronPort neutronPort = mock(NeutronPort.class);
179         when(neutronPort.getNetworkUUID()).thenReturn(UUID);
180         when(neutronPort.getMacAddress()).thenReturn(MAC_ADDRESS_2);
181         when(neutronPort.getFixedIPs()).thenReturn(neutronIps);
182         NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
183         when(neutronNetwork.getProviderSegmentationID()).thenReturn(ID);
184         List<Node> nodes = new ArrayList<>();
185         nodes.add(mock(Node.class));
186         TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
187         MemberModifier.field(DistributedArpService.class, "tenantNetworkManager").set(distributedArpService, tenantNetworkManager);
188         when(tenantNetworkManager.isTenantNetworkPresentInNode(any(Node.class), eq(ID))).thenReturn(true);
189         PowerMockito.doReturn(15L).when(distributedArpService, "getDatapathIdIntegrationBridge", any(Node.class));
190         INeutronNetworkCRUD neutronNetworkCache = mock(INeutronNetworkCRUD.class);
191         when(neutronNetworkCache.getNetwork(anyString())).thenReturn(neutronNetwork);
192         MemberModifier.field(DistributedArpService.class, "neutronNetworkCache").set(distributedArpService, neutronNetworkCache);
193         NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
194         when(nodeCacheManager.getBridgeNodes()).thenReturn(nodes);
195         MemberModifier.field(DistributedArpService.class, "nodeCacheManager").set(distributedArpService, nodeCacheManager);
196         MemberModifier.field(DistributedArpService.class, "flgDistributedARPEnabled").set(distributedArpService, true);
197
198         // Suppress the called to these functions.
199         MemberModifier.suppress(MemberMatcher.method(DistributedArpService.class, "programStaticRuleStage1", Long.class, String.class, String.class, String.class, Action.class));
200
201         //Case 1: Add Action.
202         Whitebox.invokeMethod(distributedArpService, "handleNeutronPortForArp", neutronPort, Action.ADD);
203         PowerMockito.verifyPrivate(distributedArpService, times(1)).invoke("getDatapathIdIntegrationBridge", any(Node.class));
204         Mockito.verify(distributedArpService, times(1)).programStaticRuleStage1(anyLong(), anyString(), anyString(), anyString(), eq(Action.ADD));
205
206         //Case 2: Delete Action.
207         Whitebox.invokeMethod(distributedArpService, "handleNeutronPortForArp", neutronPort, Action.DELETE);
208         PowerMockito.verifyPrivate(distributedArpService, times(2)).invoke("getDatapathIdIntegrationBridge", any(Node.class));
209         Mockito.verify(distributedArpService, times(1)).programStaticRuleStage1(anyLong(), anyString(), anyString(), anyString(), eq(Action.DELETE));
210     }
211
212     /**
213      * Test that checks if @{DistributedArpService#getDatapathIdIntegrationBridge} is called
214      * and then checks the node integration bridge, then return its datapathID.
215      */
216     @Test
217     public void testGetDatapathIdIntegrationBridge() throws Exception {
218         Southbound southbound = mock(Southbound.class);
219         ConfigurationService configurationService = mock(ConfigurationService.class);
220
221         MemberModifier.field(DistributedArpService.class, "southbound").set(distributedArpService, southbound);
222         MemberModifier.field(DistributedArpService.class, "configurationService").set(distributedArpService, configurationService);
223
224         PowerMockito.when(southbound.getBridge(any(Node.class), anyString())).thenReturn(mock(OvsdbBridgeAugmentation.class));
225         PowerMockito.when(configurationService.getIntegrationBridgeName()).thenReturn("");
226         PowerMockito.when(southbound.getDataPathId(any(Node.class))).thenReturn(45L);
227
228         //Assert check for correct Dp Id.
229         assertEquals("Error, did not return the correct Dpid", 45, (long)Whitebox.invokeMethod(distributedArpService, "getDatapathIdIntegrationBridge", mock(Node.class)));
230     }
231
232     /**
233      * Test that checks if @{DistributedArpService#processInterfaceEvent} is called
234      * and then checks that the event is processing.
235      */
236     @Test
237     public void testProcessInterfaceEvent() throws Exception {
238         NeutronPort neutronPort = mock(NeutronPort.class);
239         NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
240         PowerMockito.doNothing().when(distributedArpService).handlePortEvent(any(NeutronPort.class), any(Action.class));
241         // init instance variables.
242         TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
243         MemberModifier.field(DistributedArpService.class, "tenantNetworkManager").set(distributedArpService , tenantNetworkManager);
244
245         // Mock variables
246         NodeId nodeId = mock(NodeId.class);
247         when(nodeId.getValue()).thenReturn(ID);
248         Node node = mock(Node.class);
249         when(node.getNodeId()).thenReturn(nodeId);
250
251         OvsdbTerminationPointAugmentation intf = mock(OvsdbTerminationPointAugmentation.class);
252         when(intf.getName()).thenReturn(INTF_NAME);
253
254         when(tenantNetworkManager.getTenantPort(intf)).thenReturn(neutronPort);
255
256         //Case 1: Add Action.
257         distributedArpService.processInterfaceEvent(node, intf, neutronNetwork, Action.ADD);
258         Mockito.verify(distributedArpService, times(1)).handlePortEvent(neutronPort, Action.ADD);
259
260         //Case 2: Delete Action.
261         distributedArpService.processInterfaceEvent(node, intf, neutronNetwork, Action.DELETE);
262         Mockito.verify(distributedArpService, times(1)).handlePortEvent(neutronPort, Action.DELETE);
263     }
264
265     /**
266      * Test that checks if @{DistributedArpService#setDependencies} is called
267      * and then checks the object instances.
268      */
269     @Test
270     public void testSetDependencies() throws Exception {
271         TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
272         ConfigurationService configurationService = mock(ConfigurationService.class);
273         ArpProvider arpProvider = mock(ArpProvider.class);
274         NodeCacheManager nodeCacheManager = mock(NodeCacheManager.class);
275         Southbound southbound = mock(Southbound.class);
276
277         ServiceHelper.overrideGlobalInstance(TenantNetworkManager.class, tenantNetworkManager);
278         ServiceHelper.overrideGlobalInstance(ConfigurationService.class, configurationService);
279         ServiceHelper.overrideGlobalInstance(ArpProvider.class, arpProvider);
280         ServiceHelper.overrideGlobalInstance(NodeCacheManager.class, nodeCacheManager);
281         ServiceHelper.overrideGlobalInstance(Southbound.class, southbound);
282
283         distributedArpService.setDependencies(mock(ServiceReference.class));
284
285         assertEquals("Error, did not return the correct object", getField("tenantNetworkManager"), tenantNetworkManager);
286         assertEquals("Error, did not return the correct object", getField("configurationService"), configurationService);
287         assertEquals("Error, did not return the correct object", getField("arpProvider"), arpProvider);
288         assertEquals("Error, did not return the correct object", getField("nodeCacheManager"), nodeCacheManager);
289         assertEquals("Error, did not return the correct object", getField("southbound"), southbound);
290     }
291
292     /**
293      * Test that checks if @{DistributedArpService#setDependencies} is called
294      * and then checks the object instances.
295      */
296     @Test
297     public void testSetDependenciesObject() throws Exception{
298         INeutronNetworkCRUD iNeutronNetworkCRUD = mock(INeutronNetworkCRUD.class);
299         distributedArpService.setDependencies(iNeutronNetworkCRUD);
300         assertEquals("Error, did not return the correct object", getField("neutronNetworkCache"), iNeutronNetworkCRUD);
301
302         INeutronPortCRUD iNeutronPortCRUD = mock(INeutronPortCRUD.class);
303         distributedArpService.setDependencies(iNeutronPortCRUD);
304         assertEquals("Error, did not return the correct object", getField("neutronPortCache"), iNeutronPortCRUD);
305
306         ArpProvider arpProvider = mock(ArpProvider.class);
307         distributedArpService.setDependencies(arpProvider);
308         assertEquals("Error, did not return the correct object", getField("arpProvider"), arpProvider);
309     }
310
311     private Object getField(String fieldName) throws Exception {
312         Field field = DistributedArpService.class.getDeclaredField(fieldName);
313         field.setAccessible(true);
314         return field.get(distributedArpService);
315     }
316 }