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