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