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