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