36e4dec0495aa748f03fb10e87903408eb07ee66
[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         executeNow();
267
268         Assert.assertEquals(ConnectionConductor.CONDUCTOR_STATE.WORKING,
269                 connectionConductor.getConductorState());
270         Assert.assertEquals((short) 0x04, connectionConductor.getVersion()
271                 .shortValue());
272     }
273
274     /**
275      * Test of handshake, covering version negotiation and features.
276      * Controller sends first helloMessage with default version
277      *
278      * @throws Exception
279      */
280     @Test
281     public void testHandshake1SwitchStarts() throws Exception {
282         eventPlan.add(0, EventFactory.createConnectionReadyCallback(connectionConductor));
283         eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(21, "helloReply"));
284         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L,
285                 EventFactory.DEFAULT_VERSION, new HelloMessageBuilder()));
286         eventPlan.add(0, EventFactory.createDefaultWaitForRpcEvent(43, "getFeatures"));
287         eventPlan.add(0, EventFactory.createDefaultRpcResponseEvent(43,
288                 EventFactory.DEFAULT_VERSION, getFeatureResponseMsg()));
289
290         executeNow();
291
292         Assert.assertEquals(ConnectionConductor.CONDUCTOR_STATE.WORKING,
293                 connectionConductor.getConductorState());
294         Assert.assertEquals((short) 0x04, connectionConductor.getVersion()
295                 .shortValue());
296     }
297
298     /**
299      * Test of handshake, covering version negotiation and features.
300      * Switch delivers first helloMessage with version 0x05
301      * and negotiates following versions: 0x03, 0x01
302      *
303      * @throws Exception
304      */
305     @Test
306     public void testHandshake2() throws Exception {
307         connectionConductor.setBitmapNegotiationEnable(false);
308         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L,
309                 (short) 0x05, new HelloMessageBuilder()));
310         eventPlan.add(0,
311                 EventFactory.createDefaultWaitForRpcEvent(43, "helloReply"));
312         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(43L,
313                 (short) 0x03, new HelloMessageBuilder()));
314         eventPlan.add(0,
315                 EventFactory.createDefaultWaitForRpcEvent(44, "helloReply"));
316         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(44L,
317                 (short) 0x01, new HelloMessageBuilder()));
318         eventPlan.add(0,
319                 EventFactory.createDefaultWaitForRpcEvent(45, "getFeatures"));
320
321         eventPlan.add(0, EventFactory.createDefaultRpcResponseEvent(45,
322                 (short) 0x01, getFeatureResponseMsg()));
323
324         executeNow();
325
326         Assert.assertEquals(ConnectionConductor.CONDUCTOR_STATE.WORKING,
327                 connectionConductor.getConductorState());
328         Assert.assertEquals((short) 0x01, connectionConductor.getVersion()
329                 .shortValue());
330     }
331
332     /**
333      * Test of handshake, covering version negotiation and features.
334      * Controller sends first helloMessage with default version
335      * and switch negotiates following versions: 0x05, 0x03, 0x01
336      *
337      * @throws Exception
338      */
339     @Test
340     public void testHandshake2SwitchStarts() throws Exception {
341         connectionConductor.setBitmapNegotiationEnable(false);
342         eventPlan.add(0, EventFactory.createConnectionReadyCallback(connectionConductor));
343         eventPlan.add(0,
344                 EventFactory.createDefaultWaitForRpcEvent(21, "helloReply"));
345         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(42L,
346                 (short) 0x05, new HelloMessageBuilder()));
347         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(43L,
348                 (short) 0x03, new HelloMessageBuilder()));
349         eventPlan.add(0,
350                 EventFactory.createDefaultWaitForRpcEvent(44, "helloReply"));
351         eventPlan.add(0, EventFactory.createDefaultNotificationEvent(44L,
352                 (short) 0x01, new HelloMessageBuilder()));
353         eventPlan.add(0,
354                 EventFactory.createDefaultWaitForRpcEvent(45, "getFeatures"));
355
356         eventPlan.add(0, EventFactory.createDefaultRpcResponseEvent(45,
357                 (short) 0x01, getFeatureResponseMsg()));
358
359         executeNow();
360
361         Assert.assertEquals(ConnectionConductor.CONDUCTOR_STATE.WORKING,
362                 connectionConductor.getConductorState());
363         Assert.assertEquals((short) 0x01, connectionConductor.getVersion()
364                 .shortValue());
365     }
366
367     /**
368      * Test method for
369      * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onFlowRemovedMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowRemovedMessage)}
370      * .
371      *
372      * @throws InterruptedException
373      */
374     @Test
375     public void testOnFlowRemovedMessage() throws InterruptedException {
376         FlowRemovedMessageService objFms = new FlowRemovedMessageService();
377         controller.addMessageTranslator(FlowRemovedMessage.class, 4, objFms);
378
379         simulateV13PostHandshakeState(connectionConductor);
380         objFms.resetLatch(2);
381
382         // Now send Flow Removed messages
383         FlowRemovedMessageBuilder builder1 = new FlowRemovedMessageBuilder();
384         builder1.setVersion((short) 4);
385         builder1.setXid(1L);
386         connectionConductor.onFlowRemovedMessage(builder1.build());
387             LOG.debug("about to wait for popListener");
388         builder1.setXid(2L);
389         connectionConductor.onFlowRemovedMessage(builder1.build());
390
391         flushMessageProcessing();
392         Assert.assertTrue(objFms.await(maxProcessingTimeout, TimeUnit.MILLISECONDS));
393         Assert.assertEquals(2, flowremovedMessageCounter);
394     }
395
396     /**
397      * Test method for
398      * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onMultipartReplyMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReplyMessage)}
399      * .
400      */
401     @Test
402     public void testOnMultipartReplyMessage() {
403         // fail("Not yet implemented");
404         // TODO:: add test
405     }
406
407     /**
408      * Test method for
409      * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onPacketInMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketInMessage)}
410      * .
411      *
412      * @throws InterruptedException
413      */
414     @Test
415     public void testOnPacketInMessage() throws InterruptedException {
416         PacketInMessageService objPms = new PacketInMessageService();
417         controller.addMessageTranslator(PacketInMessage.class, 4, objPms);
418
419         simulateV13PostHandshakeState(connectionConductor);
420
421         // Now send PacketIn
422         PacketInMessageBuilder builder1 = new PacketInMessageBuilder();
423         builder1.setVersion((short) 4);
424         builder1.setBufferId((long) 1);
425         connectionConductor.onPacketInMessage(builder1.build());
426         builder1.setBufferId((long) 2);
427         connectionConductor.onPacketInMessage(builder1.build());
428
429         flushMessageProcessing();
430         Assert.assertTrue(objPms.await(maxProcessingTimeout, TimeUnit.MILLISECONDS));
431         Assert.assertEquals(2, packetinMessageCounter);
432     }
433
434     /**
435      * Test method for
436      * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onPortStatusMessage(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessage)}
437      * .
438      *
439      * @throws InterruptedException
440      */
441     @Test
442     public void testOnPortStatusMessage() throws InterruptedException {
443         PortStatusMessageService objPSms = new PortStatusMessageService();
444         controller.addMessageTranslator(PortStatusMessage.class, 4, objPSms);
445
446         simulateV13PostHandshakeState(connectionConductor);
447
448         // Send Port Status messages
449         PortStatusMessageBuilder builder1 = new PortStatusMessageBuilder();
450         builder1.setVersion((short) 4);
451         PortFeatures features = new PortFeatures(true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false);
452         builder1.setPortNo(90L).setReason(PortReason.OFPPRADD).setCurrentFeatures(features);
453         objPSms.resetLatch(3);
454         LOG.debug("sending port message");
455         connectionConductor.onPortStatusMessage(builder1.build());
456         builder1.setPortNo(90L).setReason(PortReason.OFPPRMODIFY).setCurrentFeatures(features);
457         connectionConductor.onPortStatusMessage(builder1.build());
458         builder1.setPortNo(90L).setReason(PortReason.OFPPRDELETE).setCurrentFeatures(features);
459         connectionConductor.onPortStatusMessage(builder1.build());
460
461         flushMessageProcessing();
462         Assert.assertTrue(objPSms.await(maxProcessingTimeout, TimeUnit.MILLISECONDS));
463         Assert.assertEquals(1, portstatusModifyMessageCounter);
464         Assert.assertEquals(1, portstatusAddMessageCounter);
465         Assert.assertEquals(1, portstatusDeleteMessageCounter);
466     }
467
468     private void flushMessageProcessing() throws InterruptedException {
469         // make sure that harvester sleeps deeply
470         Thread.sleep(maxProcessingTimeout);
471         // flushing messages
472         queueProcessor.getHarvesterHandle().ping();
473     }
474
475     /**
476      * @throws InterruptedException
477      */
478     private void executeLater() throws InterruptedException {
479         execute(false);
480     }
481
482     /**
483      * @throws InterruptedException
484      */
485     private void executeNow() throws InterruptedException {
486         execute(true);
487         connectionConductor.getHsPool().shutdown();
488     }
489
490     /**
491      * @throws InterruptedException
492      */
493     private void execute(final boolean join) throws InterruptedException {
494         libSimulation = new Thread(adapter, "junit-adapter");
495         libSimulation.start();
496         if (join) {
497             libSimulation.join();
498         }
499     }
500
501     private static GetFeaturesOutputBuilder getFeatureResponseMsg() {
502         GetFeaturesOutputBuilder getFeaturesOutputBuilder = new GetFeaturesOutputBuilder();
503         getFeaturesOutputBuilder.setDatapathId(new BigInteger("102030405060"));
504         getFeaturesOutputBuilder.setAuxiliaryId((short) 0);
505         getFeaturesOutputBuilder.setBuffers(4L);
506         getFeaturesOutputBuilder.setReserved(0L);
507         getFeaturesOutputBuilder.setTables((short) 2);
508         getFeaturesOutputBuilder.setCapabilities(createCapabilities(84));
509
510         return getFeaturesOutputBuilder;
511     }
512
513     /**
514      * @return
515      */
516     private static Capabilities createCapabilities(final long input) {
517         final Boolean FLOW_STATS = (input & (1 << 0)) != 0;
518         final Boolean TABLE_STATS = (input & (1 << 1)) != 0;
519         final Boolean PORT_STATS = (input & (1 << 2)) != 0;
520         final Boolean GROUP_STATS = (input & (1 << 3)) != 0;
521         final Boolean IP_REASM = (input & (1 << 5)) != 0;
522         final Boolean QUEUE_STATS = (input & (1 << 6)) != 0;
523         final Boolean PORT_BLOCKED = (input & (1 << 8)) != 0;
524         Capabilities capabilities = new Capabilities(FLOW_STATS, GROUP_STATS, IP_REASM,
525                 PORT_BLOCKED, PORT_STATS, QUEUE_STATS, TABLE_STATS);
526         return capabilities;
527     }
528
529     public abstract class ProcessingLatchService {
530         private CountDownLatch processingLatch = new CountDownLatch(0);
531
532         public void resetLatch(int passAmount) {
533             processingLatch = new CountDownLatch(passAmount);
534         }
535
536         protected void countDown() {
537             processingLatch.countDown();
538         }
539
540         public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
541             return processingLatch.await(timeout, unit);
542         }
543     }
544
545     public class ExperimenterMessageService implements IMDMessageTranslator<OfHeader, List<DataObject>> {
546         @Override
547         public List<DataObject> translate(final SwitchConnectionDistinguisher cookie, final SessionContext sw, final OfHeader msg) {
548             LOG.debug("Received a packet in Experimenter Service");
549             ConnectionConductorImplTest.this.incrExperimenterMessageCounter();
550             return null;
551         }
552     }
553
554     public class PacketInMessageService extends ProcessingLatchService implements IMDMessageTranslator<OfHeader, List<DataObject>> {
555         @Override
556         public List<DataObject> translate(final SwitchConnectionDistinguisher cookie, final SessionContext sw, final OfHeader msg) {
557             LOG.debug("Received a packet in PacketIn Service");
558             ConnectionConductorImplTest.this.incrPacketinMessageCounter();
559             countDown();
560             return null;
561         }
562     }
563
564     public class FlowRemovedMessageService extends ProcessingLatchService implements IMDMessageTranslator<OfHeader, List<DataObject>> {
565         @Override
566         public List<DataObject> translate(final SwitchConnectionDistinguisher cookie, final SessionContext sw, final OfHeader msg) {
567             LOG.debug("Received a packet in FlowRemoved Service");
568             ConnectionConductorImplTest.this.incrFlowremovedMessageCounter();
569             countDown();
570             return null;
571         }
572     }
573
574     public class PortStatusMessageService extends ProcessingLatchService implements IMDMessageTranslator<OfHeader, List<DataObject>> {
575         @Override
576         public List<DataObject> translate(final SwitchConnectionDistinguisher cookie, final SessionContext sw, final OfHeader msg) {
577             LOG.debug("Received a packet in PortStatus Service");
578             if ((((PortStatusMessage) msg).getReason().equals(PortReason.OFPPRADD))) {
579                 ConnectionConductorImplTest.this.incrPortstatusAddMessageCounter();
580             } else if (((PortStatusMessage) msg).getReason().equals(PortReason.OFPPRDELETE)) {
581                 ConnectionConductorImplTest.this.incrPortstatusDeleteMessageCounter();
582             } else if (((PortStatusMessage) msg).getReason().equals(PortReason.OFPPRMODIFY)) {
583                 ConnectionConductorImplTest.this.incrPortstatusModifyMessageCounter();
584             }
585             countDown();
586             return null;
587         }
588     }
589
590     public class ErrorMessageService extends ProcessingLatchService implements IMDMessageTranslator<OfHeader, List<DataObject>> {
591         @Override
592         public List<DataObject> translate(final SwitchConnectionDistinguisher cookie, final SessionContext sw, final OfHeader msg) {
593             LOG.debug("Received a packet in Experimenter Service");
594             ConnectionConductorImplTest.this.incrErrorMessageCounter();
595             countDown();
596             return null;
597         }
598     }
599
600     /**
601      * Test method for
602      * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#onExperimenterMessage(ExperimenterMessage)}
603      * .
604      *
605      * @throws InterruptedException
606      */
607     @Test
608     public void testOnErrorMessage() throws InterruptedException {
609         simulateV13PostHandshakeState(connectionConductor);
610         final int messageAmount = 2;
611
612         objErms.resetLatch(messageAmount);
613         ErrorMessageBuilder builder1 = new ErrorMessageBuilder();
614         builder1.setVersion((short) 4);
615         builder1.setCode(100);
616         connectionConductor.onErrorMessage(builder1.build());
617         builder1.setCode(200);
618         connectionConductor.onErrorMessage(builder1.build());
619
620         flushMessageProcessing();
621         Assert.assertTrue(objErms.await(maxProcessingTimeout, TimeUnit.MILLISECONDS));
622         Assert.assertEquals(messageAmount, errorMessageCounter);
623     }
624
625     /**
626      * @return listener mapping for:
627      * <ul>
628      * <li>experimenter</li>
629      * <li>error</li>
630      * </ul>
631      */
632     private Map<TranslatorKey, Collection<IMDMessageTranslator<OfHeader, List<DataObject>>>> assembleTranslatorMapping() {
633         Map<TranslatorKey, Collection<IMDMessageTranslator<OfHeader, List<DataObject>>>> translatorMapping = new HashMap<>();
634         TranslatorKey tKey;
635
636         IMDMessageTranslator<OfHeader, List<DataObject>> objEms = new ExperimenterMessageService();
637         Collection<IMDMessageTranslator<OfHeader, List<DataObject>>> existingValues = new ArrayList<>();
638         existingValues.add(objEms);
639         tKey = new TranslatorKey(4, ExperimenterMessage.class.getName());
640         translatorMapping.put(tKey, existingValues);
641         objErms = new ErrorMessageService();
642         existingValues.add(objErms);
643         tKey = new TranslatorKey(4, ErrorMessage.class.getName());
644         translatorMapping.put(tKey, existingValues);
645         return translatorMapping;
646     }
647
648     /**
649      * Test method for
650      * {@link org.opendaylight.openflowplugin.openflow.md.core.ConnectionConductorImpl#processPortStatusMsg(PortStatus)}
651      * <br><br>
652      * Tests for getting features from port status message by port version
653      * <ul>
654      * <li>features are malformed - one of them is null</li>
655      * <li>mismatch between port version and port features</li>
656      * <li>mismatch between port version and port features</li>
657      * <li>non-existing port version</li>
658      * <li>port version OF 1.0</li>
659      * <li>port version OF 1.3</li>
660      * </ul>
661      */
662     @Test
663     public void testProcessPortStatusMsg() {
664         simulateV13PostHandshakeState(connectionConductor);
665
666         long portNumber = 90L;
667         long portNumberV10 = 91L;
668         PortStatusMessage msg;
669
670         PortStatusMessageBuilder builder = new PortStatusMessageBuilder();
671         PortFeatures features = new PortFeatures(true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false);
672         PortFeatures featuresMal = new PortFeatures(true, false, false, false, null, false, false, false, false, false, false, false, false, false, false, false);
673         PortFeaturesV10 featuresV10 = new PortFeaturesV10(true, false, false, false, false, false, false, false, false, false, false, false);
674
675         //Malformed features
676         builder.setVersion((short) 1).setPortNo(portNumber).setReason(PortReason.OFPPRADD).setCurrentFeatures(featuresMal);
677         connectionConductor.processPortStatusMsg(builder.build());
678         Assert.assertTrue(connectionConductor.getSessionContext().getPortsBandwidth().isEmpty());
679         Assert.assertTrue(connectionConductor.getSessionContext().getPhysicalPorts().isEmpty());
680
681         //Version-features mismatch
682         builder.setCurrentFeatures(features);
683         connectionConductor.processPortStatusMsg(builder.build());
684         Assert.assertTrue(connectionConductor.getSessionContext().getPortsBandwidth().isEmpty());
685         Assert.assertTrue(connectionConductor.getSessionContext().getPhysicalPorts().isEmpty());
686
687         //Non existing version
688         builder.setVersion((short) 0);
689         connectionConductor.processPortStatusMsg(builder.build());
690         Assert.assertTrue(connectionConductor.getSessionContext().getPortsBandwidth().isEmpty());
691         Assert.assertTrue(connectionConductor.getSessionContext().getPhysicalPorts().isEmpty());
692
693         //Version OF 1.3
694         builder.setVersion((short) 4);
695         msg = builder.build();
696         connectionConductor.processPortStatusMsg(builder.build());
697         Assert.assertTrue(connectionConductor.getSessionContext().getPortBandwidth(portNumber));
698         Assert.assertEquals(connectionConductor.getSessionContext().getPhysicalPort(portNumber), msg);
699
700         //Version OF 1.0
701         builder.setVersion((short) 1).setPortNo(portNumberV10).setCurrentFeatures(null).setCurrentFeaturesV10(featuresV10);
702         msg = builder.build();
703         connectionConductor.processPortStatusMsg(builder.build());
704         Assert.assertTrue(connectionConductor.getSessionContext().getPortBandwidth(portNumberV10));
705         Assert.assertEquals(connectionConductor.getSessionContext().getPhysicalPort(portNumberV10), msg);
706     }
707
708
709     @Test
710     public void testHandshakeFailOperations(){
711         connectionConductor.onHandshakeFailure();
712         connectionConductor.checkState(ConnectionConductor.CONDUCTOR_STATE.RIP);
713     }
714     private static void simulateV13PostHandshakeState(final ConnectionConductorImpl conductor) {
715         GetFeaturesOutputBuilder featureOutput = getFeatureResponseMsg();
716         conductor.postHandshakeBasic(featureOutput.build(), OFConstants.OFP_VERSION_1_3);
717         LOG.debug("simulating post handshake event done");
718     }
719 }