Decompose RPC implementation classes
[openflowplugin.git] / openflowplugin-impl / src / test / java / org / opendaylight / openflowplugin / impl / services / sal / SalFlowServiceImplTest.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies s.r.o. 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 package org.opendaylight.openflowplugin.impl.services.sal;
9
10 import static org.junit.Assert.assertFalse;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertTrue;
13 import static org.mockito.Mockito.doReturn;
14 import static org.mockito.Mockito.mock;
15 import static org.mockito.Mockito.when;
16
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import java.util.concurrent.ExecutionException;
20 import org.junit.Before;
21 import org.junit.Test;
22 import org.junit.runner.RunWith;
23 import org.mockito.Mock;
24 import org.mockito.junit.MockitoJUnitRunner;
25 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
26 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueue;
27 import org.opendaylight.openflowplugin.api.OFConstants;
28 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
29 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
30 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
31 import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
32 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
33 import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
34 import org.opendaylight.openflowplugin.api.openflow.device.Xid;
35 import org.opendaylight.openflowplugin.api.openflow.registry.flow.DeviceFlowRegistry;
36 import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageSpy;
37 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorManagerFactory;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlow;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput;
62 import org.opendaylight.yangtools.yang.binding.DataObject;
63 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
64 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
65 import org.opendaylight.yangtools.yang.common.RpcResult;
66 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
67 import org.opendaylight.yangtools.yang.common.Uint16;
68 import org.opendaylight.yangtools.yang.common.Uint32;
69 import org.opendaylight.yangtools.yang.common.Uint64;
70 import org.opendaylight.yangtools.yang.common.Uint8;
71
72 @RunWith(MockitoJUnitRunner.StrictStubs.class)
73 public class SalFlowServiceImplTest {
74     private static final Uint64 DUMMY_DATAPATH_ID = Uint64.valueOf(444);
75     private static final String DUMMY_NODE_ID = "dummyNodeID";
76     private static final String DUMMY_FLOW_ID = "dummyFlowID";
77     private static final Uint8 DUMMY_TABLE_ID = Uint8.ZERO;
78
79     private static final KeyedInstanceIdentifier<Node, NodeKey> NODE_II =
80         InstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(new NodeId(DUMMY_NODE_ID)));
81
82     private static final KeyedInstanceIdentifier<Table, TableKey> TABLE_II =
83         NODE_II.augmentation(FlowCapableNode.class).child(Table.class, new TableKey(DUMMY_TABLE_ID));
84
85     private final NodeRef noderef = new NodeRef(NODE_II);
86
87     @Mock
88     private RequestContextStack mockedRequestContextStack;
89     @Mock
90     private DeviceContext mockedDeviceContext;
91     @Mock
92     private ConnectionContext mockedPrimConnectionContext;
93     @Mock
94     private FeaturesReply mockedFeatures;
95     @Mock
96     private ConnectionAdapter mockedConnectionAdapter;
97     @Mock
98     private MessageSpy mockedMessagSpy;
99     @Mock
100     private RequestContext<Object> requestContext;
101     @Mock
102     private OutboundQueue outboundQueue;
103     @Mock
104     private Match match;
105
106     @Mock
107     private DeviceState mockedDeviceState;
108     @Mock
109     private DeviceInfo mockedDeviceInfo;
110     @Mock
111     private DeviceFlowRegistry deviceFlowRegistry;
112     @Mock
113     private GetFeaturesOutput mockedFeaturesOutput;
114
115     @Before
116     public void initialization() {
117
118         when(mockedPrimConnectionContext.getOutboundQueueProvider()).thenReturn(outboundQueue);
119
120         when(mockedDeviceContext.getPrimaryConnectionContext()).thenReturn(mockedPrimConnectionContext);
121         when(mockedDeviceContext.getMessageSpy()).thenReturn(mockedMessagSpy);
122         when(mockedDeviceContext.getDeviceFlowRegistry()).thenReturn(deviceFlowRegistry);
123
124         when(requestContext.getXid()).thenReturn(new Xid(Uint32.valueOf(84L)));
125         when(requestContext.getFuture()).thenReturn(RpcResultBuilder.success().buildFuture());
126         when(mockedRequestContextStack.createRequestContext()).thenReturn(requestContext);
127
128         when(mockedDeviceInfo.getDatapathId()).thenReturn(DUMMY_DATAPATH_ID);
129
130         when(mockedDeviceContext.getDeviceInfo()).thenReturn(mockedDeviceInfo);
131     }
132
133     private AddFlowImpl mockAddFlow(final Uint8 version) {
134         when(mockedFeatures.getVersion()).thenReturn(version);
135         when(mockedFeaturesOutput.getVersion()).thenReturn(version);
136         when(mockedDeviceInfo.getVersion()).thenReturn(version);
137
138         final var convertorManager = ConvertorManagerFactory.createDefaultManager();
139         return new AddFlowImpl(mockedRequestContextStack, mockedDeviceContext, convertorManager);
140     }
141
142     private RemoveFlowImpl mockRemoveFlow(final Uint8 version) {
143         when(mockedFeatures.getVersion()).thenReturn(version);
144         when(mockedFeaturesOutput.getVersion()).thenReturn(version);
145         when(mockedDeviceInfo.getVersion()).thenReturn(version);
146
147         final var convertorManager = ConvertorManagerFactory.createDefaultManager();
148         return new RemoveFlowImpl(mockedRequestContextStack, mockedDeviceContext, convertorManager);
149     }
150
151     private UpdateFlowImpl mockUpdateFlow(final Uint8 version) {
152         when(mockedFeatures.getVersion()).thenReturn(version);
153         when(mockedFeaturesOutput.getVersion()).thenReturn(version);
154         when(mockedDeviceInfo.getVersion()).thenReturn(version);
155
156         final var convertorManager = ConvertorManagerFactory.createDefaultManager();
157         return new UpdateFlowImpl(mockedRequestContextStack, mockedDeviceContext, convertorManager);
158     }
159
160     @Test
161     public void testAddFlow() throws Exception {
162         addFlow(OFConstants.OFP_VERSION_1_0);
163         addFlow(OFConstants.OFP_VERSION_1_3);
164     }
165
166     @Test
167     public void testAddFlowFailCallback() throws Exception {
168         addFlowFailCallback(OFConstants.OFP_VERSION_1_0);
169     }
170
171     @Test
172     public void testAddFlowFailCallback1() throws Exception {
173         addFlowFailCallback(OFConstants.OFP_VERSION_1_3);
174     }
175
176     private void addFlowFailCallback(final Uint8 version) throws InterruptedException, ExecutionException {
177         AddFlowInput mockedAddFlowInput = new AddFlowInputBuilder()
178                 .setMatch(match)
179                 .setTableId(Uint8.ONE)
180                 .setNode(noderef)
181                 .build();
182
183         doReturn(Futures.<RequestContext<Object>>immediateFailedFuture(new Exception("ut-failed-response")))
184                 .when(requestContext).getFuture();
185
186         final var rpcResultFuture = mockAddFlow(version).invoke(mockedAddFlowInput);
187
188         assertNotNull(rpcResultFuture);
189         final var addFlowOutputRpcResult = rpcResultFuture.get();
190         assertNotNull(addFlowOutputRpcResult);
191         assertFalse(addFlowOutputRpcResult.isSuccessful());
192     }
193
194     @Test
195     public void testRemoveFlowFailCallback() throws Exception {
196         removeFlowFailCallback(OFConstants.OFP_VERSION_1_0);
197     }
198
199     @Test
200     public void testRemoveFlowFailCallback1() throws Exception {
201         removeFlowFailCallback(OFConstants.OFP_VERSION_1_3);
202     }
203
204     private void removeFlowFailCallback(final Uint8 version) throws InterruptedException, ExecutionException {
205         RemoveFlowInput mockedRemoveFlowInput = new RemoveFlowInputBuilder()
206                 .setTableId(Uint8.ONE)
207                 .setMatch(match)
208                 .setNode(noderef)
209                 .build();
210
211         doReturn(Futures.<RequestContext<Object>>immediateFailedFuture(new Exception("ut-failed-response")))
212                 .when(requestContext).getFuture();
213
214         final var rpcResultFuture = mockRemoveFlow(version).invoke(mockedRemoveFlowInput);
215
216         assertNotNull(rpcResultFuture);
217         final var removeFlowOutputRpcResult = rpcResultFuture.get();
218         assertNotNull(removeFlowOutputRpcResult);
219         assertFalse(removeFlowOutputRpcResult.isSuccessful());
220     }
221
222     @Test
223     public void testAddFlowWithItemLifecycle() throws Exception {
224         addFlow(OFConstants.OFP_VERSION_1_0);
225         addFlow(OFConstants.OFP_VERSION_1_3);
226     }
227
228     private void addFlow(final Uint8 version) throws ExecutionException, InterruptedException {
229         AddFlowInput mockedAddFlowInput = new AddFlowInputBuilder()
230                 .setMatch(match)
231                 .setTableId(Uint8.ONE)
232                 .setNode(noderef)
233                 .build();
234         var addFlow = mockAddFlow(version);
235
236         verifyOutput(addFlow.invoke(mockedAddFlowInput));
237     }
238
239     @Test
240     public void testRemoveFlow() throws Exception {
241         removeFlow(OFConstants.OFP_VERSION_1_0);
242         removeFlow(OFConstants.OFP_VERSION_1_3);
243     }
244
245     @Test
246     public void testRemoveFlowWithItemLifecycle() throws Exception {
247         removeFlow(OFConstants.OFP_VERSION_1_0);
248         removeFlow(OFConstants.OFP_VERSION_1_3);
249     }
250
251     private void removeFlow(final Uint8 version) throws Exception {
252         RemoveFlowInput mockedRemoveFlowInput = new RemoveFlowInputBuilder()
253                 .setMatch(match)
254                 .setTableId(Uint8.ONE)
255                 .setNode(noderef)
256                 .build();
257
258         final var removeFlow = mockRemoveFlow(version);
259         verifyOutput(removeFlow.invoke(mockedRemoveFlowInput));
260     }
261
262     @Test
263     public void testUpdateFlow() throws Exception {
264         updateFlow(OFConstants.OFP_VERSION_1_0);
265         updateFlow(OFConstants.OFP_VERSION_1_3);
266     }
267
268     @Test
269     public void testUpdateFlowWithItemLifecycle() throws Exception {
270         updateFlow(OFConstants.OFP_VERSION_1_0);
271         updateFlow(OFConstants.OFP_VERSION_1_3);
272     }
273
274     private void updateFlow(final Uint8 version) throws Exception {
275         UpdateFlowInput mockedUpdateFlowInput = mock(UpdateFlowInput.class);
276         UpdateFlowInput mockedUpdateFlowInput1 = mock(UpdateFlowInput.class);
277
278         UpdatedFlow mockedUpdateFlow = new UpdatedFlowBuilder()
279                 .setMatch(match)
280                 .setTableId(Uint8.ONE)
281                 .build();
282
283         UpdatedFlow mockedUpdateFlow1 = new UpdatedFlowBuilder()
284                 .setMatch(match)
285                 .setTableId(Uint8.ONE)
286                 .setPriority(Uint16.ONE)
287                 .build();
288
289         when(mockedUpdateFlowInput.getUpdatedFlow()).thenReturn(mockedUpdateFlow);
290         when(mockedUpdateFlowInput1.getUpdatedFlow()).thenReturn(mockedUpdateFlow1);
291
292         FlowRef mockedFlowRef = mock(FlowRef.class);
293         doReturn(TABLE_II.child(Flow.class,
294                          new FlowKey(new FlowId(DUMMY_FLOW_ID)))).when(mockedFlowRef).getValue();
295         when(mockedUpdateFlowInput.getFlowRef()).thenReturn(mockedFlowRef);
296         when(mockedUpdateFlowInput1.getFlowRef()).thenReturn(mockedFlowRef);
297
298         OriginalFlow mockedOriginalFlow = new OriginalFlowBuilder()
299                 .setMatch(match)
300                 .setTableId(Uint8.ONE)
301                 .build();
302
303         OriginalFlow mockedOriginalFlow1 = new OriginalFlowBuilder()
304                 .setMatch(match)
305                 .setTableId(Uint8.ONE)
306                 .setPriority(Uint16.TWO)
307                 .build();
308
309         when(mockedUpdateFlowInput.getOriginalFlow()).thenReturn(mockedOriginalFlow);
310         when(mockedUpdateFlowInput1.getOriginalFlow()).thenReturn(mockedOriginalFlow1);
311
312         final var updateFlow = mockUpdateFlow(version);
313         verifyOutput(updateFlow.invoke(mockedUpdateFlowInput));
314         verifyOutput(updateFlow.invoke(mockedUpdateFlowInput1));
315     }
316
317     private static <T extends DataObject> void verifyOutput(final ListenableFuture<RpcResult<T>> rpcResultFuture)
318             throws ExecutionException, InterruptedException {
319         assertNotNull(rpcResultFuture);
320         final var addFlowOutputRpcResult = rpcResultFuture.get();
321         assertNotNull(addFlowOutputRpcResult);
322         assertTrue(addFlowOutputRpcResult.isSuccessful());
323     }
324 }