BUG 2820 - LLDP refactor
[controller.git] / opendaylight / commons / liblldp / src / test / java / org / opendaylight / controller / liblldp / LLDPTest.java
1 /*
2  * Copyright (c) 2015 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.controller.liblldp;
9
10 import static org.junit.Assert.assertArrayEquals;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertFalse;
13 import static org.junit.Assert.assertNotNull;
14 import static org.junit.Assert.assertNull;
15 import static org.junit.Assert.assertTrue;
16 import org.junit.Before;
17 import java.util.Iterator;
18 import java.util.ArrayList;
19 import java.util.List;
20
21 import org.apache.commons.lang3.ArrayUtils;
22 import org.junit.Assert;
23 import org.junit.Test;
24 import org.junit.internal.ArrayComparisonFailure;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 import com.google.common.primitives.Bytes;
29
30 /**
31  * Test of {@link LLDP} serialization feature (TODO: and deserialization)
32  */
33 public class LLDPTest {
34
35     private static final Logger LOG = LoggerFactory.getLogger(LLDPTest.class);
36
37     private static final byte[] CHASSIS_ID_VALUE = "chassis".getBytes();
38     private static final short CHASSIS_ID_LENGTH = (short) CHASSIS_ID_VALUE.length;
39
40     private static final byte[] TTL_VALUE = new byte[] { (byte) 0, (byte) 100 };
41     private static final short TTL_LENGTH = (short) TTL_VALUE.length;
42
43     private static final byte[] PORT_VALUE = "dummy port id".getBytes();
44     private static final short PORT_LENGTH = (short) PORT_VALUE.length;
45
46     private static final byte[] SYSTEM_NAME_VALUE = "dummy system name".getBytes();
47     private static final short SYSTEM_NAME_LENGTH = (short) SYSTEM_NAME_VALUE.length;
48
49     private static final byte SYSTEM_CAPABILITIES_TLV = 8;
50     private static final byte[] SYSTEM_CAPABILITIES_VALUE = "dummy system capabilities".getBytes();
51     private static final short SYSTEM_CAPABILITIES_LENGTH = (short) SYSTEM_CAPABILITIES_VALUE.length;
52
53     private static final byte[] OUI = LLDPTLV.OFOUI;
54
55     private static final byte[] OUI_SUBTYPE_A = new byte[] { (byte) 0 };
56     private static final byte[] CUSTOM_SUBTYPE_A_VALUE = "first custom value A".getBytes();
57     private static final short CUSTOM_SUBTYPE_A_LENGTH = (short) (OUI.length + OUI_SUBTYPE_A.length + CUSTOM_SUBTYPE_A_VALUE.length);
58
59     private static final byte[] OUI_SUBTYPE_B = new byte[] { (byte) 1 };
60     private static final byte[] CUSTOM_SUBTYPE_B_VALUE = "second custom value B".getBytes();
61     private static final short CUSTOM_SUBTYPE_B_LENGTH = (short) (OUI.length + OUI_SUBTYPE_B.length + CUSTOM_SUBTYPE_B_VALUE.length);
62
63     private static final byte[] BYTES_BEFORE_CUSTOM_A = new byte[] { 0x00, 0x26, (byte) 0xe1, OUI_SUBTYPE_A[0] };
64     private static final byte[] BYTES_BEFORE_CUSTOM_B = new byte[] { 0x00, 0x26, (byte) 0xe1, OUI_SUBTYPE_B[0] };
65     private LLDP lldpBuilder;
66
67     @Before
68     public void setup() {
69         lldpBuilder = new LLDP();
70     }
71
72     /**
73      * Tests whether serialization of LLDP packet is correct
74      *
75      * @see LLDP#serialize()
76      * @throws PacketException
77      */
78     @Test
79     public void testSerialize() throws PacketException {
80         lldpBuilder.setChassisId(dummyTlv(LLDPTLV.TLVType.ChassisID.getValue(), CHASSIS_ID_LENGTH, CHASSIS_ID_VALUE));
81         lldpBuilder.setTtl(dummyTlv(LLDPTLV.TLVType.TTL.getValue(), TTL_LENGTH, TTL_VALUE));
82         lldpBuilder.setPortId(dummyTlv(LLDPTLV.TLVType.PortID.getValue(), PORT_LENGTH, PORT_VALUE));
83         lldpBuilder.setSystemNameId(dummyTlv(LLDPTLV.TLVType.SystemName.getValue(), SYSTEM_NAME_LENGTH,
84                 SYSTEM_NAME_VALUE));
85
86         // adding optional TLVs for which doesn't exist special set* methods in LLDP
87         final List<LLDPTLV> optionalTLVs = new ArrayList<>();
88         // System Capabilities TLV (type = 7)
89         optionalTLVs.add(dummyTlv(SYSTEM_CAPABILITIES_TLV, SYSTEM_CAPABILITIES_LENGTH, SYSTEM_CAPABILITIES_VALUE));
90         lldpBuilder.setOptionalTLVList(optionalTLVs);
91
92         // adding custom TLVs
93         lldpBuilder.addCustomTLV(dummyCustomTlv(LLDPTLV.TLVType.Custom.getValue(), OUI, OUI_SUBTYPE_A,
94                 CUSTOM_SUBTYPE_A_LENGTH, CUSTOM_SUBTYPE_A_VALUE));
95         lldpBuilder.addCustomTLV(dummyCustomTlv(LLDPTLV.TLVType.Custom.getValue(), OUI, OUI_SUBTYPE_B,
96                 CUSTOM_SUBTYPE_B_LENGTH, CUSTOM_SUBTYPE_B_VALUE));
97
98         byte[] serialized = lldpBuilder.serialize();
99
100         int offset = 0;
101         offset = checkTLV(serialized, offset, (byte) 0b00000010, "ChassisID", CHASSIS_ID_LENGTH, CHASSIS_ID_VALUE);
102         offset = checkTLV(serialized, offset, (byte) 0b00000110, "TTL", TTL_LENGTH, TTL_VALUE);
103         offset = checkTLV(serialized, offset, (byte) 0b00000100, "PortID", PORT_LENGTH, PORT_VALUE);
104         offset = checkTLV(serialized, offset, (byte) 0b00001010, "SystemName", SYSTEM_NAME_LENGTH,
105                 SYSTEM_NAME_VALUE);
106         offset = checkTLV(serialized, offset, (byte) 0b00010000, "System capabilities",
107                 SYSTEM_CAPABILITIES_LENGTH, SYSTEM_CAPABILITIES_VALUE);
108         offset = checkTLV(serialized, offset, (byte) 0b11111110, "Custom subtype A",
109                 CUSTOM_SUBTYPE_A_LENGTH, CUSTOM_SUBTYPE_A_VALUE, OUI[0], OUI[1], OUI[2],
110                 OUI_SUBTYPE_A[0]);
111         offset = checkTLV(serialized, offset, (byte) 0b11111110, "Custom subtype B",
112                 CUSTOM_SUBTYPE_B_LENGTH, CUSTOM_SUBTYPE_B_VALUE, OUI[0], OUI[1], OUI[2],
113                 OUI_SUBTYPE_B[0]);
114
115     }
116
117     /**
118      * Tests whether serialization of LLDP packet is correct
119      *
120      * @see LLDP#deserialize(byte[], int, int)
121      * @throws Exception
122      */
123     @Test
124     public void testDeserialize() throws Exception {
125
126         byte[] rawLldpTlv = Bytes.concat(
127                 awaitedBytes((byte) 0b00000010, CHASSIS_ID_LENGTH, CHASSIS_ID_VALUE, null),
128                 awaitedBytes((byte) 0b00000110, TTL_LENGTH, TTL_VALUE, null),
129                 awaitedBytes((byte) 0b00000100, PORT_LENGTH, PORT_VALUE, null),
130                 awaitedBytes((byte) 0b00001010, SYSTEM_NAME_LENGTH, SYSTEM_NAME_VALUE, null),
131                 awaitedBytes((byte) 0b00010010, SYSTEM_CAPABILITIES_LENGTH,
132                         SYSTEM_CAPABILITIES_VALUE, null),
133                 awaitedBytes((byte) 0b11111110, CUSTOM_SUBTYPE_A_LENGTH, CUSTOM_SUBTYPE_A_VALUE,
134                         BYTES_BEFORE_CUSTOM_A),
135                 awaitedBytes((byte) 0b11111110, CUSTOM_SUBTYPE_B_LENGTH, CUSTOM_SUBTYPE_B_VALUE,
136                         BYTES_BEFORE_CUSTOM_B));
137
138         lldpBuilder.deserialize(rawLldpTlv, 0, rawLldpTlv.length * NetUtils.NumBitsInAByte);
139         Assert.assertEquals("chassis", new String(lldpBuilder.getChassisId().getValue()));
140         Assert.assertArrayEquals(TTL_VALUE, lldpBuilder.getTtl().getValue());
141         Assert.assertEquals("dummy port id", new String(lldpBuilder.getPortId().getValue()));
142         Assert.assertEquals("dummy system name", new String(lldpBuilder.getSystemNameId().getValue()));
143
144         // optional items check
145         Iterator<LLDPTLV> iteratorTlvOptional = lldpBuilder.getOptionalTLVList().iterator();
146
147         assertTrue(iteratorTlvOptional.hasNext());
148         LLDPTLV item0 = iteratorTlvOptional.next();
149         Assert.assertEquals(5, item0.getType());
150         Assert.assertEquals("dummy system name", new String(item0.getValue()));
151         assertTrue(iteratorTlvOptional.hasNext());
152
153         assertTrue(iteratorTlvOptional.hasNext());
154         LLDPTLV item1 = iteratorTlvOptional.next();
155         Assert.assertEquals(9, item1.getType());
156         Assert.assertEquals("dummy system capabilities", new String(item1.getValue()));
157         assertFalse(iteratorTlvOptional.hasNext());
158
159         // custom items check
160         Iterable<LLDPTLV> customTlvs = lldpBuilder.getCustomTlvList();
161         Iterator<LLDPTLV> iteratorLLDPTLV = customTlvs.iterator();
162         assertEquals(true, iteratorLLDPTLV.hasNext());
163         checkCustomTlv(iteratorLLDPTLV.next(), "first custom value A");
164         assertEquals(true, iteratorLLDPTLV.hasNext());
165         checkCustomTlv(iteratorLLDPTLV.next(), "second custom value B");
166         assertEquals(false, iteratorLLDPTLV.hasNext());
167     }
168
169     /**
170      * Test of {@link LLDP#addCustomTLV(LLDPTLV)}
171      * @throws PacketException
172      */
173     @Test
174     public void testAddCustomTLV() throws PacketException {
175         byte[] customA = awaitedBytes((byte) 0b11111110, CUSTOM_SUBTYPE_A_LENGTH, CUSTOM_SUBTYPE_A_VALUE,
176                 BYTES_BEFORE_CUSTOM_A);
177         byte[] customB = awaitedBytes((byte) 0b11111110, CUSTOM_SUBTYPE_B_LENGTH, CUSTOM_SUBTYPE_B_VALUE,
178                 BYTES_BEFORE_CUSTOM_B);
179
180         Packet lldptlvA = new LLDPTLV().deserialize(customA, 0, customA.length);
181         assertTrue(lldptlvA instanceof LLDPTLV);
182         Packet lldptlvB = new LLDPTLV().deserialize(customB, 0, customB.length);
183         assertTrue(lldptlvB instanceof LLDPTLV);
184
185         lldpBuilder.addCustomTLV((LLDPTLV) lldptlvA);
186         lldpBuilder.addCustomTLV((LLDPTLV) lldptlvB);
187
188         Iterator<LLDPTLV> customTLVsIterator = lldpBuilder.getCustomTlvList().iterator();
189         assertTrue(customTLVsIterator.hasNext());
190         customTLVsIterator.next();
191         assertTrue(customTLVsIterator.hasNext());
192         customTLVsIterator.next();
193         assertFalse(customTLVsIterator.hasNext());
194     }
195
196     @Test
197     public void testGetCustomTLV() throws PacketException {
198         int ouiInt = BitBufferHelper.getInt(OUI);
199         CustomTLVKey key = new CustomTLVKey(ouiInt, OUI_SUBTYPE_A[0]);
200         LLDPTLV customTLV = lldpBuilder.getCustomTLV(key);
201         assertNull(customTLV);
202
203         byte[] customA = awaitedBytes((byte) 0b11111110, CUSTOM_SUBTYPE_A_LENGTH, CUSTOM_SUBTYPE_A_VALUE,
204                 BYTES_BEFORE_CUSTOM_A);
205         lldpBuilder.deserialize(customA, 0, customA.length);
206
207         customTLV = lldpBuilder.getCustomTLV(key);
208         assertNotNull(customTLV);
209         assertEquals(ouiInt, LLDPTLV.extractCustomOUI(customTLV));
210         assertEquals(OUI_SUBTYPE_A[0], LLDPTLV.extractCustomSubtype(customTLV));
211     }
212
213     /**
214      * @param customItem
215      * @param expectedValue
216      */
217     private static void checkCustomTlv(LLDPTLV customItem, String expectedValue) {
218         Assert.assertEquals(127, customItem.getType());
219         LOG.debug("custom TLV1.length: {}", customItem.getLength());
220         Assert.assertEquals(expectedValue,
221                 new String(
222                         LLDPTLV.getCustomString(
223                                 customItem.getValue(),
224                                 customItem.getLength()))
225         );
226     }
227
228     private static int checkTLV(byte[] serializedData, int offset, byte typeTLVBits, String typeTLVName, short lengthTLV,
229             byte[] valueTLV, byte... bytesBeforeValue) throws ArrayComparisonFailure {
230         byte[] concreteTlvAwaited = awaitedBytes(typeTLVBits, lengthTLV, valueTLV, bytesBeforeValue);
231         int concreteTlvAwaitLength = concreteTlvAwaited.length;
232         assertArrayEquals("Serialization problem " + typeTLVName, concreteTlvAwaited,
233                 ArrayUtils.subarray(serializedData, offset, offset + concreteTlvAwaitLength));
234         return offset + concreteTlvAwaitLength;
235     }
236
237     private static byte[] awaitedBytes(byte typeTLV, short length, byte[] value, byte[] bytesBeforeValue) {
238         byte[] awaited = ArrayUtils.EMPTY_BYTE_ARRAY;
239
240         // 0 - the less meaning byte (right), 1 most meaning byte (left)
241         byte lengthByte0 = (byte) length;
242         byte lengthByte1 = (byte) (length >> 8);
243
244         awaited = ArrayUtils.addAll(awaited, (byte) (typeTLV | lengthByte1), lengthByte0);
245         awaited = ArrayUtils.addAll(awaited, bytesBeforeValue);
246         awaited = ArrayUtils.addAll(awaited, value);
247         return awaited;
248     }
249
250     private static LLDPTLV dummyCustomTlv(final byte tlvType, byte[] oui, byte[] ouiSubtype, short customLength,
251             byte[] subtypeValue) {
252         byte[] fullCustomValue = new byte[0];
253         fullCustomValue = ArrayUtils.addAll(fullCustomValue, oui);
254         fullCustomValue = ArrayUtils.addAll(fullCustomValue, ouiSubtype);
255         fullCustomValue = ArrayUtils.addAll(fullCustomValue, subtypeValue);
256         return dummyTlv(tlvType, customLength, fullCustomValue);
257     }
258
259     private static LLDPTLV dummyTlv(final byte concreteTlv, final short concreteLength, final byte[] concreteValue) {
260         LLDPTLV tlv = new LLDPTLV();
261         tlv.setType(concreteTlv).setLength(concreteLength).setValue(concreteValue);
262         return tlv;
263     }
264 }