Use ByteBuf.readRetainedSlice()
[openflowplugin.git] / openflowplugin-impl / src / test / java / org / opendaylight / openflowplugin / impl / connection / HandshakeManagerImplTest.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 package org.opendaylight.openflowplugin.impl.connection;
9
10 import static org.junit.Assert.assertThrows;
11 import static org.mockito.ArgumentMatchers.any;
12
13 import com.google.common.collect.Lists;
14 import com.google.common.util.concurrent.Futures;
15 import java.math.BigInteger;
16 import java.time.LocalDateTime;
17 import java.util.ArrayList;
18 import java.util.List;
19 import org.junit.After;
20 import org.junit.Assert;
21 import org.junit.Before;
22 import org.junit.Test;
23 import org.junit.runner.RunWith;
24 import org.mockito.ArgumentCaptor;
25 import org.mockito.Mock;
26 import org.mockito.Mockito;
27 import org.mockito.junit.MockitoJUnitRunner;
28 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
29 import org.opendaylight.openflowplugin.api.OFConstants;
30 import org.opendaylight.openflowplugin.api.openflow.connection.DeviceConnectionStatusProvider;
31 import org.opendaylight.openflowplugin.api.openflow.md.core.ErrorHandler;
32 import org.opendaylight.openflowplugin.api.openflow.md.core.HandshakeListener;
33 import org.opendaylight.openflowplugin.impl.common.DeviceConnectionRateLimiter;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.HelloElementType;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesInput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloMessageBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.hello.Elements;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.hello.ElementsBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.provider.config.rev160510.OpenflowProviderConfigBuilder;
44 import org.opendaylight.yangtools.yang.common.RpcResult;
45 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
46 import org.opendaylight.yangtools.yang.common.Uint16;
47 import org.opendaylight.yangtools.yang.common.Uint32;
48 import org.opendaylight.yangtools.yang.common.Uint64;
49 import org.opendaylight.yangtools.yang.common.Uint8;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 /**
54  * testing handshake.
55  */
56 @RunWith(MockitoJUnitRunner.class)
57 public class HandshakeManagerImplTest {
58
59     private static final Logger LOG = LoggerFactory.getLogger(HandshakeManagerImplTest.class);
60     private static final Uint16 DEVICE_CONNECTION_RATE_LIMIT_PER_MIN = Uint16.ZERO;
61     private static final int DEVICE_CONNECTION_HOLD_TIME_IN_SECONDS = 60;
62
63     private HandshakeManagerImpl handshakeManager;
64     @Mock
65     private ConnectionAdapter adapter;
66     @Mock
67     private ErrorHandler errorHandler;
68     @Mock
69     private HandshakeListener handshakeListener;
70     @Mock
71     private DeviceConnectionStatusProvider deviceConnectionStatusProvider;
72
73     private DeviceConnectionRateLimiter deviceConnectionRateLimiter;
74
75     private RpcResult<GetFeaturesOutput> resultFeatures;
76
77     private final long helloXid = 42L;
78
79     private int expectedErrors = 0;
80
81     /**
82      * invoked before every test method.
83      */
84     @Before
85     public void setUp() {
86         deviceConnectionRateLimiter = new DeviceConnectionRateLimiter(new OpenflowProviderConfigBuilder()
87                 .setDeviceConnectionRateLimitPerMin(DEVICE_CONNECTION_RATE_LIMIT_PER_MIN).build());
88         handshakeManager = new HandshakeManagerImpl(adapter, OFConstants.OFP_VERSION_1_3, OFConstants.VERSION_ORDER,
89                 errorHandler, handshakeListener, false, deviceConnectionRateLimiter,
90                 DEVICE_CONNECTION_HOLD_TIME_IN_SECONDS, deviceConnectionStatusProvider);
91
92         resultFeatures = RpcResultBuilder.success(new GetFeaturesOutputBuilder().setDatapathId(Uint64.ONE).build())
93                 .build();
94
95         Mockito.when(adapter.hello(any(HelloInput.class)))
96                 .thenReturn(Futures.immediateFuture(RpcResultBuilder.success((HelloOutput) null).build()));
97         Mockito.when(deviceConnectionStatusProvider.getDeviceLastConnectionTime(BigInteger.ONE))
98                 .thenReturn(LocalDateTime.now().minusSeconds(DEVICE_CONNECTION_HOLD_TIME_IN_SECONDS));
99     }
100
101     /**
102      * invoked after each test method.
103      */
104     @After
105     public void teardown() {
106         // logging errors if occurred
107         ArgumentCaptor<Throwable> errorCaptor = ArgumentCaptor.forClass(Throwable.class);
108         Mockito.verify(errorHandler, Mockito.atMost(1)).handleException(errorCaptor.capture());
109         for (Throwable problem : errorCaptor.getAllValues()) {
110             LOG.warn(problem.getMessage(), problem);
111         }
112
113         Mockito.verify(errorHandler, Mockito.times(expectedErrors)).handleException(any(Throwable.class));
114     }
115
116     /**
117      * Test method for
118      * {@link org.opendaylight.openflowplugin.openflow.md.core
119      * .HandshakeManagerImpl#proposeCommonBitmapVersion(java.util.List)}.
120      */
121     @Test
122     public void testProposeCommonBitmapVersion() {
123         Boolean[][] versions
124                 = new Boolean[][]{{true, true, true, false, false, false}, {true, true, true, false, false}};
125
126         for (Boolean[] verasionList : versions) {
127             ElementsBuilder elementsBuilder = new ElementsBuilder();
128             elementsBuilder.setVersionBitmap(Lists.newArrayList(verasionList));
129             Elements element = elementsBuilder.build();
130             Assert.assertEquals(Uint8.ONE, handshakeManager.proposeCommonBitmapVersion(List.of(element)));
131         }
132     }
133
134     /**
135      * Test method for
136      * {@link org.opendaylight.openflowplugin.openflow.md.core.HandshakeManagerImpl#proposeNextVersion(short)}.
137      */
138     @Test
139     public void testProposeNextVersion() {
140         short[] remoteVer = new short[]{0x05, 0x04, 0x03, 0x02, 0x01, 0x8f, 0xff};
141         short[] expectedProposal = new short[]{0x04, 0x04, 0x01, 0x01, 0x01, 0x04, 0x04};
142
143         for (int i = 0; i < remoteVer.length; i++) {
144             Uint8 actualProposal = handshakeManager.proposeNextVersion(Uint8.valueOf(remoteVer[i]));
145             Assert.assertEquals(String.format("proposing for version: %04x", remoteVer[i]), expectedProposal[i],
146                                 actualProposal.toJava());
147         }
148
149         assertThrows(IllegalArgumentException.class, () -> handshakeManager.proposeNextVersion(Uint8.ZERO));
150     }
151
152     //////// Version Negotiation Tests //////////////
153
154     /**
155      * Test of version negotiation Where switch version = 1.0.
156      *
157      */
158     @Test
159     public void testVersionNegotiation10() {
160         LOG.debug("testVersionNegotiation10");
161         Uint8 version = OFConstants.OFP_VERSION_1_0;
162
163         Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
164                 .thenReturn(Futures.immediateFuture(resultFeatures));
165
166         handshakeManager.shake(null);
167
168         handshakeManager.shake(createHelloMessage(version, helloXid).build());
169
170         Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
171     }
172
173     /**
174      * Test of version negotiation Where switch version = 1.0.
175      *
176      */
177     @Test
178     public void testVersionNegotiation10SwitchStarts() {
179         LOG.debug("testVersionNegotiation10-ss");
180         Uint8 version = OFConstants.OFP_VERSION_1_0;
181
182         Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
183                 .thenReturn(Futures.immediateFuture(resultFeatures));
184
185         handshakeManager.shake(createHelloMessage(version, helloXid).build());
186
187         Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
188     }
189
190     /**
191      * Test of version negotiation Where switch version < 1.0.
192      * Switch delivers first helloMessage with version 0x00 = negotiation unsuccessful
193      */
194     @Test
195     public void testVersionNegotiation00() {
196         LOG.debug("testVersionNegotiation00");
197         expectedErrors = 1;
198
199         handshakeManager.shake(createHelloMessage(Uint8.ZERO, helloXid).build());
200
201         Mockito.verify(handshakeListener, Mockito.never())
202                 .onHandshakeSuccessful(any(GetFeaturesOutput.class), any(Uint8.class));
203     }
204
205     /**
206      * Test of version negotiation Where switch version < 1.0.
207      * Switch delivers first helloMessage with version 0x00 = negotiation unsuccessful
208      */
209     @Test
210     public void testVersionNegotiation00SwitchStarts() {
211         LOG.debug("testVersionNegotiation00-ss");
212         expectedErrors = 1;
213         Uint8 version = Uint8.ZERO;
214
215         handshakeManager.shake(null);
216
217         handshakeManager.shake(createHelloMessage(version, helloXid).build());
218
219         Mockito.verify(handshakeListener, Mockito.never())
220                 .onHandshakeSuccessful(any(GetFeaturesOutput.class), any(Uint8.class));
221     }
222
223     /**
224      * Test of version negotiation Where 1.0 < switch version < 1.3.
225      *
226      */
227     @Test
228     public void testVersionNegotiation11() {
229         LOG.debug("testVersionNegotiation11");
230         final Uint8 version = Uint8.TWO;
231         final Uint8 expVersion = Uint8.ONE;
232
233         Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
234                 .thenReturn(Futures.immediateFuture(resultFeatures));
235
236         handshakeManager.shake(createHelloMessage(version, helloXid).build());
237
238         handshakeManager.shake(createHelloMessage(expVersion, helloXid).build());
239
240         Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), expVersion);
241     }
242
243     /**
244      * Test of version negotiation Where 1.0 < switch version < 1.3.
245      */
246     @Test
247     public void testVersionNegotiation11SwitchStarts() {
248         LOG.debug("testVersionNegotiation11-ss");
249         final Uint8 version = Uint8.TWO;
250         final Uint8 expVersion = Uint8.ONE;
251
252         Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
253                 .thenReturn(Futures.immediateFuture(resultFeatures));
254
255         handshakeManager.shake(null);
256
257         handshakeManager.shake(createHelloMessage(version, helloXid).build());
258
259         handshakeManager.shake(createHelloMessage(expVersion, helloXid).build());
260
261         Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), expVersion);
262     }
263
264     /**
265      * Test of version negotiation Where switch version = 1.3.
266      *
267      */
268     @Test
269     public void testVersionNegotiation13() {
270         LOG.debug("testVersionNegotiation13");
271         Uint8 version = OFConstants.OFP_VERSION_1_3;
272
273         Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
274                 .thenReturn(Futures.immediateFuture(resultFeatures));
275
276         handshakeManager.shake(createHelloMessage(version, helloXid).build());
277
278         Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
279     }
280
281     /**
282      * Test of version negotiation Where switch version = 1.3.
283      *
284      */
285     @Test
286     public void testVersionNegotiation13SwitchStarts() {
287         LOG.debug("testVersionNegotiation13-ss");
288         Uint8 version = OFConstants.OFP_VERSION_1_3;
289
290         Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
291                 .thenReturn(Futures.immediateFuture(resultFeatures));
292
293         handshakeManager.shake(null);
294
295         handshakeManager.shake(createHelloMessage(version, helloXid).build());
296
297         Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
298     }
299
300     /**
301      * Test of version negotiation Where switch version >= 1.3.
302      *
303      */
304     @Test
305     public void testVersionNegotiation15() {
306         LOG.debug("testVersionNegotiation15");
307         Uint8 version = Uint8.valueOf(6);
308         Uint8 expVersion = OFConstants.OFP_VERSION_1_3;
309
310         Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
311                 .thenReturn(Futures.immediateFuture(resultFeatures));
312
313         handshakeManager.shake(createHelloMessage(version, helloXid).build());
314
315         handshakeManager.shake(createHelloMessage(expVersion, helloXid).build());
316
317         Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), expVersion);
318     }
319
320     /**
321      * Test of version negotiation Where switch version >= 1.3.
322      *
323      */
324     @Test
325     public void testVersionNegotiation15SwitchStart() {
326         LOG.debug("testVersionNegotiation15-ss");
327         Uint8 version = Uint8.valueOf(6);
328         Uint8 expVersion = OFConstants.OFP_VERSION_1_3;
329
330         Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
331                 .thenReturn(Futures.immediateFuture(resultFeatures));
332
333         handshakeManager.shake(createHelloMessage(version, helloXid).build());
334
335         handshakeManager.shake(createHelloMessage(expVersion, helloXid).build());
336
337         Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), expVersion);
338     }
339
340     /**
341      * Test of version negotiation Where switch version > 1.3.
342      *
343      */
344     @Test
345     public void testVersionNegotiation15_MultipleCall() {
346         LOG.debug("testVersionNegotiation15_MultipleCall");
347         Uint8 version = Uint8.valueOf(6);
348         expectedErrors = 1;
349
350         handshakeManager.shake(createHelloMessage(version, helloXid).build());
351
352         handshakeManager.shake(createHelloMessage(version, helloXid).build());
353
354         Mockito.verify(handshakeListener, Mockito.never())
355                 .onHandshakeSuccessful(any(GetFeaturesOutput.class), any(Uint8.class));
356     }
357
358     /**
359      * Test of version negotiation Where switch version > 1.3.
360      *
361      */
362     @Test
363     public void testVersionNegotiation15_MultipleCallSwitchStarts() {
364         LOG.debug("testVersionNegotiation15_MultipleCall-ss");
365         Uint8 version = Uint8.valueOf(6);
366         expectedErrors = 1;
367
368         handshakeManager.shake(null);
369
370         handshakeManager.shake(createHelloMessage(version, helloXid).build());
371
372         handshakeManager.shake(createHelloMessage(version, helloXid).build());
373
374         Mockito.verify(handshakeListener, Mockito.never())
375                 .onHandshakeSuccessful(any(GetFeaturesOutput.class), any(Uint8.class));
376     }
377
378     /**
379      * Test of version negotiation Where bitmap version {0x05,0x01}.
380      *
381      */
382     @Test
383     public void testVersionNegotiation10InBitmap() {
384         LOG.debug("testVersionNegotiation10InBitmap");
385         Uint8 version = OFConstants.OFP_VERSION_1_0;
386         handshakeManager.setUseVersionBitmap(true);
387
388         HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid);
389         addVersionBitmap(List.of(Uint8.valueOf(5), OFConstants.OFP_VERSION_1_0), helloMessage);
390
391         Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
392                 .thenReturn(Futures.immediateFuture(resultFeatures));
393
394         handshakeManager.shake(helloMessage.build());
395
396         Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
397     }
398
399     /**
400      * Test of version negotiation Where bitmap version {0x05,0x01}.
401      *
402      */
403     @Test
404     public void testVersionNegotiation10InBitmapSwitchStarts() {
405         LOG.debug("testVersionNegotiation10InBitmap-ss");
406         Uint8 version = OFConstants.OFP_VERSION_1_0;
407         handshakeManager.setUseVersionBitmap(true);
408
409         HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid);
410         addVersionBitmap(List.of(Uint8.valueOf(5), OFConstants.OFP_VERSION_1_0), helloMessage);
411
412         Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
413                 .thenReturn(Futures.immediateFuture(resultFeatures));
414
415         handshakeManager.shake(null);
416
417         handshakeManager.shake(helloMessage.build());
418
419         Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
420     }
421
422     /**
423      * Test of version negotiation Where bitmap version {0x05,0x04}.
424      *
425      */
426     @Test
427     public void testVersionNegotiation13InBitmap() {
428         LOG.debug("testVersionNegotiation13InBitmap");
429         Uint8 version = OFConstants.OFP_VERSION_1_3;
430         handshakeManager.setUseVersionBitmap(true);
431
432         HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid);
433         addVersionBitmap(List.of(Uint8.valueOf(5), OFConstants.OFP_VERSION_1_3), helloMessage);
434
435         Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
436                 .thenReturn(Futures.immediateFuture(resultFeatures));
437
438         handshakeManager.shake(helloMessage.build());
439
440         Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
441     }
442
443     /**
444      * Test of version negotiation Where bitmap version {0x05,0x04}.
445      *
446      */
447     @Test
448     public void testVersionNegotiation13InBitmapSwitchFirst() {
449         LOG.debug("testVersionNegotiation13InBitmap-ss");
450         Uint8 version = OFConstants.OFP_VERSION_1_3;
451         handshakeManager.setUseVersionBitmap(true);
452
453         HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid);
454         addVersionBitmap(List.of(Uint8.valueOf(5), OFConstants.OFP_VERSION_1_3), helloMessage);
455
456         Mockito.when(adapter.getFeatures(any(GetFeaturesInput.class)))
457                 .thenReturn(Futures.immediateFuture(resultFeatures));
458
459         handshakeManager.shake(null);
460
461         handshakeManager.shake(helloMessage.build());
462
463         Mockito.verify(handshakeListener).onHandshakeSuccessful(resultFeatures.getResult(), version);
464     }
465
466     /**
467      * Test of version negotiation Where bitmap version {0x05,0x02}.
468      *
469      */
470     @Test
471     public void testVersionNegotiationNoCommonVersionInBitmap() {
472         LOG.debug("testVersionNegotiationNoCommonVersionInBitmap");
473         Uint8 version = Uint8.valueOf(5);
474         expectedErrors = 1;
475         handshakeManager.setUseVersionBitmap(true);
476
477         HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid);
478         addVersionBitmap(List.of(Uint8.valueOf(5), Uint8.TWO), helloMessage);
479
480         handshakeManager.shake(helloMessage.build());
481
482         Mockito.verify(handshakeListener, Mockito.never())
483                 .onHandshakeSuccessful(any(GetFeaturesOutput.class), any(Uint8.class));
484     }
485
486     /**
487      * Test of version negotiation Where bitmap version {0x05,0x02}.
488      *
489      */
490     @Test
491     public void testVersionNegotiationNoCommonVersionInBitmapSwitchStarts() {
492         LOG.debug("testVersionNegotiationNoCommonVersionInBitmap-ss");
493         Uint8 version = Uint8.valueOf(5);
494         expectedErrors = 1;
495         handshakeManager.setUseVersionBitmap(true);
496
497         HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid);
498         addVersionBitmap(List.of(Uint8.valueOf(5), Uint8.TWO), helloMessage);
499
500         handshakeManager.shake(null);
501
502         handshakeManager.shake(helloMessage.build());
503
504         Mockito.verify(handshakeListener, Mockito.never())
505                 .onHandshakeSuccessful(any(GetFeaturesOutput.class), any(Uint8.class));
506     }
507
508
509     /**
510      * Creates hello message.
511      *
512      * @param ofpVersion10 version
513      * @param helloXid hello xid
514      * @return builder
515      */
516     private static HelloMessageBuilder createHelloMessage(final Uint8 ofpVersion10, final long helloXid) {
517         return new HelloMessageBuilder().setVersion(ofpVersion10).setXid(Uint32.valueOf(helloXid));
518     }
519
520     /**
521      * Adds version bitmap.
522      * @param versionOrder version order
523      * @param helloBuilder hello builder
524      * @return builder
525      */
526     private static HelloMessageBuilder addVersionBitmap(final List<Uint8> versionOrder,
527             final HelloMessageBuilder helloBuilder) {
528         final short highestVersion = versionOrder.get(0).toJava();
529         final int elementsCount = highestVersion / Integer.SIZE;
530         ElementsBuilder elementsBuilder = new ElementsBuilder();
531
532         List<Elements> elementList = new ArrayList<>();
533         int orderIndex = versionOrder.size();
534         int value = versionOrder.get(--orderIndex).toJava();
535         for (int index = 0; index <= elementsCount; index++) {
536             List<Boolean> booleanList = new ArrayList<>();
537             for (int i = 0; i < Integer.SIZE; i++) {
538                 if (value == index * Integer.SIZE + i) {
539                     booleanList.add(true);
540                     value = orderIndex == 0 ? highestVersion : versionOrder.get(--orderIndex).toJava();
541                 } else {
542                     booleanList.add(false);
543                 }
544             }
545             elementsBuilder.setType(HelloElementType.forValue(1));
546             elementsBuilder.setVersionBitmap(booleanList);
547             elementList.add(elementsBuilder.build());
548         }
549
550         helloBuilder.setElements(elementList);
551         return helloBuilder;
552     }
553
554 }