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