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