Make sure RequestContext has a constant XID
[openflowplugin.git] / openflowplugin-impl / src / test / java / org / opendaylight / openflowplugin / impl / device / DeviceContextImplTest.java
1 package org.opendaylight.openflowplugin.impl.device;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.fail;
5 import static org.mockito.Matchers.any;
6 import com.google.common.util.concurrent.SettableFuture;
7 import io.netty.util.HashedWheelTimer;
8 import java.util.ArrayList;
9 import java.util.Collections;
10 import java.util.List;
11 import java.util.concurrent.ExecutionException;
12 import java.util.concurrent.TimeUnit;
13 import java.util.concurrent.TimeoutException;
14 import java.util.concurrent.atomic.AtomicLong;
15 import org.junit.Assert;
16 import org.junit.Before;
17 import org.junit.Test;
18 import org.junit.runner.RunWith;
19 import org.mockito.Mock;
20 import org.mockito.Mockito;
21 import org.mockito.invocation.InvocationOnMock;
22 import org.mockito.runners.MockitoJUnitRunner;
23 import org.mockito.stubbing.Answer;
24 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
27 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
28 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
29 import org.opendaylight.openflowplugin.api.OFConstants;
30 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
31 import org.opendaylight.openflowplugin.api.openflow.connection.OutboundQueueProvider;
32 import org.opendaylight.openflowplugin.api.openflow.connection.ThrottledNotificationsOfferer;
33 import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
34 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
35 import org.opendaylight.openflowplugin.api.openflow.device.Xid;
36 import org.opendaylight.openflowplugin.api.openflow.device.exception.DeviceDataException;
37 import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageIntelligenceAgency;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartRequestFlags;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.Error;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ErrorMessageBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetAsyncOutput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetAsyncOutputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetAsyncReply;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReplyMessageBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.async.body.grouping.FlowRemovedMask;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.async.body.grouping.PacketInMask;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.async.body.grouping.PortStatusMask;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyDescCase;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyDescCaseBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.desc._case.MultipartReplyDesc;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.desc._case.MultipartReplyDescBuilder;
54 import org.opendaylight.yangtools.yang.common.RpcError;
55 import org.opendaylight.yangtools.yang.common.RpcResult;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 @RunWith(MockitoJUnitRunner.class)
60 public class DeviceContextImplTest {
61     private static final Logger LOG = LoggerFactory
62             .getLogger(DeviceContextImplTest.class);
63     Xid xid;
64     Xid xidMulti;
65     DeviceContextImpl deviceContext;
66     TransactionChainManager txChainManager;
67     @Mock
68     RequestContext<GetAsyncReply> requestContext;
69     @Mock
70     RequestContext<MultipartReply> requestContextMultiReply;
71
72     @Mock
73     ConnectionContext connectionContext;
74     @Mock
75     DeviceState deviceState;
76     @Mock
77     DataBroker dataBroker;
78     @Mock
79     WriteTransaction wTx;
80     @Mock
81     ReadOnlyTransaction rTx;
82     @Mock
83     BindingTransactionChain txChainFactory;
84     @Mock
85     HashedWheelTimer timer;
86     @Mock
87     MessageIntelligenceAgency messageIntelligenceAgency;
88     @Mock
89     ThrottledNotificationsOfferer throttledConnectionsHolder;
90     @Mock
91     OutboundQueueProvider outboundQueueProvider;
92
93     private final AtomicLong atomicLong = new AtomicLong(0);
94     @Before
95     public void setUp() {
96         Mockito.when(dataBroker.createTransactionChain(Mockito.any(TransactionChainManager.class))).thenReturn(txChainFactory);
97         txChainManager = new TransactionChainManager(dataBroker, timer, 5L, 5L);
98         final SettableFuture<RpcResult<GetAsyncReply>> settableFuture = SettableFuture.create();
99         final SettableFuture<RpcResult<MultipartReply>> settableFutureMultiReply = SettableFuture.create();
100         Mockito.when(requestContext.getFuture()).thenReturn(settableFuture);
101         Mockito.doAnswer(new Answer<Object>() {
102             @SuppressWarnings("unchecked")
103             @Override
104             public Object answer(final InvocationOnMock invocation) {
105                 settableFuture.set((RpcResult<GetAsyncReply>) invocation.getArguments()[0]);
106                 return null;
107             }
108         }).when(requestContext).setResult(any(RpcResult.class));
109
110         Mockito.when(requestContextMultiReply.getFuture()).thenReturn(settableFutureMultiReply);
111         Mockito.doAnswer(new Answer<Object>() {
112             @SuppressWarnings("unchecked")
113             @Override
114             public Object answer(final InvocationOnMock invocation) {
115                 settableFutureMultiReply.set((RpcResult<MultipartReply>) invocation.getArguments()[0]);
116                 return null;
117             }
118         }).when(requestContextMultiReply).setResult(any(RpcResult.class));
119         Mockito.when(txChainFactory.newWriteOnlyTransaction()).thenReturn(wTx);
120         Mockito.when(dataBroker.newReadOnlyTransaction()).thenReturn(rTx);
121         Mockito.when(connectionContext.getOutboundQueueProvider()).thenReturn(outboundQueueProvider);
122         deviceContext = new DeviceContextImpl(connectionContext, deviceState, dataBroker, timer, messageIntelligenceAgency,throttledConnectionsHolder);
123
124         xid = new Xid(atomicLong.incrementAndGet());
125         xidMulti = new Xid(atomicLong.incrementAndGet());
126     }
127
128     @Test(expected = NullPointerException.class)
129     public void testDeviceContextImplConstructorNullConnectionContext() {
130         new DeviceContextImpl(null, deviceState, dataBroker, timer, messageIntelligenceAgency,throttledConnectionsHolder);
131     }
132
133     @Test(expected = NullPointerException.class)
134     public void testDeviceContextImplConstructorNullDataBroker() {
135         new DeviceContextImpl(connectionContext, deviceState, null, timer, messageIntelligenceAgency,throttledConnectionsHolder);
136     }
137
138     @Test(expected = NullPointerException.class)
139     public void testDeviceContextImplConstructorNullDeviceState() {
140         new DeviceContextImpl(connectionContext, null, dataBroker, timer, messageIntelligenceAgency,throttledConnectionsHolder);
141     }
142
143     @Test(expected = NullPointerException.class)
144     public void testDeviceContextImplConstructorNullTimer() {
145         new DeviceContextImpl(null, deviceState, dataBroker, null, messageIntelligenceAgency,throttledConnectionsHolder);
146     }
147
148     @Test
149     public void testGetDeviceState() {
150         final DeviceState deviceSt = deviceContext.getDeviceState();
151         Assert.assertNotNull(deviceSt);
152         Assert.assertEquals(deviceState, deviceSt);
153     }
154
155     @Test
156     public void testGetReadTransaction() {
157         final ReadTransaction readTx = deviceContext.getReadTransaction();
158         Assert.assertNotNull(readTx);
159         Assert.assertEquals(rTx, readTx);
160     }
161
162     private static GetAsyncOutput createAsyncOutput(final Xid xid) {
163         final GetAsyncOutputBuilder asyncOutputBuilder = new GetAsyncOutputBuilder();
164         asyncOutputBuilder.setFlowRemovedMask(Collections.<FlowRemovedMask>emptyList());
165         asyncOutputBuilder.setPacketInMask(Collections.<PacketInMask>emptyList());
166         asyncOutputBuilder.setPortStatusMask(Collections.<PortStatusMask>emptyList());
167         asyncOutputBuilder.setVersion(OFConstants.OFP_VERSION_1_3);
168         asyncOutputBuilder.setXid(xid.getValue());
169         return asyncOutputBuilder.build();
170     }
171
172     @Test
173     public void testProcessReply() {
174         final GetAsyncOutput asyncOutput = createAsyncOutput(xid);
175         LOG.info("Hooking RequestContext");
176         deviceContext.hookRequestCtx(xid, requestContext);
177         Assert.assertEquals(requestContext, deviceContext.lookupRequest(xid));
178
179         Assert.assertFalse(requestContext.getFuture().isDone());
180         LOG.info("Sending reply from device");
181         deviceContext.processReply(asyncOutput);
182         Assert.assertTrue(requestContext.getFuture().isDone());
183
184         LOG.info("Checking RequestContext.future");
185         try {
186             final Object object = requestContext.getFuture().get(1L, TimeUnit.SECONDS);
187             final RpcResult<OfHeader> rpcResult = (RpcResult<OfHeader>) object;
188             final GetAsyncOutput getAsyncOutput = (GetAsyncOutput) rpcResult.getResult();
189             assertEquals(asyncOutput.getVersion(), getAsyncOutput.getVersion());
190         } catch (InterruptedException | ExecutionException | TimeoutException e) {
191             LOG.error("Test failed when checking RequestContext.future", e);
192             fail("fail");
193         }
194         Assert.assertTrue(deviceContext.getNumberOfOutstandingRequests() == 0);
195     }
196
197     private static Error createError(final Xid xid) {
198         final ErrorMessageBuilder errorMessageBuilder = new ErrorMessageBuilder();
199         errorMessageBuilder.setCode(42);
200         errorMessageBuilder.setCodeString("42");
201         errorMessageBuilder.setXid(xid.getValue());
202         return errorMessageBuilder.build();
203     }
204
205     @Test
206     public void testProcessReplyError() {
207         LOG.info("Hooking RequestContext");
208         deviceContext.hookRequestCtx(xid, requestContext);
209         Assert.assertEquals(requestContext, deviceContext.lookupRequest(xid));
210
211         Assert.assertFalse(requestContext.getFuture().isDone());
212         LOG.info("Sending error reply from device");
213         final Error error = createError(xid);
214         deviceContext.processReply(error);
215         Assert.assertTrue(requestContext.getFuture().isDone());
216
217         LOG.info("Checking RequestContext.future");
218         try {
219             final Object object = requestContext.getFuture().get(1L, TimeUnit.SECONDS);
220             final RpcResult<OfHeader> rpcResult = (RpcResult<OfHeader>) object;
221             Assert.assertFalse(rpcResult.isSuccessful());
222             final List<RpcError> errors = (List<RpcError>) rpcResult.getErrors();
223             Assert.assertTrue(errors.get(0).getCause() instanceof DeviceDataException);
224             final DeviceDataException cause = (DeviceDataException) errors.get(0).getCause();
225             Assert.assertEquals(error, cause.getError());
226         } catch (InterruptedException | ExecutionException | TimeoutException e) {
227             LOG.error("Test failed when checking RequestContext.future", e);
228             fail("fail");
229         }
230         Assert.assertTrue(deviceContext.getNumberOfOutstandingRequests() == 0);
231     }
232
233     @Test
234     public void testProcessReplyList() {
235         LOG.info("Hooking RequestContext");
236         deviceContext.hookRequestCtx(xidMulti, requestContextMultiReply);
237         Assert.assertEquals(requestContextMultiReply, deviceContext.lookupRequest(xidMulti));
238
239         Assert.assertFalse(requestContextMultiReply.getFuture().isDone());
240         LOG.info("Sending reply from device");
241         deviceContext.processReply(xidMulti, createMultipartReplyList(xidMulti));
242         Assert.assertTrue(requestContextMultiReply.getFuture().isDone());
243
244         LOG.info("Checking RequestContext.future");
245         try {
246             final Object object = requestContextMultiReply.getFuture().get(1L, TimeUnit.SECONDS);
247             final RpcResult<List<OfHeader>> rpcResult = (RpcResult<List<OfHeader>>) object;
248             final List<OfHeader> multipartReplies = rpcResult.getResult();
249             final List<MultipartReply> expectedMpReplies = createMultipartReplyList(xidMulti);
250             assertEquals(expectedMpReplies, multipartReplies);
251         } catch (InterruptedException | ExecutionException | TimeoutException e) {
252             LOG.error("Test failed when checking RequestContext.future", e);
253             fail("fail");
254         }
255         Assert.assertTrue(deviceContext.getNumberOfOutstandingRequests() == 0);
256     }
257
258     private static List<MultipartReply> createMultipartReplyList(final Xid xid) {
259         final MultipartReplyDesc descValue = new MultipartReplyDescBuilder().setHwDesc("hw-test-value").build();
260         final MultipartReplyDescCase replyBody = new MultipartReplyDescCaseBuilder()
261                 .setMultipartReplyDesc(descValue).build();
262         final List<MultipartReply> multipartReplies = new ArrayList<>();
263         multipartReplies.add(new MultipartReplyMessageBuilder()
264                 .setMultipartReplyBody(replyBody)
265                 .setXid(xid.getValue())
266                 .setFlags(new MultipartRequestFlags(false))
267                 .build());
268         multipartReplies.add(new MultipartReplyMessageBuilder()
269                 .setMultipartReplyBody(replyBody)
270                 .setXid(xid.getValue())
271                 .setFlags(new MultipartRequestFlags(true))
272                 .build());
273         return multipartReplies;
274     }
275
276     @Test
277     public void testProcessException() {
278         LOG.info("Hooking RequestContext");
279         deviceContext.hookRequestCtx(xid, requestContext);
280         Assert.assertEquals(requestContext, deviceContext.lookupRequest(xid));
281
282         Assert.assertFalse(requestContext.getFuture().isDone());
283
284         LOG.info("Sending reply from device");
285         deviceContext.processException(xid, new DeviceDataException("Some freakin' error", new NullPointerException()));
286         Assert.assertTrue(requestContext.getFuture().isDone());
287
288         LOG.info("Checking RequestContext.future");
289         try {
290             final Object object = requestContext.getFuture().get(1L, TimeUnit.SECONDS);
291             final RpcResult<OfHeader> rpcResult = (RpcResult<OfHeader>) object;
292             Assert.assertFalse(rpcResult.isSuccessful());
293             final List<RpcError> errors = (List<RpcError>) rpcResult.getErrors();
294             Assert.assertTrue(errors.get(0).getCause() instanceof DeviceDataException);
295             final DeviceDataException cause = (DeviceDataException) errors.get(0).getCause();
296             Assert.assertTrue(cause.getCause() instanceof NullPointerException);
297         } catch (InterruptedException | ExecutionException | TimeoutException e) {
298             LOG.error("Test failed when checking RequestContext.future", e);
299             fail("fail");
300         }
301         Assert.assertTrue(deviceContext.getNumberOfOutstandingRequests() == 0);
302     }
303
304 }