2 * Copyright (c) 2017 Hewlett Packard Enterprise, Co. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.federation.plugin.end2end;
10 import static org.mockito.Matchers.any;
11 import static org.mockito.Matchers.anyString;
12 import static org.mockito.Matchers.eq;
13 import static org.mockito.Mockito.doAnswer;
14 import static org.mockito.Mockito.doReturn;
15 import static org.mockito.Mockito.mock;
16 import static org.mockito.Mockito.when;
18 import com.google.common.base.Optional;
19 import com.google.common.util.concurrent.Futures;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.LinkedList;
26 import java.util.List;
28 import org.mockito.ArgumentCaptor;
29 import org.mockito.Mock;
30 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
31 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
32 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
33 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
34 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
35 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
36 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
37 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
38 import org.opendaylight.federation.service.api.IConsumerManagement;
39 import org.opendaylight.federation.service.api.message.WrapperEntityFederationMessage;
40 import org.opendaylight.federation.service.impl.FederationProducerMgr;
41 import org.opendaylight.federation.service.impl.WrapperConsumer;
42 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
43 import org.opendaylight.messagequeue.AbstractFederationMessage;
44 import org.opendaylight.messagequeue.IMessageBusClient;
45 import org.opendaylight.netvirt.elanmanager.api.IElanService;
46 import org.opendaylight.netvirt.federation.plugin.FederatedNetworkPair;
47 import org.opendaylight.netvirt.federation.plugin.FederationPluginEgress;
48 import org.opendaylight.netvirt.federation.plugin.FederationPluginIngress;
49 import org.opendaylight.netvirt.federation.plugin.FederationPluginMgr;
50 import org.opendaylight.netvirt.federation.plugin.FederationPluginUtils;
51 import org.opendaylight.netvirt.federation.plugin.SubnetVpnAssociationManager;
52 import org.opendaylight.netvirt.federation.plugin.creators.FederationElanInterfaceModificationCreator;
53 import org.opendaylight.netvirt.federation.plugin.creators.FederationIetfInterfaceModificationCreator;
54 import org.opendaylight.netvirt.federation.plugin.creators.FederationInventoryNodeModificationCreator;
55 import org.opendaylight.netvirt.federation.plugin.creators.FederationTopologyNodeModificationCreator;
56 import org.opendaylight.netvirt.federation.plugin.creators.FederationVpnInterfaceModificationCreator;
57 import org.opendaylight.netvirt.federation.plugin.filters.FederationElanInterfaceFilter;
58 import org.opendaylight.netvirt.federation.plugin.filters.FederationIetfInterfaceFilter;
59 import org.opendaylight.netvirt.federation.plugin.filters.FederationInventoryNodeFilter;
60 import org.opendaylight.netvirt.federation.plugin.filters.FederationTopologyNodeFilter;
61 import org.opendaylight.netvirt.federation.plugin.filters.FederationVpnInterfaceFilter;
62 import org.opendaylight.netvirt.federation.plugin.identifiers.FederationElanInterfaceIdentifier;
63 import org.opendaylight.netvirt.federation.plugin.identifiers.FederationIetfInterfaceIdentifier;
64 import org.opendaylight.netvirt.federation.plugin.identifiers.FederationInventoryNodeIdentifier;
65 import org.opendaylight.netvirt.federation.plugin.identifiers.FederationTopologyNodeIdentifier;
66 import org.opendaylight.netvirt.federation.plugin.identifiers.FederationVpnInterfaceIdentifier;
67 import org.opendaylight.netvirt.federation.plugin.transformers.FederationElanInterfaceTransformer;
68 import org.opendaylight.netvirt.federation.plugin.transformers.FederationIetfInterfaceTransformer;
69 import org.opendaylight.netvirt.federation.plugin.transformers.FederationInventoryNodeTransformer;
70 import org.opendaylight.netvirt.federation.plugin.transformers.FederationTopologyNodeTransformer;
71 import org.opendaylight.netvirt.federation.plugin.transformers.FederationVpnInterfaceTransformer;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.federation.plugin.manager.rev170219.FederationGenerations;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.federation.plugin.manager.rev170219.federation.generations.RemoteSiteGenerationInfo;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.federation.plugin.manager.rev170219.federation.generations.RemoteSiteGenerationInfoBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.federation.plugin.manager.rev170219.federation.generations.RemoteSiteGenerationInfoKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.federation.service.config.rev161110.FederationConfigData;
77 import org.opendaylight.yangtools.yang.binding.DataObject;
78 import org.opendaylight.yangtools.yang.binding.Identifier;
79 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
80 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
81 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
83 public class AbstractEnd2EndTest {
85 protected DataBroker dataBroker = mock(DataBroker.class);
86 protected IElanService elanService = mock(IElanService.class);
87 protected SubnetVpnAssociationManager associationMgr = mock(SubnetVpnAssociationManager.class);
88 protected LinkedList<AbstractFederationMessage> sentMessages;
89 public LinkedList<MergedObject> mergedObjects = new LinkedList<>();
91 protected FederationProducerMgr producer;
92 protected FederationPluginEgress egressPlugin;
93 protected final HashMap<String, DataTreeChangeListener<?>> keyToListener = new HashMap<>();
96 protected ReadOnlyTransaction mockReadTx;
98 protected WriteTransaction stubWriteTx = mock(WriteTransaction.class);
100 protected IMessageBusClient msgBusConsumerMock = mock(IMessageBusClient.class);
102 protected ClusterSingletonServiceProvider singletonService = mock(ClusterSingletonServiceProvider.class);
104 protected IConsumerManagement consumerMgr = mock(IConsumerManagement.class);
107 protected FederationPluginMgr mgr;
109 protected FederationPluginIngress ingressPlugin;
111 protected WrapperConsumer wrapperConsumer;
114 FederationConfigData configMock;
116 @SuppressWarnings("rawtypes")
117 protected HashMap<String, ArgumentCaptor<DataTreeChangeListener>> listenerKeyToCaptor;
119 protected final ArgumentCaptor<AbstractFederationMessage> msgCaptor = ArgumentCaptor
120 .forClass(AbstractFederationMessage.class);
122 protected static final String REMOTE_IP = "1.1.1.1";
123 protected static final String DUMMYINTERFACE = "dummyinterface";
124 protected static final String REMOTE_TENANT_ID = "remoteTenantId";
125 protected static final String LOCAL_TENANT_ID = "localTenantId";
126 protected static final String PRODUCER_SUBNET_ID = "11112222-ffff-aaaa-2222-333444555666";
127 protected static final String CONSUMER_SUBNET_ID = "11113333-ffff-aaaa-2222-333444555666";
128 protected static final String PRODUCER_NETWORK_ID = "remoteNetworkId";
129 protected static final String CONSUMER_NETWORK_ID = "localNetworkId";
130 protected static final String CONSUMER1_QUEUE = "consumer1Queue";
131 protected static final String CONSUMER2_QUEUE = "consumer2Queue";
132 protected static final String INTEGRATION_BRIDGE_PREFIX = "bridge/br-int";
134 public AbstractEnd2EndTest() {
135 FederationInventoryNodeTransformer inventoryNodeTransformer = new FederationInventoryNodeTransformer();
136 new FederationInventoryNodeFilter(dataBroker, inventoryNodeTransformer);
137 new FederationInventoryNodeModificationCreator();
138 new FederationInventoryNodeIdentifier();
139 new FederationTopologyNodeTransformer();
140 new FederationTopologyNodeFilter();
141 new FederationTopologyNodeModificationCreator();
142 new FederationTopologyNodeIdentifier();
143 new FederationIetfInterfaceTransformer();
144 new FederationIetfInterfaceFilter(dataBroker, elanService);
145 new FederationIetfInterfaceModificationCreator();
146 new FederationIetfInterfaceIdentifier();
147 new FederationElanInterfaceTransformer();
148 new FederationElanInterfaceFilter(dataBroker, elanService);
149 new FederationElanInterfaceModificationCreator();
150 new FederationElanInterfaceIdentifier();
151 new FederationVpnInterfaceFilter(dataBroker, associationMgr);
152 new FederationVpnInterfaceTransformer(associationMgr);
153 new FederationVpnInterfaceModificationCreator();
154 new FederationVpnInterfaceIdentifier();
157 public void initialization() {
158 sentMessages = new LinkedList<>();
159 producer = new FederationProducerMgr(msgBusConsumerMock, dataBroker, configMock, singletonService, consumerMgr);
160 producer.attachPluginFactory("netvirt", (payload, queueName, contextId) -> egressPlugin);
161 List<FederatedNetworkPair> federatedNetworkPairs = Arrays.asList(new FederatedNetworkPair(CONSUMER_NETWORK_ID,
162 PRODUCER_NETWORK_ID, CONSUMER_SUBNET_ID, PRODUCER_SUBNET_ID, LOCAL_TENANT_ID, REMOTE_TENANT_ID));
163 egressPlugin = new FederationPluginEgress(producer, federatedNetworkPairs, CONSUMER1_QUEUE, CONSUMER1_QUEUE);
164 ingressPlugin = new FederationPluginIngress(mgr, dataBroker, REMOTE_IP, federatedNetworkPairs);
165 wrapperConsumer = new WrapperConsumer(REMOTE_IP, ingressPlugin);
170 private void prepareMocks() {
171 HashMap<String, DataTreeIdentifier<?>> listenerKeyToIdentifer = new HashMap<>();
172 listenerKeyToCaptor = new HashMap<>();
173 egressPlugin.getListenersData().forEach(p -> listenerKeyToIdentifer.put(p.listenerId, p.listenerPath));
174 egressPlugin.getListenersData().forEach(
175 p -> listenerKeyToCaptor.put(p.listenerId, ArgumentCaptor.forClass(DataTreeChangeListener.class)));
176 for (String key : FederationPluginUtils.getOrderedListenerKeys()) {
177 when(dataBroker.registerDataTreeChangeListener(eq(listenerKeyToIdentifer.get(key)),
178 listenerKeyToCaptor.get(key).capture())).thenReturn(null);
181 doAnswer(invocation -> {
182 AbstractFederationMessage msg = (AbstractFederationMessage) invocation.getArguments()[0];
183 sentMessages.add(msg);
184 wrapperConsumer.consumeMsg(msg);
186 }).when(msgBusConsumerMock).sendMsg(any(), anyString());
188 doReturn("2.2.2.2").when(configMock).getMqBrokerIp();
189 doReturn(stubWriteTx).when(dataBroker).newWriteOnlyTransaction();
190 when(associationMgr.getSubnetVpn(any())).thenReturn("dummySubnetVpn");
191 doReturn(mockReadTx).when(dataBroker).newReadOnlyTransaction();
193 when(stubWriteTx.submit()).thenReturn(Futures.immediateCheckedFuture(null));
194 doAnswer(invocation -> {
195 InstanceIdentifier<?> path = (InstanceIdentifier<?>) invocation.getArguments()[1];
196 DataObject data = (DataObject) invocation.getArguments()[2];
197 mergedObjects.add(new MergedObject(data, path));
199 }).when(stubWriteTx).merge(any(), any(), any());
202 protected class MergedObject {
203 public DataObject obj;
204 public InstanceIdentifier<?> insId;
206 public MergedObject(DataObject obj, InstanceIdentifier<?> insId) {
212 public int mergedObjectsAmount() {
213 return mergedObjects.size();
216 protected <T extends DataObject> T removeLastMerged(Class<T> type) {
217 return type.cast(mergedObjects.removeLast().obj);
220 protected <T extends DataObject> T removeFirstMerged(Class<T> type) {
221 return type.cast(mergedObjects.removeFirst().obj);
224 protected String lastSentJson() {
225 AbstractFederationMessage lastMsg = sentMessages.getLast();
226 WrapperEntityFederationMessage wrapper = (WrapperEntityFederationMessage) lastMsg;
227 return wrapper.getPayload().getJsonInput();
230 @SuppressWarnings({ "unchecked", "rawtypes" })
231 protected void dcn(String listenerKey, DataObject newObject) {
232 DataTreeChangeListener listener = getListenerForKey(listenerKey);
233 listener.onDataTreeChanged(change(newObject, FederationPluginUtils.getListenerDatastoreType(listenerKey),
234 FederationPluginUtils.getInstanceIdentifier(listenerKey)));
237 @SuppressWarnings({ "rawtypes", "unchecked" })
238 protected void dcns(String listenerKey, List<? extends DataObject> newObjects) {
239 DataTreeChangeListener listener = getListenerForKey(listenerKey);
240 listener.onDataTreeChanged(changes(FederationPluginUtils.getListenerDatastoreType(listenerKey),
241 FederationPluginUtils.getInstanceIdentifier(listenerKey), newObjects));
244 protected DataTreeChangeListener<?> getListenerForKey(String listenerKey) {
245 return listenerKeyToCaptor.get(listenerKey).getValue();
248 protected Collection<DataTreeModification<?>> changes(LogicalDatastoreType datastoreType,
249 InstanceIdentifier<? extends DataObject> instanceIdentifier, List<? extends DataObject> dataObjects) {
250 ArrayList<DataTreeModification<?>> changes = new ArrayList<>();
251 dataObjects.forEach(data -> changes.add(new FakeDataTreeModification(data, datastoreType, instanceIdentifier)));
255 protected Collection<?> change(DataObject newObject, LogicalDatastoreType datastoreType,
256 InstanceIdentifier<? extends DataObject> instanceIdentifier) {
257 ArrayList<DataTreeModification<?>> changes = new ArrayList<>();
258 changes.add(new FakeDataTreeModification(newObject, datastoreType, instanceIdentifier));
262 protected void setGenerationNumberMock() {
263 int generationNumberValue = 2;
264 KeyedInstanceIdentifier<RemoteSiteGenerationInfo, RemoteSiteGenerationInfoKey>
265 generationNumberPath = InstanceIdentifier.create(FederationGenerations.class)
266 .child(RemoteSiteGenerationInfo.class, new RemoteSiteGenerationInfoKey(REMOTE_IP));
267 RemoteSiteGenerationInfo generationNumber = new RemoteSiteGenerationInfoBuilder().setRemoteIp(REMOTE_IP)
268 .setGenerationNumber(generationNumberValue).build();
269 when(mockReadTx.read(LogicalDatastoreType.CONFIGURATION, generationNumberPath))
270 .thenReturn(Futures.immediateCheckedFuture(Optional.of(generationNumber)));
273 @SuppressWarnings("rawtypes")
274 public class FakeDataTreeModification implements DataTreeModification {
276 private final FakeDataObjectModification fakeMod;
277 private final LogicalDatastoreType dataStoreType;
278 private final InstanceIdentifier<? extends DataObject> instanceIdentifier;
280 public FakeDataTreeModification(DataObject theObject, LogicalDatastoreType datastoreType,
281 InstanceIdentifier<? extends DataObject> instanceIdentifier) {
282 fakeMod = new FakeDataObjectModification(theObject);
283 this.dataStoreType = datastoreType;
284 this.instanceIdentifier = instanceIdentifier;
287 @SuppressWarnings("unchecked")
289 public DataTreeIdentifier<?> getRootPath() {
290 return new DataTreeIdentifier(dataStoreType, instanceIdentifier);
294 public DataObjectModification<?> getRootNode() {
300 @SuppressWarnings("rawtypes")
301 public class FakeDataObjectModification implements DataObjectModification {
303 private final DataObject theObject;
305 private final ModificationType modType = ModificationType.WRITE;
307 public FakeDataObjectModification(DataObject theObject) {
308 this.theObject = theObject;
312 public PathArgument getIdentifier() {
317 public Class getDataType() {
322 public ModificationType getModificationType() {
327 public DataObject getDataBefore() {
332 public DataObject getDataAfter() {
337 public Collection<?> getModifiedChildren() {
342 public DataObjectModification<?> getModifiedChildContainer(Class child) {
347 public DataObjectModification<?> getModifiedAugmentation(Class augmentation) {
352 public DataObjectModification<?> getModifiedChildListItem(Class listItem, Identifier listKey) {
357 public DataObjectModification<?> getModifiedChild(PathArgument childArgument) {