BUG-3849: Unit test failure due to timing issues
[openflowplugin.git] / openflowplugin / src / test / java / org / opendaylight / openflowplugin / openflow / md / core / ConnectionConductorImplTest.java
1 /**
2  * Copyright (c) 2013-2014 Cisco Systems, Inc. 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
9 package org.opendaylight.openflowplugin.openflow.md.core;
10
11 import static org.junit.Assert.assertNotNull;
12
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Stack;
20 import java.util.concurrent.CountDownLatch;
21 import java.util.concurrent.ScheduledThreadPoolExecutor;
22 import java.util.concurrent.TimeUnit;
23 import org.junit.After;
24 import org.junit.Assert;
25 import org.junit.Before;
26 import org.junit.Test;
27 import org.junit.runner.RunWith;
28 import org.mockito.ArgumentCaptor;
29 import org.mockito.Matchers;
30 import org.mockito.Mock;
31 import org.mockito.Mockito;
32 import org.mockito.runners.MockitoJUnitRunner;
33 import org.opendaylight.openflowplugin.api.OFConstants;
34 import org.opendaylight.openflowplugin.api.openflow.connection.HandshakeContext;
35 import org.opendaylight.openflowplugin.api.openflow.md.core.ConnectionConductor;
36 import org.opendaylight.openflowplugin.api.openflow.md.core.IMDMessageTranslator;
37 import org.opendaylight.openflowplugin.api.openflow.md.core.SwitchConnectionDistinguisher;
38 import org.opendaylight.openflowplugin.api.openflow.md.core.TranslatorKey;
39 import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext;
40 import org.opendaylight.openflowplugin.api.openflow.md.queue.PopListener;
41 import org.opendaylight.openflowplugin.api.openflow.statistics.MessageSpy;
42 import org.opendaylight.openflowplugin.openflow.md.core.plan.ConnectionAdapterStackImpl;
43 import org.opendaylight.openflowplugin.openflow.md.core.plan.EventFactory;
44 import org.opendaylight.openflowplugin.openflow.md.core.plan.SwitchTestEvent;
45 import org.opendaylight.openflowplugin.openflow.md.queue.QueueProcessorLightImpl;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.Capabilities;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortFeatures;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortFeaturesV10;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortReason;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoRequestMessageBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ErrorMessage;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ErrorMessageBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ExperimenterMessage;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowRemovedMessage;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowRemovedMessageBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutputBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloMessageBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketInMessage;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketInMessageBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatus;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessage;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessageBuilder;
64 import org.opendaylight.yangtools.yang.binding.DataContainer;
65 import org.opendaylight.yangtools.yang.binding.DataObject;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
68
69 @RunWith(MockitoJUnitRunner.class)
70 public class ConnectionConductorImplTest {
71
72     protected static final Logger LOG = LoggerFactory
73             .getLogger(ConnectionConductorImplTest.class);
74
75     /**
76      * in [ms]
77      */
78     private final int maxProcessingTimeout = 500;
79
80     protected ConnectionAdapterStackImpl adapter;
81     private ConnectionConductorImpl connectionConductor;
82     private MDController controller;
83     private Stack<SwitchTestEvent> eventPlan;
84
85     private Thread libSimulation;
86     private final ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(
87             8);
88
89     protected QueueProcessorLightImpl queueProcessor;
90
91     private PopListenerCountingImpl<DataObject> popListener;
92
93     private int experimenterMessageCounter;
94     private int packetinMessageCounter;
95     private int flowremovedMessageCounter;
96     private int portstatusAddMessageCounter;
97     private int portstatusDeleteMessageCounter;
98     private int portstatusModifyMessageCounter;
99     private int errorMessageCounter;
100
101     @Mock
102     private ErrorHandlerSimpleImpl errorHandler;
103
104     private final int expectedErrors = 0;
105     @Mock
106     private MessageSpy<DataContainer> messageSpy;
107     @Mock
108     HandshakeContext handshakeContext;
109     private ErrorMessageService objErms;
110
111     public void incrExperimenterMessageCounter() {
112         this.experimenterMessageCounter++;
113     }
114
115     public void incrPacketinMessageCounter() {
116         this.packetinMessageCounter++;
117     }
118
119     public void incrFlowremovedMessageCounter() {
120         this.flowremovedMessageCounter++;
121     }
122
123     public void incrPortstatusAddMessageCounter() {
124         this.portstatusAddMessageCounter++;
125     }
126
127     public void incrPortstatusDeleteMessageCounter() {
128         this.portstatusDeleteMessageCounter++;
129     }
130
131     public void incrPortstatusModifyMessageCounter() {
132         this.portstatusModifyMessageCounter++;
133     }
134
135     public void incrErrorMessageCounter() {
136         this.errorMessageCounter++;
137     }
138
139     @Test
140     /**
141      * Test for ConnectionConductorFactory#createConductor
142      */
143     public void testCreateConductor() {
144         ConnectionConductor connectionConductor = ConnectionConductorFactory.createConductor(adapter, queueProcessor);
145         assertNotNull(connectionConductor);
146     }
147
148     /**
149      * @throws java.lang.Exception
150      */
151     @Before
152     public void setUp() throws Exception {
153         adapter = new ConnectionAdapterStackImpl();
154
155         popListener = new PopListenerCountingImpl<>();
156
157         controller = new MDController();
158         controller.init();
159         controller.getMessageTranslators().putAll(assembleTranslatorMapping());
160
161         queueProcessor = new QueueProcessorLightImpl();
162         queueProcessor.setMessageSpy(messageSpy);
163         queueProcessor.setPopListenersMapping(assemblePopListenerMapping());
164         queueProcessor.setTranslatorMapping(controller.getMessageTranslators());
165         queueProcessor.init();
166
167         connectionConductor = new ConnectionConductorImpl(adapter);
168         connectionConductor.setQueueProcessor(queueProcessor);
169         connectionConductor.setErrorHandler(errorHandler);
170         connectionConductor.init();
171         connectionConductor.setHandshakeContext(handshakeContext);
172         eventPlan = new Stack<>();
173         adapter.setEventPlan(eventPlan);
174         adapter.setProceedTimeout(5000L);
175         adapter.checkListeners();
176     }
177
178     /**
179      * @return
180      */
181     private Map<Class<? extends DataObject>, Collection<PopListener<DataObject>>> assemblePopListenerMapping() {
182         Map<Class<? extends DataObject>, Collection<PopListener<DataObject>>> mapping = new HashMap<>();
183         Collection<PopListener<DataObject>> popListenerBag = new ArrayList<>();
184         popListenerBag.add(popListener);
185         //TODO: add testing registered types
186         mapping.put(DataObject.class, popListenerBag);
187         return mapping;
188     }
189
190     /**
191      * @throws java.lang.Exception
192      */
193     @After
194     public void tearDown() throws Exception {
195         if (libSimulation != null) {
196             libSimulation.join();
197         }
198         queueProcessor.shutdown();
199         connectionConductor.getHsPool().shutdown();
200
201         for (Exception problem : adapter.getOccuredExceptions()) {
202             LOG.error("during simulation on adapter side: "
203                     + problem.getMessage());
204         }
205         Assert.assertEquals(0, adapter.getOccuredExceptions().size());
206         adapter = null;
207         if (LOG.isDebugEnabled()) {
208             if (eventPlan.size() > 0) {
209                 LOG.debug("eventPlan size: " + eventPlan.size());
210                 for (SwitchTestEvent event : eventPlan) {
211                     LOG.debug(" # EVENT:: " + event);
212                 }
213             }
214         }
215         Assert.assertTrue("plan is not finished", eventPlan.isEmpty());
216         eventPlan = null;
217         controller = null;
218
219         // logging errors if occurred
220         ArgumentCaptor<Throwable> errorCaptor = ArgumentCaptor.forClass(Throwable.class);
221         Mockito.verify(errorHandler, Mockito.atMost(1)).handleException(
222                 errorCaptor.capture(), Matchers.any(SessionContext.class));
223         for (Throwable problem : errorCaptor.getAllValues()) {
224             LOG.warn(problem.getMessage(), problem);
225         }
226
227         Mockito.verify(errorHandler, Mockito.times(expectedErrors)).handleException(
228                 Matchers.any(Throwable.class), Matchers.any(SessionContext.class));
229     }
230
231     /**
232      * Test method for
233      * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onEchoRequestMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoRequestMessage)}
234      * .
235      *
236      * @throws Exception
237      */
238     @Test
239     public void testOnEchoRequestMessage() throws Exception {
240         simulateV13PostHandshakeState(connectionConductor);
241
242         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L,
243                 EventFactory.DEFAULT_VERSION, new EchoRequestMessageBuilder()));
244         eventPlan.add(0,
245                 EventFactory.createDefaultWaitForRpcEvent(42, "echoReply"));
246         executeNow();
247     }
248
249     /**
250      * Test of handshake, covering version negotiation and features.
251      * Switch delivers first helloMessage with default version.
252      *
253      * @throws Exception
254      */
255     @Test
256     public void testHandshake1() throws Exception {
257         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L,
258                 EventFactory.DEFAULT_VERSION, new HelloMessageBuilder()));
259         eventPlan.add(0, EventFactory.createDefaultWaitForAllEvent(
260                 EventFactory.createDefaultWaitForRpcEvent(43, "helloReply"),
261                 EventFactory.createDefaultWaitForRpcEvent(44, "getFeatures")));
262         eventPlan.add(0, EventFactory.createDefaultRpcResponseEvent(44,
263                 EventFactory.DEFAULT_VERSION, getFeatureResponseMsg()));
264
265         int i = 1;
266         eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput"));
267         eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput"));
268         executeNow();
269
270         Assert.assertEquals(ConnectionConductor.CONDUCTOR_STATE.WORKING,
271                 connectionConductor.getConductorState());
272         Assert.assertEquals((short) 0x04, connectionConductor.getVersion()
273                 .shortValue());
274     }
275
276     /**
277      * Test of handshake, covering version negotiation and features.
278      * Controller sends first helloMessage with default version
279      *
280      * @throws Exception
281      */
282     @Test
283     public void testHandshake1SwitchStarts() throws Exception {
284         eventPlan.add(0, EventFactory.createConnectionReadyCallback(connectionConductor));
285         eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(21, "helloReply"));
286         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L,
287                 EventFactory.DEFAULT_VERSION, new HelloMessageBuilder()));
288         eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(43, "getFeatures"));
289         eventPlan.add(0, EventFactory.createDefaultRpcResponseEvent(43,
290                 EventFactory.DEFAULT_VERSION, getFeatureResponseMsg()));
291
292         int i = 1;
293         eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput"));
294         eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput"));
295
296         executeNow();
297
298         Assert.assertEquals(ConnectionConductor.CONDUCTOR_STATE.WORKING,
299                 connectionConductor.getConductorState());
300         Assert.assertEquals((short) 0x04, connectionConductor.getVersion()
301                 .shortValue());
302     }
303
304     /**
305      * Test of handshake, covering version negotiation and features.
306      * Switch delivers first helloMessage with version 0x05
307      * and negotiates following versions: 0x03, 0x01
308      *
309      * @throws Exception
310      */
311     @Test
312     public void testHandshake2() throws Exception {
313         connectionConductor.setBitmapNegotiationEnable(false);
314         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L,
315                 (short) 0x05, new HelloMessageBuilder()));
316         eventPlan.add(0,
317                 EventFactory.createDefaultWaitForRpcEvent(43, "helloReply"));
318         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(43L,
319                 (short) 0x03, new HelloMessageBuilder()));
320         eventPlan.add(0,
321                 EventFactory.createDefaultWaitForRpcEvent(44, "helloReply"));
322         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(44L,
323                 (short) 0x01, new HelloMessageBuilder()));
324         eventPlan.add(0,
325                 EventFactory.createDefaultWaitForRpcEvent(45, "getFeatures"));
326
327         eventPlan.add(0, EventFactory.createDefaultRpcResponseEvent(45,
328                 (short) 0x01, getFeatureResponseMsg()));
329
330         int i = 1;
331         eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput"));
332
333         executeNow();
334
335         Assert.assertEquals(ConnectionConductor.CONDUCTOR_STATE.WORKING,
336                 connectionConductor.getConductorState());
337         Assert.assertEquals((short) 0x01, connectionConductor.getVersion()
338                 .shortValue());
339     }
340
341     /**
342      * Test of handshake, covering version negotiation and features.
343      * Controller sends first helloMessage with default version
344      * and switch negotiates following versions: 0x05, 0x03, 0x01
345      *
346      * @throws Exception
347      */
348     @Test
349     public void testHandshake2SwitchStarts() throws Exception {
350         connectionConductor.setBitmapNegotiationEnable(false);
351         eventPlan.add(0, EventFactory.createConnectionReadyCallback(connectionConductor));
352         eventPlan.add(0,
353                 EventFactory.createDefaultWaitForRpcEvent(21, "helloReply"));
354         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L,
355                 (short) 0x05, new HelloMessageBuilder()));
356         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(43L,
357                 (short) 0x03, new HelloMessageBuilder()));
358         eventPlan.add(0,
359                 EventFactory.createDefaultWaitForRpcEvent(44, "helloReply"));
360         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(44L,
361                 (short) 0x01, new HelloMessageBuilder()));
362         eventPlan.add(0,
363                 EventFactory.createDefaultWaitForRpcEvent(45, "getFeatures"));
364
365         eventPlan.add(0, EventFactory.createDefaultRpcResponseEvent(45,
366                 (short) 0x01, getFeatureResponseMsg()));
367
368         int i = 1;
369         eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(i++, "multipartRequestInput"));
370
371         executeNow();
372
373         Assert.assertEquals(ConnectionConductor.CONDUCTOR_STATE.WORKING,
374                 connectionConductor.getConductorState());
375         Assert.assertEquals((short) 0x01, connectionConductor.getVersion()
376                 .shortValue());
377     }
378
379     /**
380      * Test method for
381      * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onFlowRemovedMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowRemovedMessage)}
382      * .
383      *
384      * @throws InterruptedException
385      */
386     @Test
387     public void testOnFlowRemovedMessage() throws InterruptedException {
388         FlowRemovedMessageService objFms = new FlowRemovedMessageService();
389         controller.addMessageTranslator(FlowRemovedMessage.class, 4, objFms);
390
391         simulateV13PostHandshakeState(connectionConductor);
392         objFms.resetLatch(2);
393
394         // Now send Flow Removed messages
395         FlowRemovedMessageBuilder builder1 = new FlowRemovedMessageBuilder();
396         builder1.setVersion((short) 4);
397         builder1.setXid(1L);
398         connectionConductor.onFlowRemovedMessage(builder1.build());
399             LOG.debug("about to wait for popListener");
400         builder1.setXid(2L);
401         connectionConductor.onFlowRemovedMessage(builder1.build());
402
403         flushMessageProcessing();
404         Assert.assertTrue(objFms.await(maxProcessingTimeout, TimeUnit.MILLISECONDS));
405         Assert.assertEquals(2, flowremovedMessageCounter);
406     }
407
408     /**
409      * Test method for
410      * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onMultipartReplyMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReplyMessage)}
411      * .
412      */
413     @Test
414     public void testOnMultipartReplyMessage() {
415         // fail("Not yet implemented");
416         // TODO:: add test
417     }
418
419     /**
420      * Test method for
421      * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onPacketInMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketInMessage)}
422      * .
423      *
424      * @throws InterruptedException
425      */
426     @Test
427     public void testOnPacketInMessage() throws InterruptedException {
428         PacketInMessageService objPms = new PacketInMessageService();
429         controller.addMessageTranslator(PacketInMessage.class, 4, objPms);
430
431         simulateV13PostHandshakeState(connectionConductor);
432
433         // Now send PacketIn
434         PacketInMessageBuilder builder1 = new PacketInMessageBuilder();
435         builder1.setVersion((short) 4);
436         builder1.setBufferId((long) 1);
437         connectionConductor.onPacketInMessage(builder1.build());
438         builder1.setBufferId((long) 2);
439         connectionConductor.onPacketInMessage(builder1.build());
440
441         flushMessageProcessing();
442         Assert.assertTrue(objPms.await(maxProcessingTimeout, TimeUnit.MILLISECONDS));
443         Assert.assertEquals(2, packetinMessageCounter);
444     }
445
446     /**
447      * Test method for
448      * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onPortStatusMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessage)}
449      * .
450      *
451      * @throws InterruptedException
452      */
453     @Test
454     public void testOnPortStatusMessage() throws InterruptedException {
455         PortStatusMessageService objPSms = new PortStatusMessageService();
456         controller.addMessageTranslator(PortStatusMessage.class, 4, objPSms);
457
458         simulateV13PostHandshakeState(connectionConductor);
459
460         // Send Port Status messages
461         PortStatusMessageBuilder builder1 = new PortStatusMessageBuilder();
462         builder1.setVersion((short) 4);
463         PortFeatures features = new PortFeatures(true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false);
464         builder1.setPortNo(90L).setReason(PortReason.OFPPRADD).setCurrentFeatures(features);
465         objPSms.resetLatch(3);
466         LOG.debug("sending port message");
467         connectionConductor.onPortStatusMessage(builder1.build());
468         builder1.setPortNo(90L).setReason(PortReason.OFPPRMODIFY).setCurrentFeatures(features);
469         connectionConductor.onPortStatusMessage(builder1.build());
470         builder1.setPortNo(90L).setReason(PortReason.OFPPRDELETE).setCurrentFeatures(features);
471         connectionConductor.onPortStatusMessage(builder1.build());
472
473         flushMessageProcessing();
474         Assert.assertTrue(objPSms.await(maxProcessingTimeout, TimeUnit.MILLISECONDS));
475         Assert.assertEquals(1, portstatusModifyMessageCounter);
476         Assert.assertEquals(1, portstatusAddMessageCounter);
477         Assert.assertEquals(1, portstatusDeleteMessageCounter);
478     }
479
480     private void flushMessageProcessing() throws InterruptedException {
481         // make sure that harvester sleeps deeply
482         Thread.sleep(maxProcessingTimeout);
483         // flushing messages
484         queueProcessor.getHarvesterHandle().ping();
485     }
486
487     /**
488      * @throws InterruptedException
489      */
490     private void executeLater() throws InterruptedException {
491         execute(false);
492     }
493
494     /**
495      * @throws InterruptedException
496      */
497     private void executeNow() throws InterruptedException {
498         execute(true);
499         connectionConductor.getHsPool().shutdown();
500     }
501
502     /**
503      * @throws InterruptedException
504      */
505     private void execute(final boolean join) throws InterruptedException {
506         libSimulation = new Thread(adapter, "junit-adapter");
507         libSimulation.start();
508         if (join) {
509             libSimulation.join();
510         }
511     }
512
513     private static GetFeaturesOutputBuilder getFeatureResponseMsg() {
514         GetFeaturesOutputBuilder getFeaturesOutputBuilder = new GetFeaturesOutputBuilder();
515         getFeaturesOutputBuilder.setDatapathId(new BigInteger("102030405060"));
516         getFeaturesOutputBuilder.setAuxiliaryId((short) 0);
517         getFeaturesOutputBuilder.setBuffers(4L);
518         getFeaturesOutputBuilder.setReserved(0L);
519         getFeaturesOutputBuilder.setTables((short) 2);
520         getFeaturesOutputBuilder.setCapabilities(createCapabilities(84));
521
522         return getFeaturesOutputBuilder;
523     }
524
525     /**
526      * @return
527      */
528     private static Capabilities createCapabilities(final long input) {
529         final Boolean FLOW_STATS = (input & (1 << 0)) != 0;
530         final Boolean TABLE_STATS = (input & (1 << 1)) != 0;
531         final Boolean PORT_STATS = (input & (1 << 2)) != 0;
532         final Boolean GROUP_STATS = (input & (1 << 3)) != 0;
533         final Boolean IP_REASM = (input & (1 << 5)) != 0;
534         final Boolean QUEUE_STATS = (input & (1 << 6)) != 0;
535         final Boolean PORT_BLOCKED = (input & (1 << 8)) != 0;
536         Capabilities capabilities = new Capabilities(FLOW_STATS, GROUP_STATS, IP_REASM,
537                 PORT_BLOCKED, PORT_STATS, QUEUE_STATS, TABLE_STATS);
538         return capabilities;
539     }
540
541     public abstract class ProcessingLatchService {
542         private CountDownLatch processingLatch = new CountDownLatch(0);
543
544         public void resetLatch(int passAmount) {
545             processingLatch = new CountDownLatch(passAmount);
546         }
547
548         protected void countDown() {
549             processingLatch.countDown();
550         }
551
552         public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
553             return processingLatch.await(timeout, unit);
554         }
555     }
556
557     public class ExperimenterMessageService implements IMDMessageTranslator<OfHeader, List<DataObject>> {
558         @Override
559         public List<DataObject> translate(final SwitchConnectionDistinguisher cookie, final SessionContext sw, final OfHeader msg) {
560             LOG.debug("Received a packet in Experimenter Service");
561             ConnectionConductorImplTest.this.incrExperimenterMessageCounter();
562             return null;
563         }
564     }
565
566     public class PacketInMessageService extends ProcessingLatchService implements IMDMessageTranslator<OfHeader, List<DataObject>> {
567         @Override
568         public List<DataObject> translate(final SwitchConnectionDistinguisher cookie, final SessionContext sw, final OfHeader msg) {
569             LOG.debug("Received a packet in PacketIn Service");
570             ConnectionConductorImplTest.this.incrPacketinMessageCounter();
571             countDown();
572             return null;
573         }
574     }
575
576     public class FlowRemovedMessageService extends ProcessingLatchService implements IMDMessageTranslator<OfHeader, List<DataObject>> {
577         @Override
578         public List<DataObject> translate(final SwitchConnectionDistinguisher cookie, final SessionContext sw, final OfHeader msg) {
579             LOG.debug("Received a packet in FlowRemoved Service");
580             ConnectionConductorImplTest.this.incrFlowremovedMessageCounter();
581             countDown();
582             return null;
583         }
584     }
585
586     public class PortStatusMessageService extends ProcessingLatchService implements IMDMessageTranslator<OfHeader, List<DataObject>> {
587         @Override
588         public List<DataObject> translate(final SwitchConnectionDistinguisher cookie, final SessionContext sw, final OfHeader msg) {
589             LOG.debug("Received a packet in PortStatus Service");
590             if ((((PortStatusMessage) msg).getReason().equals(PortReason.OFPPRADD))) {
591                 ConnectionConductorImplTest.this.incrPortstatusAddMessageCounter();
592             } else if (((PortStatusMessage) msg).getReason().equals(PortReason.OFPPRDELETE)) {
593                 ConnectionConductorImplTest.this.incrPortstatusDeleteMessageCounter();
594             } else if (((PortStatusMessage) msg).getReason().equals(PortReason.OFPPRMODIFY)) {
595                 ConnectionConductorImplTest.this.incrPortstatusModifyMessageCounter();
596             }
597             countDown();
598             return null;
599         }
600     }
601
602     public class ErrorMessageService extends ProcessingLatchService implements IMDMessageTranslator<OfHeader, List<DataObject>> {
603         @Override
604         public List<DataObject> translate(final SwitchConnectionDistinguisher cookie, final SessionContext sw, final OfHeader msg) {
605             LOG.debug("Received a packet in Experimenter Service");
606             ConnectionConductorImplTest.this.incrErrorMessageCounter();
607             countDown();
608             return null;
609         }
610     }
611
612     /**
613      * Test method for
614      * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onExperimenterMessage(ExperimenterMessage)}
615      * .
616      *
617      * @throws InterruptedException
618      */
619     @Test
620     public void testOnErrorMessage() throws InterruptedException {
621         simulateV13PostHandshakeState(connectionConductor);
622         final int messageAmount = 2;
623
624         objErms.resetLatch(messageAmount);
625         ErrorMessageBuilder builder1 = new ErrorMessageBuilder();
626         builder1.setVersion((short) 4);
627         builder1.setCode(100);
628         connectionConductor.onErrorMessage(builder1.build());
629         builder1.setCode(200);
630         connectionConductor.onErrorMessage(builder1.build());
631
632         flushMessageProcessing();
633         Assert.assertTrue(objErms.await(maxProcessingTimeout, TimeUnit.MILLISECONDS));
634         Assert.assertEquals(messageAmount, errorMessageCounter);
635     }
636
637     /**
638      * @return listener mapping for:
639      * <ul>
640      * <li>experimenter</li>
641      * <li>error</li>
642      * </ul>
643      */
644     private Map<TranslatorKey, Collection<IMDMessageTranslator<OfHeader, List<DataObject>>>> assembleTranslatorMapping() {
645         Map<TranslatorKey, Collection<IMDMessageTranslator<OfHeader, List<DataObject>>>> translatorMapping = new HashMap<>();
646         TranslatorKey tKey;
647
648         IMDMessageTranslator<OfHeader, List<DataObject>> objEms = new ExperimenterMessageService();
649         Collection<IMDMessageTranslator<OfHeader, List<DataObject>>> existingValues = new ArrayList<>();
650         existingValues.add(objEms);
651         tKey = new TranslatorKey(4, ExperimenterMessage.class.getName());
652         translatorMapping.put(tKey, existingValues);
653         objErms = new ErrorMessageService();
654         existingValues.add(objErms);
655         tKey = new TranslatorKey(4, ErrorMessage.class.getName());
656         translatorMapping.put(tKey, existingValues);
657         return translatorMapping;
658     }
659
660     /**
661      * Test method for
662      * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#processPortStatusMsg(PortStatus)}
663      * <br><br>
664      * Tests for getting features from port status message by port version
665      * <ul>
666      * <li>features are malformed - one of them is null</li>
667      * <li>mismatch between port version and port features</li>
668      * <li>mismatch between port version and port features</li>
669      * <li>non-existing port version</li>
670      * <li>port version OF 1.0</li>
671      * <li>port version OF 1.3</li>
672      * </ul>
673      */
674     @Test
675     public void testProcessPortStatusMsg() {
676         simulateV13PostHandshakeState(connectionConductor);
677
678         long portNumber = 90L;
679         long portNumberV10 = 91L;
680         PortStatusMessage msg;
681
682         PortStatusMessageBuilder builder = new PortStatusMessageBuilder();
683         PortFeatures features = new PortFeatures(true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false);
684         PortFeatures featuresMal = new PortFeatures(true, false, false, false, null, false, false, false, false, false, false, false, false, false, false, false);
685         PortFeaturesV10 featuresV10 = new PortFeaturesV10(true, false, false, false, false, false, false, false, false, false, false, false);
686
687         //Malformed features
688         builder.setVersion((short) 1).setPortNo(portNumber).setReason(PortReason.OFPPRADD).setCurrentFeatures(featuresMal);
689         connectionConductor.processPortStatusMsg(builder.build());
690         Assert.assertTrue(connectionConductor.getSessionContext().getPortsBandwidth().isEmpty());
691         Assert.assertTrue(connectionConductor.getSessionContext().getPhysicalPorts().isEmpty());
692
693         //Version-features mismatch
694         builder.setCurrentFeatures(features);
695         connectionConductor.processPortStatusMsg(builder.build());
696         Assert.assertTrue(connectionConductor.getSessionContext().getPortsBandwidth().isEmpty());
697         Assert.assertTrue(connectionConductor.getSessionContext().getPhysicalPorts().isEmpty());
698
699         //Non existing version
700         builder.setVersion((short) 0);
701         connectionConductor.processPortStatusMsg(builder.build());
702         Assert.assertTrue(connectionConductor.getSessionContext().getPortsBandwidth().isEmpty());
703         Assert.assertTrue(connectionConductor.getSessionContext().getPhysicalPorts().isEmpty());
704
705         //Version OF 1.3
706         builder.setVersion((short) 4);
707         msg = builder.build();
708         connectionConductor.processPortStatusMsg(builder.build());
709         Assert.assertTrue(connectionConductor.getSessionContext().getPortBandwidth(portNumber));
710         Assert.assertEquals(connectionConductor.getSessionContext().getPhysicalPort(portNumber), msg);
711
712         //Version OF 1.0
713         builder.setVersion((short) 1).setPortNo(portNumberV10).setCurrentFeatures(null).setCurrentFeaturesV10(featuresV10);
714         msg = builder.build();
715         connectionConductor.processPortStatusMsg(builder.build());
716         Assert.assertTrue(connectionConductor.getSessionContext().getPortBandwidth(portNumberV10));
717         Assert.assertEquals(connectionConductor.getSessionContext().getPhysicalPort(portNumberV10), msg);
718     }
719
720
721     @Test
722     public void testHandshakeFailOperations(){
723         connectionConductor.onHandshakeFailure();
724         connectionConductor.checkState(ConnectionConductor.CONDUCTOR_STATE.RIP);
725     }
726     private static void simulateV13PostHandshakeState(final ConnectionConductorImpl conductor) {
727         GetFeaturesOutputBuilder featureOutput = getFeatureResponseMsg();
728         conductor.postHandshakeBasic(featureOutput.build(), OFConstants.OFP_VERSION_1_3);
729         LOG.debug("simulating post handshake event done");
730     }
731 }