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