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