Cleanup of Lisp in VPP renderer
[groupbasedpolicy.git] / renderers / vpp / src / test / java / org / opendaylight / groupbasedpolicy / renderer / vpp / iface / VppEndpointLocationProviderTest.java
1 /*
2  * Copyright (c) 2017 Cisco Systems, Inc. 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.groupbasedpolicy.renderer.vpp.iface;
10
11 import java.util.Arrays;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.stream.Collectors;
16
17 import javax.annotation.Nonnull;
18
19 import org.junit.After;
20 import org.junit.Assert;
21 import org.junit.Before;
22 import org.junit.Test;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
25 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.groupbasedpolicy.test.CustomDataBrokerTest;
28 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
29 import org.opendaylight.groupbasedpolicy.util.IidFactory;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.Endpoints;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.AddressEndpoints;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocation;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpoint;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpointBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpointKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.relative.location.relative.locations.ExternalLocation;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.ParentEndpointCaseBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpoint;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpointBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpointKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.LocationProviders;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProvider;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocation;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocationKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.IpPrefixType;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.L2BridgeDomain;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.L3Context;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.MacAddressType;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.Config;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey;
60 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
62
63 import com.google.common.base.Function;
64 import com.google.common.base.Optional;
65 import com.google.common.collect.ImmutableList;
66
67 public class VppEndpointLocationProviderTest extends CustomDataBrokerTest {
68
69     private static final EndpointGroupId DEFAULT_EPG = new EndpointGroupId("Default");
70     private DataBroker dataBroker;
71     private VppEndpointLocationProvider locationProvider;
72
73     private final String INTF_NAME = "interface-name";
74     private final static String TENANT = "tenant";
75     private final NodeId NODE_1 = new NodeId("vpp-node-1");
76     private final NodeId NODE_2 = new NodeId("vpp-node-2");
77     private final NodeId NODE_3 = new NodeId("vpp-node-3");
78
79     private static final ContextId MAC_CTX = new ContextId("mac-context");
80     private static final ContextId IP_CTX = new ContextId("ip-context");
81     private static final VppEndpointKey MAC_KEY_23_45_VPP =
82             new VppEndpointKey("ab:cd:ef:01:23:45", MacAddressType.class, MAC_CTX, L2BridgeDomain.class);
83     private static final VppEndpointKey MAC_KEY_24_45_VPP =
84             new VppEndpointKey("ab:cd:ef:01:24:45", MacAddressType.class, MAC_CTX, L2BridgeDomain.class);
85     private static final VppEndpointKey MAC_KEY_25_45_VPP =
86             new VppEndpointKey("ab:cd:ef:01:25:45", MacAddressType.class, MAC_CTX, L2BridgeDomain.class);
87     private static final AddressEndpointKey MAC_KEY_23_45 =
88             new AddressEndpointKey("ab:cd:ef:01:23:45", MacAddressType.class, MAC_CTX, L2BridgeDomain.class);
89     private static final AddressEndpointKey MAC_KEY_24_45 =
90             new AddressEndpointKey("ab:cd:ef:01:24:45", MacAddressType.class, MAC_CTX, L2BridgeDomain.class);
91     private static final AddressEndpointKey MAC_KEY_25_45 =
92             new AddressEndpointKey("ab:cd:ef:01:25:45", MacAddressType.class, MAC_CTX, L2BridgeDomain.class);
93     private static final AddressEndpointKey IP_KEY_1_22 =
94             new AddressEndpointKey("192.168.1.22/32", IpPrefixType.class, IP_CTX, L3Context.class);
95     private static final AddressEndpointKey IP_KEY_2_22 =
96             new AddressEndpointKey("192.168.2.22/32", IpPrefixType.class, IP_CTX, L3Context.class);
97     private static final AddressEndpointKey IP_KEY_3_22 =
98             new AddressEndpointKey("192.168.3.22/32", IpPrefixType.class, IP_CTX, L3Context.class);
99     private static final AddressEndpointKey IP_KEY_9_99 =
100             new AddressEndpointKey("192.168.9.99/32", IpPrefixType.class, IP_CTX, L3Context.class);
101
102     Function<ExternalLocation, NodeId> extLoctoNodeId =
103             input -> input.getExternalNodeMountPoint().firstKeyOf(Node.class).getNodeId();
104
105     @Before
106     public void init() {
107         dataBroker = getDataBroker();
108         locationProvider = new VppEndpointLocationProvider(dataBroker);
109     }
110
111     @After
112     public void finish() {
113         locationProvider.close();
114     }
115
116     /**
117      * Two L3 endpoints use the same L2 endpoint.
118      * L3 <-> L2 <-> L3
119      * This is an Openstack CI use case, when metadata service and DHCP service
120      * can be reached via the same port.
121      * This should result in 2 absolute locations which keys are derived from L3
122      * endpoints.
123      */
124     @Test
125     public void l2ChildHasTwoL3Parents() {
126         l2ChildHasTwoIpParents(true);
127     }
128
129     /**
130      * There are two data sources from which location is resolved:
131      * {@link AddressEndpoint} and {@link VppEndpoint}
132      * Here the order of events is swapped, i.e. vpp endpoint is written
133      * prior to address endpoint into the datastore.
134      */
135     @Test
136     public void l2ChildHasTwoL3Parents_swapped_order() {
137         locationProvider.createLocationForVppEndpoint(vppEndpointBuilder(MAC_KEY_23_45_VPP, NODE_1, INTF_NAME));
138         l2ChildHasTwoIpParents(false);
139     }
140
141     private void l2ChildHasTwoIpParents(boolean vppEndpointEvent) {
142         AddressEndpointBuilder child = getAddressEndpointBuilder().setKey(MAC_KEY_23_45);
143         setParentEndpoints(child, IP_KEY_1_22, IP_KEY_2_22);
144         AddressEndpointBuilder firstParent = getAddressEndpointBuilder().setKey(IP_KEY_1_22);
145         AddressEndpointBuilder secondParent = getAddressEndpointBuilder().setKey(IP_KEY_2_22);
146         setChildEndpoints(firstParent, MAC_KEY_23_45);
147         setChildEndpoints(secondParent, MAC_KEY_23_45);
148         submitEndpointsToDatastore(child.build(), firstParent.build(), secondParent.build());
149         assertEndpointsInDatastore(child.getKey(), firstParent.getKey(), secondParent.getKey());
150         if (vppEndpointEvent) {
151             locationProvider.createLocationForVppEndpoint(vppEndpointBuilder(MAC_KEY_23_45_VPP, NODE_1, INTF_NAME));
152         }
153         List<ProviderAddressEndpointLocation> locations = readLocations();
154         Assert.assertEquals(locations.size(), 2);
155         locations.forEach(location -> {
156             Assert.assertTrue(location.getKey().equals(getLocationKey(IP_KEY_1_22))
157                     || location.getKey().equals(getLocationKey(IP_KEY_2_22)));
158             assertNodeConnector(location.getAbsoluteLocation(), INTF_NAME);
159             assertMountPoint(location.getAbsoluteLocation(), NODE_1);
160         });
161     }
162
163     /**
164      * This is a regular use case with one to one mapping between L2 endpoint
165      * and L3 endpoint.
166      * As a result one location should be created which key is derived from
167      * L2 endpoint.
168      */
169     @Test
170     public void l2ChildHasOneL3Parent() {
171         locationProvider.createLocationForVppEndpoint(vppEndpointBuilder(MAC_KEY_23_45_VPP, NODE_1, INTF_NAME));
172         l2ChildHasOneIpParent(false);
173     }
174
175     @Test
176     public void l2ChildHasOneL3Parent_swapped_order() {
177         l2ChildHasOneIpParent(true);
178     }
179
180     private void l2ChildHasOneIpParent(boolean vppEndpointEvent) {
181         AddressEndpointBuilder child = getAddressEndpointBuilder().setKey(MAC_KEY_23_45);
182         setParentEndpoints(child, IP_KEY_1_22);
183         AddressEndpointBuilder firstParent = getAddressEndpointBuilder().setKey(IP_KEY_1_22);
184         setChildEndpoints(firstParent, MAC_KEY_23_45);
185         submitEndpointsToDatastore(child.build(), firstParent.build());
186         assertEndpointsInDatastore(child.getKey(), firstParent.getKey());
187         if (vppEndpointEvent) {
188             locationProvider.createLocationForVppEndpoint(vppEndpointBuilder(MAC_KEY_23_45_VPP, NODE_1, INTF_NAME));
189         }
190         List<ProviderAddressEndpointLocation> locations = readLocations();
191         Assert.assertEquals(locations.size(), 1);
192         ProviderAddressEndpointLocation location = locations.get(0);
193         Assert.assertTrue(location.getKey().equals(getLocationKey(IP_KEY_1_22)));
194         assertNodeConnector(location.getAbsoluteLocation(), INTF_NAME);
195         assertMountPoint(location.getAbsoluteLocation(), NODE_1);
196     }
197
198     /**
199      * L3 <-> L2 --> one absolute location is created which key is derived from L2 endpoint
200      * L3 <-> L2 <-> L3 --> two abs. loc. are created which key is derived from L3 endpoints
201      * L3 <-> L2 <-> --> one absolute location is created which key is derived from L2 endpoint
202      * removed --> no location should be present in datastore
203      */
204     @Test
205     public void lifecycleTest() {
206         AddressEndpointBuilder child = getAddressEndpointBuilder().setKey(MAC_KEY_23_45);
207         setParentEndpoints(child, IP_KEY_1_22);
208         AddressEndpointBuilder firstParent = getAddressEndpointBuilder().setKey(IP_KEY_1_22);
209         setChildEndpoints(firstParent, MAC_KEY_23_45);
210         submitEndpointsToDatastore(child.build(), firstParent.build());
211         assertEndpointsInDatastore(child.getKey(), firstParent.getKey());
212         locationProvider.createLocationForVppEndpoint(vppEndpointBuilder(MAC_KEY_23_45_VPP, NODE_1, INTF_NAME));
213         List<ProviderAddressEndpointLocation> locations = readLocations();
214         Assert.assertEquals(1, locations.size());
215         ProviderAddressEndpointLocation location = locations.get(0);
216         Assert.assertTrue(location.getKey().equals(getLocationKey(IP_KEY_1_22)));
217         assertNodeConnector(location.getAbsoluteLocation(), INTF_NAME);
218         assertMountPoint(location.getAbsoluteLocation(), NODE_1);
219         AddressEndpointBuilder secondParent = getAddressEndpointBuilder().setKey(IP_KEY_2_22);
220         setChildEndpoints(secondParent, MAC_KEY_23_45);
221         setParentEndpoints(child, IP_KEY_1_22, IP_KEY_2_22);
222         submitEndpointsToDatastore(child.build(), secondParent.build());
223         assertEndpointsInDatastore(child.getKey(), secondParent.getKey());
224         locations = readLocations();
225         Assert.assertEquals(2, locations.size());
226         locations.forEach(loc -> {
227             Assert.assertTrue(loc.getKey().equals(getLocationKey(IP_KEY_1_22))
228                     || loc.getKey().equals(getLocationKey(IP_KEY_2_22)));
229             assertNodeConnector(loc.getAbsoluteLocation(), INTF_NAME);
230             assertMountPoint(loc.getAbsoluteLocation(), NODE_1);
231         });
232         setParentEndpoints(child, IP_KEY_1_22);
233         WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
234         putEndpoints(wTx, child.build());
235         deleteEndpoints(wTx, secondParent.getKey());
236         DataStoreHelper.submitToDs(wTx);
237         locations = readLocations();
238         Assert.assertEquals(1, locations.size());
239         locations.forEach(loc -> {
240             Assert.assertTrue(loc.getKey().equals(getLocationKey(IP_KEY_1_22)));
241             assertNodeConnector(loc.getAbsoluteLocation(), INTF_NAME);
242             assertMountPoint(loc.getAbsoluteLocation(), NODE_1);
243         });
244         deleteEndpointsFromDatastore(child.getKey(), firstParent.getKey());
245         locations = readLocations();
246         Assert.assertTrue(locations == null || locations.isEmpty());
247     }
248
249     /**
250      * Multihome use case
251      * L2 <-> L3 <-> L2
252      * Relative location should be created in DS which key is derived from L3 endpoint.
253      * The location has two items pointing to corresponding L2 interfaces.
254      */
255     @Test
256     public void testRelativeLocation_multihome() {
257         AddressEndpointBuilder mac1 = getAddressEndpointBuilder().setKey(MAC_KEY_23_45);
258         setParentEndpoints(mac1, IP_KEY_1_22);
259         AddressEndpointBuilder mac2 = getAddressEndpointBuilder().setKey(MAC_KEY_24_45);
260         setParentEndpoints(mac2, IP_KEY_1_22);
261         AddressEndpointBuilder ip1 = getAddressEndpointBuilder().setKey(IP_KEY_1_22);
262         setChildEndpoints(ip1, MAC_KEY_23_45, MAC_KEY_24_45);
263         submitEndpointsToDatastore(mac1.build(), mac2.build(), ip1.build());
264         assertEndpointsInDatastore(mac1.getKey(), mac2.getKey(), ip1.getKey());
265         locationProvider.createLocationForVppEndpoint(vppEndpointBuilder(MAC_KEY_23_45_VPP, NODE_1, INTF_NAME));
266         locationProvider.createLocationForVppEndpoint(vppEndpointBuilder(MAC_KEY_24_45_VPP, NODE_2, INTF_NAME));
267         List<ProviderAddressEndpointLocation> locations = readLocations();
268         Assert.assertEquals(1, locations.size());
269         List<ExternalLocation> extLocs = locations.get(0).getRelativeLocations().getExternalLocation();
270         Assert.assertEquals(1, extLocs.stream().filter(extLoc -> extLoctoNodeId.apply(extLoc).equals(NODE_1)).count());
271         Assert.assertEquals(1, extLocs.stream().filter(extLoc -> extLoctoNodeId.apply(extLoc).equals(NODE_2)).count());
272         Assert.assertEquals(2,
273                 extLocs.stream().filter(extLoc -> extLoc.getExternalNodeConnector().contains(INTF_NAME)).count());
274     }
275
276     /**
277      * Metadata use case in Openstack HA scenarios
278      * A DHCP pot is created on each of three controller nodes. Metadata service can be reached
279      * through any of the ports. This results in GBP into following endpoint configuration:
280      * L3(DHCP1) <-> L2(1) <-> L3(METADATA)
281      * L3(DHCP2) <-> L2(2) <-> L3(METADATA)
282      * L3(DHCP3) <-> L2(3) <-> L3(METADATA)
283      * Notice that Metadata endpoint has three L2 childs. Every L2 endpoint has two parents,
284      * Metadata endpoint and L3 endpoint.
285      * Locations created:
286      * Metadata -> relative location with three l2 items, key is derived from L3 address
287      * DHCP(x) -> absolute location, key is derived from L3 address
288      */
289     @Test
290     public void testMetadataHaUseCase() {
291         AddressEndpointBuilder mac1 = getAddressEndpointBuilder().setKey(MAC_KEY_23_45);
292         setParentEndpoints(mac1, IP_KEY_1_22, IP_KEY_9_99);
293         AddressEndpointBuilder mac2 = getAddressEndpointBuilder().setKey(MAC_KEY_24_45);
294         setParentEndpoints(mac2, IP_KEY_2_22, IP_KEY_9_99);
295         AddressEndpointBuilder mac3 = getAddressEndpointBuilder().setKey(MAC_KEY_25_45);
296         setParentEndpoints(mac3, IP_KEY_3_22, IP_KEY_9_99);
297         AddressEndpointBuilder ip1 = getAddressEndpointBuilder().setKey(IP_KEY_1_22);
298         setChildEndpoints(ip1, MAC_KEY_23_45);
299         AddressEndpointBuilder ip2 = getAddressEndpointBuilder().setKey(IP_KEY_2_22);
300         setChildEndpoints(ip2, MAC_KEY_24_45);
301         AddressEndpointBuilder ip3 = getAddressEndpointBuilder().setKey(IP_KEY_3_22);
302         setChildEndpoints(ip3, MAC_KEY_25_45);
303         AddressEndpointBuilder ip9 = getAddressEndpointBuilder().setKey(IP_KEY_9_99);
304         setChildEndpoints(ip9, MAC_KEY_23_45, MAC_KEY_24_45, MAC_KEY_25_45);
305         submitEndpointsToDatastore(mac1.build(), mac2.build(), mac3.build(), ip1.build(), ip2.build(), ip3.build(),
306                 ip9.build());
307         assertEndpointsInDatastore(mac1.getKey(), mac2.getKey(), mac3.getKey(), ip1.getKey(), ip2.getKey(),
308                 ip3.getKey(), ip9.getKey());
309         locationProvider.createLocationForVppEndpoint(vppEndpointBuilder(MAC_KEY_23_45_VPP, NODE_1, INTF_NAME));
310         locationProvider.createLocationForVppEndpoint(vppEndpointBuilder(MAC_KEY_24_45_VPP, NODE_2, INTF_NAME));
311         locationProvider.createLocationForVppEndpoint(vppEndpointBuilder(MAC_KEY_25_45_VPP, NODE_3, INTF_NAME));
312         assertL2ChildHasTwoIpParentsAndIpParentHasMultipleChilds(4L);
313     }
314
315     /**
316      * Metadata use case where endpoints are created in more realistic order
317      */
318     @Test
319     public void metadataHaUseCase_swapped_order() {
320         AddressEndpointBuilder mac1 = getAddressEndpointBuilder().setKey(MAC_KEY_23_45);
321         setParentEndpoints(mac1, IP_KEY_1_22, IP_KEY_9_99);
322         locationProvider.createLocationForVppEndpoint(vppEndpointBuilder(MAC_KEY_23_45_VPP, NODE_1, INTF_NAME));
323         AddressEndpointBuilder ip1 = getAddressEndpointBuilder().setKey(IP_KEY_1_22);
324         setChildEndpoints(ip1, MAC_KEY_23_45);
325         AddressEndpointBuilder ip9 = getAddressEndpointBuilder().setKey(IP_KEY_9_99);
326         setChildEndpoints(ip9, MAC_KEY_23_45);
327         submitEndpointsToDatastore(mac1.build(), ip1.build(), ip9.build());
328         locationProvider.createLocationForVppEndpoint(vppEndpointBuilder(MAC_KEY_24_45_VPP, NODE_2, INTF_NAME));
329         AddressEndpointBuilder mac2 = getAddressEndpointBuilder().setKey(MAC_KEY_24_45);
330         setParentEndpoints(mac2, IP_KEY_2_22, IP_KEY_9_99);
331         AddressEndpointBuilder ip2 = getAddressEndpointBuilder().setKey(IP_KEY_2_22);
332         setChildEndpoints(ip2, MAC_KEY_24_45);
333         ip9 = getAddressEndpointBuilder().setKey(IP_KEY_9_99);
334         setChildEndpoints(ip9, MAC_KEY_23_45, MAC_KEY_24_45);
335         submitEndpointsToDatastore(mac2.build(), ip2.build(), ip9.build());
336         AddressEndpointBuilder mac3 = getAddressEndpointBuilder().setKey(MAC_KEY_25_45);
337         setParentEndpoints(mac3, IP_KEY_3_22, IP_KEY_9_99);
338         AddressEndpointBuilder ip3 = getAddressEndpointBuilder().setKey(IP_KEY_3_22);
339         setChildEndpoints(ip3, MAC_KEY_25_45);
340         ip9 = getAddressEndpointBuilder().setKey(IP_KEY_9_99);
341         setChildEndpoints(ip9, MAC_KEY_23_45, MAC_KEY_24_45, MAC_KEY_25_45);
342         locationProvider.createLocationForVppEndpoint(vppEndpointBuilder(MAC_KEY_25_45_VPP, NODE_3, INTF_NAME));
343         submitEndpointsToDatastore(mac3.build(), ip3.build(), ip9.build());
344         assertEndpointsInDatastore(mac1.getKey(), mac2.getKey(), mac3.getKey(), ip1.getKey(), ip2.getKey(),
345                 ip3.getKey(), ip9.getKey());
346         assertL2ChildHasTwoIpParentsAndIpParentHasMultipleChilds(4L);
347     }
348
349     private AddressEndpointBuilder getAddressEndpointBuilder() {
350         return new AddressEndpointBuilder()
351             .setTenant(new TenantId(TENANT))
352             .setEndpointGroup(Collections.singletonList(DEFAULT_EPG))
353             ;
354     }
355
356     private void assertL2ChildHasTwoIpParentsAndIpParentHasMultipleChilds(long expected) {
357         List<ProviderAddressEndpointLocation> locations = readLocations();
358         Assert.assertEquals(expected, locations.size());
359         locations.forEach(location -> {
360             if (location.getKey().equals(getLocationKey(IP_KEY_1_22))) {
361                 assertNodeConnector(location.getAbsoluteLocation(), INTF_NAME);
362                 assertMountPoint(location.getAbsoluteLocation(), NODE_1);
363             } else if (location.getKey().equals(getLocationKey(IP_KEY_2_22))) {
364                 assertNodeConnector(location.getAbsoluteLocation(), INTF_NAME);
365                 assertMountPoint(location.getAbsoluteLocation(), NODE_2);
366             } else if (location.getKey().equals(getLocationKey(IP_KEY_3_22))) {
367                 assertNodeConnector(location.getAbsoluteLocation(), INTF_NAME);
368                 assertMountPoint(location.getAbsoluteLocation(), NODE_3);
369             } else if (location.getKey().equals(getLocationKey(IP_KEY_9_99))) {
370                 List<ExternalLocation> extLocs = location.getRelativeLocations().getExternalLocation();
371                 Assert.assertEquals(1,
372                         extLocs.stream().filter(extLoc -> extLoctoNodeId.apply(extLoc).equals(NODE_1)).count());
373                 Assert.assertEquals(1,
374                         extLocs.stream().filter(extLoc -> extLoctoNodeId.apply(extLoc).equals(NODE_2)).count());
375                 Assert.assertEquals(1,
376                         extLocs.stream().filter(extLoc -> extLoctoNodeId.apply(extLoc).equals(NODE_3)).count());
377                 Assert.assertEquals(3, extLocs.stream()
378                     .filter(extLoc -> extLoc.getExternalNodeConnector().contains(INTF_NAME))
379                     .count());
380             }
381         });
382     }
383
384     private static void assertNodeConnector(AbsoluteLocation absoluteLocation, String intfName) {
385         ExternalLocationCase extLocation = (ExternalLocationCase) absoluteLocation.getLocationType();
386         Assert.assertTrue(extLocation.getExternalNodeConnector().contains(intfName));
387     }
388
389     private static void assertMountPoint(AbsoluteLocation absoluteLocation, NodeId nodeId) {
390         ExternalLocationCase extLocation = (ExternalLocationCase) absoluteLocation.getLocationType();
391         NodeId ref = extLocation.getExternalNodeMountPoint().firstKeyOf(Node.class).getNodeId();
392         Assert.assertTrue(ref.equals(nodeId));
393     }
394
395     private static void setParentEndpoints(@Nonnull AddressEndpointBuilder builder,
396             @Nonnull AddressEndpointKey... parents) {
397         List<ParentEndpoint> builtParents = Arrays.stream(parents)
398             .map(key -> new ParentEndpointBuilder().setKey(getParentKey(key)).build())
399             .collect(Collectors.toList());
400         builder.setParentEndpointChoice(new ParentEndpointCaseBuilder().setParentEndpoint(builtParents).build());
401     }
402
403     private static void setChildEndpoints(@Nonnull AddressEndpointBuilder builder,
404             @Nonnull AddressEndpointKey... childs) {
405         List<ChildEndpoint> builtChilds = Arrays.stream(childs)
406             .map(key -> new ChildEndpointBuilder().setKey(getChildKey(key)).build())
407             .collect(Collectors.toList());
408         builder.setChildEndpoint(builtChilds).build();
409     }
410
411     private static ParentEndpointKey getParentKey(AddressEndpointKey key) {
412         return new ParentEndpointKey(key.getAddress(), key.getAddressType(), key.getContextId(), key.getContextType());
413     }
414
415     private static ChildEndpointKey getChildKey(AddressEndpointKey key) {
416         return new ChildEndpointKey(key.getAddress(), key.getAddressType(), key.getContextId(), key.getContextType());
417     }
418
419     private static VppEndpoint vppEndpointBuilder(VppEndpointKey vppEpKey, NodeId nodeId, String interfaceName) {
420         final VppEndpointBuilder vppEndpointBuilder = new VppEndpointBuilder();
421         vppEndpointBuilder.setKey(vppEpKey).setVppNodeId(nodeId).setVppInterfaceName(interfaceName);
422         return vppEndpointBuilder.build();
423     }
424
425     private static ProviderAddressEndpointLocationKey getLocationKey(AddressEndpointKey key) {
426         return new ProviderAddressEndpointLocationKey(key.getAddress(), key.getAddressType(), key.getContextId(),
427                 key.getContextType());
428     }
429
430     private void assertEndpointsInDatastore(AddressEndpointKey... keys) {
431         ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
432         for (AddressEndpointKey key : keys) {
433             Assert.assertTrue(DataStoreHelper
434                 .readFromDs(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(key), rTx).isPresent());
435         }
436         rTx.close();
437     }
438
439     private static void putEndpoints(WriteTransaction wTx, AddressEndpoint... endpoints) {
440         for (AddressEndpoint endpoint : endpoints) {
441             wTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(endpoint.getKey()), endpoint);
442         }
443     }
444
445     private static void deleteEndpoints(WriteTransaction wTx, AddressEndpointKey... keys) {
446         for (AddressEndpointKey key : keys) {
447             wTx.delete(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(key));
448         }
449     }
450
451     private void deleteEndpointsFromDatastore(AddressEndpointKey... keys) {
452         WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
453         for (AddressEndpointKey key : keys) {
454             wTx.delete(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(key));
455         }
456         DataStoreHelper.submitToDs(wTx);
457     }
458
459     private List<ProviderAddressEndpointLocation> readLocations() {
460         ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
461         Optional<LocationProvider> locations = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
462                 IidFactory.locationProviderIid(VppEndpointLocationProvider.VPP_ENDPOINT_LOCATION_PROVIDER), rTx);
463         rTx.close();
464         Assert.assertTrue(locations.isPresent());
465         return locations.get().getProviderAddressEndpointLocation();
466     }
467
468     @Override
469     public Collection<Class<?>> getClassesFromModules() {
470         return ImmutableList.<Class<?>>of(Endpoints.class, Config.class, LocationProviders.class,
471                 AddressEndpoints.class, MacAddressType.class, IpPrefixType.class);
472     }
473
474     private void submitEndpointsToDatastore(AddressEndpoint... endpoints) {
475         WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
476         for (AddressEndpoint endpoint : endpoints) {
477             wTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.addressEndpointIid(endpoint.getKey()), endpoint);
478         }
479         DataStoreHelper.submitToDs(wTx);
480     }
481 }