1 package org.opendaylight.openflowplugin.impl.device;
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;
59 @RunWith(MockitoJUnitRunner.class)
60 public class DeviceContextImplTest {
61 private static final Logger LOG = LoggerFactory
62 .getLogger(DeviceContextImplTest.class);
65 DeviceContextImpl deviceContext;
66 TransactionChainManager txChainManager;
68 RequestContext<GetAsyncReply> requestContext;
70 RequestContext<MultipartReply> requestContextMultiReply;
73 ConnectionContext connectionContext;
75 DeviceState deviceState;
77 DataBroker dataBroker;
81 ReadOnlyTransaction rTx;
83 BindingTransactionChain txChainFactory;
85 HashedWheelTimer timer;
87 MessageIntelligenceAgency messageIntelligenceAgency;
89 ThrottledNotificationsOfferer throttledConnectionsHolder;
91 OutboundQueueProvider outboundQueueProvider;
93 private final AtomicLong atomicLong = new AtomicLong(0);
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")
104 public Object answer(final InvocationOnMock invocation) {
105 settableFuture.set((RpcResult<GetAsyncReply>) invocation.getArguments()[0]);
108 }).when(requestContext).setResult(any(RpcResult.class));
110 Mockito.when(requestContextMultiReply.getFuture()).thenReturn(settableFutureMultiReply);
111 Mockito.doAnswer(new Answer<Object>() {
112 @SuppressWarnings("unchecked")
114 public Object answer(final InvocationOnMock invocation) {
115 settableFutureMultiReply.set((RpcResult<MultipartReply>) invocation.getArguments()[0]);
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);
124 xid = new Xid(atomicLong.incrementAndGet());
125 xidMulti = new Xid(atomicLong.incrementAndGet());
128 @Test(expected = NullPointerException.class)
129 public void testDeviceContextImplConstructorNullConnectionContext() {
130 new DeviceContextImpl(null, deviceState, dataBroker, timer, messageIntelligenceAgency,throttledConnectionsHolder);
133 @Test(expected = NullPointerException.class)
134 public void testDeviceContextImplConstructorNullDataBroker() {
135 new DeviceContextImpl(connectionContext, deviceState, null, timer, messageIntelligenceAgency,throttledConnectionsHolder);
138 @Test(expected = NullPointerException.class)
139 public void testDeviceContextImplConstructorNullDeviceState() {
140 new DeviceContextImpl(connectionContext, null, dataBroker, timer, messageIntelligenceAgency,throttledConnectionsHolder);
143 @Test(expected = NullPointerException.class)
144 public void testDeviceContextImplConstructorNullTimer() {
145 new DeviceContextImpl(null, deviceState, dataBroker, null, messageIntelligenceAgency,throttledConnectionsHolder);
149 public void testGetDeviceState() {
150 final DeviceState deviceSt = deviceContext.getDeviceState();
151 Assert.assertNotNull(deviceSt);
152 Assert.assertEquals(deviceState, deviceSt);
156 public void testGetReadTransaction() {
157 final ReadTransaction readTx = deviceContext.getReadTransaction();
158 Assert.assertNotNull(readTx);
159 Assert.assertEquals(rTx, readTx);
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();
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));
179 Assert.assertFalse(requestContext.getFuture().isDone());
180 LOG.info("Sending reply from device");
181 deviceContext.processReply(asyncOutput);
182 Assert.assertTrue(requestContext.getFuture().isDone());
184 LOG.info("Checking RequestContext.future");
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);
194 Assert.assertTrue(deviceContext.getNumberOfOutstandingRequests() == 0);
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();
206 public void testProcessReplyError() {
207 LOG.info("Hooking RequestContext");
208 deviceContext.hookRequestCtx(xid, requestContext);
209 Assert.assertEquals(requestContext, deviceContext.lookupRequest(xid));
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());
217 LOG.info("Checking RequestContext.future");
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);
230 Assert.assertTrue(deviceContext.getNumberOfOutstandingRequests() == 0);
234 public void testProcessReplyList() {
235 LOG.info("Hooking RequestContext");
236 deviceContext.hookRequestCtx(xidMulti, requestContextMultiReply);
237 Assert.assertEquals(requestContextMultiReply, deviceContext.lookupRequest(xidMulti));
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());
244 LOG.info("Checking RequestContext.future");
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);
255 Assert.assertTrue(deviceContext.getNumberOfOutstandingRequests() == 0);
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))
268 multipartReplies.add(new MultipartReplyMessageBuilder()
269 .setMultipartReplyBody(replyBody)
270 .setXid(xid.getValue())
271 .setFlags(new MultipartRequestFlags(true))
273 return multipartReplies;
277 public void testProcessException() {
278 LOG.info("Hooking RequestContext");
279 deviceContext.hookRequestCtx(xid, requestContext);
280 Assert.assertEquals(requestContext, deviceContext.lookupRequest(xid));
282 Assert.assertFalse(requestContext.getFuture().isDone());
284 LOG.info("Sending reply from device");
285 deviceContext.processException(xid, new DeviceDataException("Some freakin' error", new NullPointerException()));
286 Assert.assertTrue(requestContext.getFuture().isDone());
288 LOG.info("Checking RequestContext.future");
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);
301 Assert.assertTrue(deviceContext.getNumberOfOutstandingRequests() == 0);