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