Refactor integration tests
[lispflowmapping.git] / integrationtest / src / test / java / org / opendaylight / lispflowmapping / integrationtest / MappingServiceIntegrationTestUtil.java
1 /*
2  * Copyright (c) 2017 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.lispflowmapping.integrationtest;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.fail;
13
14 import java.net.DatagramPacket;
15 import java.net.DatagramSocket;
16 import java.net.InetAddress;
17 import java.net.InetSocketAddress;
18 import java.net.SocketException;
19 import java.net.SocketTimeoutException;
20 import java.net.UnknownHostException;
21 import java.nio.ByteBuffer;
22 import java.util.ArrayList;
23 import java.util.List;
24 import org.opendaylight.lispflowmapping.lisp.serializer.MapNotifySerializer;
25 import org.opendaylight.lispflowmapping.lisp.serializer.MapReplySerializer;
26 import org.opendaylight.lispflowmapping.lisp.serializer.MapRequestSerializer;
27 import org.opendaylight.lispflowmapping.lisp.type.LispMessage;
28 import org.opendaylight.lispflowmapping.lisp.util.ByteUtil;
29 import org.opendaylight.lispflowmapping.lisp.util.LispAddressStringifier;
30 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MapNotify;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MapReply;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MapRequest;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.MessageType;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.SiteId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.XtrId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.list.EidItemBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecordBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.locatorrecords.LocatorRecordKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecord;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecordBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.list.MappingRecordItemBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.list.MappingRecordItemKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapregistermessage.MapRegisterBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequest.ItrRloc;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequest.ItrRlocBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequest.ItrRlocKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequest.SourceEidBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.maprequestnotification.MapRequestBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.rloc.container.Rloc;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 final class MappingServiceIntegrationTestUtil {
56     private static final Logger LOG = LoggerFactory.getLogger(MappingServiceIntegrationTestUtil.class);
57
58     // Socket related method constants
59     static final String SEND_ADDRESS = "127.0.0.1";
60     static final String RECEIVE_ADDRESS = "127.0.0.2";
61     static final int NUM_OF_ATTEMPTS_TO_CREATE_SOCKET = 2;
62     static final int DEFAULT_SOCKET_TIMEOUT = 6000;
63
64     // Packet creation method constants
65     static final String DEFAULT_IPV4_EID_STRING = "192.0.2.1";
66     static final Eid DEFAULT_IPV4_EID = LispAddressUtil.asIpv4Eid(DEFAULT_IPV4_EID_STRING);
67     static final String DEFAULT_IPV4_RLOC_STRING = "172.16.0.1";
68     static final Rloc DEFAULT_IPV4_RLOC = LispAddressUtil.asIpv4Rloc(DEFAULT_IPV4_RLOC_STRING);
69     static final Rloc DEFAULT_IPV4_ITR_RLOC = LispAddressUtil.asIpv4Rloc(RECEIVE_ADDRESS);
70     static final byte[] DEFAULT_SITE_ID_BYTES = new byte[]{0, 1, 2, 3, 4, 5, 6, 7};
71     static final SiteId DEFAULT_SITE_ID = new SiteId(DEFAULT_SITE_ID_BYTES);
72     static final byte[] DEFAULT_XTR_ID_BYTES = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
73     static final XtrId DEFAULT_XTR_ID = new XtrId(DEFAULT_XTR_ID_BYTES);
74     private static final Eid NO_ADDRESS_EID = LispAddressUtil.getNoAddressEid();
75
76     // Utility class, should not be instantiated
77     private MappingServiceIntegrationTestUtil() {
78     }
79
80     /*
81      *   SOCKET RELATED METHODS
82      */
83
84     /**
85      * Create and return a UDP socket listening on the given port.
86      *
87      * @param port listening port
88      * @return the created socket
89      */
90     static DatagramSocket initSocket(int port) {
91         for (int i=0; i < NUM_OF_ATTEMPTS_TO_CREATE_SOCKET; i++) {
92             try {
93                 LOG.debug("Binding socket on {}:{}", RECEIVE_ADDRESS, port);
94                 return new DatagramSocket(new InetSocketAddress(RECEIVE_ADDRESS, port));
95             } catch (SocketException e) {
96                 LOG.error("Can't initialize socket for {}:{}", RECEIVE_ADDRESS, port, e);
97             }
98         }
99         fail();
100         return null;
101     }
102
103     /**
104      * Set the destination address and port of a UDP packet
105      * @param packet the packet to be set up
106      * @param port destination port
107      * @throws UnknownHostException when SEND_ADDRESS cannot be converted to InetAddress
108      */
109     static void initPacketAddress(DatagramPacket packet, int port) throws UnknownHostException {
110         packet.setAddress(InetAddress.getByName(SEND_ADDRESS));
111         packet.setPort(port);
112     }
113
114     /**
115      * Send a packet.
116      * @param datagramSocket use this socket for sending the packet
117      * @param bytesToSend the packet contents
118      * @param port destination port
119      */
120     static void sendPacket(DatagramSocket datagramSocket, byte[] bytesToSend, int port) {
121         try {
122             DatagramPacket packet = new DatagramPacket(bytesToSend, bytesToSend.length);
123             initPacketAddress(packet, port);
124             LOG.trace("Sending packet to {}:{}", packet.getAddress(), port);
125             datagramSocket.send(packet);
126         } catch (Throwable t) {
127             fail();
128         }
129     }
130
131     /**
132      * Receive a packet on a UDP socket with a set timeout and return it.
133      *
134      * @param datagramSocket the listening socket where we expect the packet
135      * @param timeout timeout to wait for the packet to be received in milliseconds
136      * @return the packet
137      * @throws SocketTimeoutException when timout expires without receiving a packet on the socket
138      */
139     static ByteBuffer receivePacket(DatagramSocket datagramSocket, int timeout) throws SocketTimeoutException {
140         try {
141             byte[] buffer = new byte[4096];
142             DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);
143             LOG.trace("Waiting for packet from socket...");
144             datagramSocket.setSoTimeout(timeout);
145             datagramSocket.receive(receivePacket);
146             LOG.trace("Received packet from socket!");
147             return ByteBuffer.wrap(receivePacket.getData());
148         } catch (SocketTimeoutException ste) {
149             throw ste;
150         } catch (Throwable t) {
151             fail();
152             return null;
153         }
154     }
155
156     /**
157      * Receive a packet on a UDP socket with a set timeout and return it.
158      *
159      * @param datagramSocket the listening socket where we expect the packet
160      * @return the packet
161      * @throws SocketTimeoutException when timout expires without receiving a packet on the socket
162      */
163     static ByteBuffer receivePacket(DatagramSocket datagramSocket) throws SocketTimeoutException {
164         return receivePacket(datagramSocket, DEFAULT_SOCKET_TIMEOUT);
165     }
166
167     /**
168      * Read packets on a UDP socket with a set timeout until the given type is received and return it.
169      *
170      * @param datagramSocket the listening socket where we expect the packet
171      * @param timeout timeout to wait for the packet to be received in milliseconds
172      * @param type the expected packet type
173      * @return the packet
174      * @throws SocketTimeoutException when timout expires without receiving a packet on the socket
175      */
176     static ByteBuffer receiveSpecificPacketType(DatagramSocket datagramSocket, int timeout, MessageType type)
177             throws SocketTimeoutException {
178         while (true) {
179             ByteBuffer packet = receivePacket(datagramSocket, timeout);
180             if (checkType(packet, type)) {
181                 return packet;
182             }
183         }
184     }
185
186     /**
187      * Read packets on a UDP socket with a set timeout until a Map-Request is received and return it.
188      *
189      * @param datagramSocket the listening socket where we expect the packet
190      * @return the Map-Request
191      * @throws SocketTimeoutException
192      */
193     static MapRequest receiveMapRequest(DatagramSocket datagramSocket) throws SocketTimeoutException {
194         ByteBuffer packet = receiveSpecificPacketType(datagramSocket, DEFAULT_SOCKET_TIMEOUT, MessageType.MapRequest);
195         return MapRequestSerializer.getInstance().deserialize(packet, null);
196     }
197
198     /**
199      * Read packets on a UDP socket with a set timeout until a Map-Reply is received and return it.
200      *
201      * @param datagramSocket the listening socket where we expect the packet
202      * @return the Map-Reply
203      * @throws SocketTimeoutException
204      */
205     static MapReply receiveMapReply(DatagramSocket datagramSocket) throws SocketTimeoutException {
206         ByteBuffer packet = receiveSpecificPacketType(datagramSocket, DEFAULT_SOCKET_TIMEOUT, MessageType.MapReply);
207         return MapReplySerializer.getInstance().deserialize(packet);
208     }
209
210     /**
211      * Read packets on a UDP socket with a set timeout until a Map-Notify is received and return it.
212      *
213      * @param datagramSocket the listening socket where we expect the packet
214      * @return the Map-Notify
215      * @throws SocketTimeoutException
216      */
217     static MapNotify receiveMapNotify(DatagramSocket datagramSocket) throws SocketTimeoutException {
218         ByteBuffer packet = receiveSpecificPacketType(datagramSocket, DEFAULT_SOCKET_TIMEOUT, MessageType.MapNotify);
219         return MapNotifySerializer.getInstance().deserialize(packet);
220     }
221
222     /**
223      * Check if a buffer assumed to be a LISP control packet is of the given type.
224      *
225      * @param packet buffer containing the packet data
226      * @param type LISP control packet type
227      * @return true if the packet is of the given type
228      */
229     static boolean checkType(ByteBuffer packet, MessageType type) {
230         final int receivedType = ByteUtil.getUnsignedByte(packet, LispMessage.Pos.TYPE) >> 4;
231         MessageType messageType = MessageType.forValue(receivedType);
232         LOG.trace("Packet type: {}", messageType);
233         return messageType == type;
234     }
235
236     /**
237      * Read packets from the given socket until a Map-Request is found. Assert that the request is an SMR, and the
238      * Source EID field contains the given IPv4 EID. Note that the source EID does not have a mask length.
239      *
240      * @param datagramSocket the receive socket
241      * @param vni the VNI for the expected EID
242      * @param eid the expected EID, as an IPv4 string, without mask length
243      */
244     static void checkSmr(DatagramSocket datagramSocket, long vni, String eid) {
245         try {
246             MapRequest mapRequest = receiveMapRequest(datagramSocket);
247             assertEquals(true, mapRequest.isSmr());
248
249             Eid smrEid = mapRequest.getSourceEid().getEid();
250             Eid originalSourceEid = mapRequest.getEidItem().get(0).getEid();
251             assertEquals(LispAddressUtil.asIpv4Eid(eid, vni), smrEid);
252             assertEquals(NO_ADDRESS_EID, originalSourceEid);
253         } catch (SocketTimeoutException ste) {
254             fail("No SMR received");
255         }
256     }
257
258     /*
259      * PACKETS CREATION METHODS
260      *
261      * In general we return "Builders" so that the caller can customize the fields, but that means it also needs to
262      * call .build() on the received objects.
263      */
264
265     /* Map-Request */
266
267     /**
268      * Create a default MapRequestBuilder object.
269      *
270      * @param eid the requested EID
271      * @return the MapRequestBuilder object
272      */
273     static MapRequestBuilder getDefaultMapRequestBuilder(Eid eid) {
274         MapRequestBuilder mrBuilder = new MapRequestBuilder()
275                 .setAuthoritative(false)
276                 .setEidItem(new ArrayList<>())
277                 .setItrRloc(new ArrayList<>())
278                 .setMapDataPresent(true)
279                 .setNonce((long) 4)
280                 .setPitr(false)
281                 .setProbe(false)
282                 .setSmr(false)
283                 .setSmrInvoked(false)
284                 .setSourceEid(new SourceEidBuilder().setEid(NO_ADDRESS_EID).build())
285                 .setItrRloc(getDefaultItrRlocList(DEFAULT_IPV4_ITR_RLOC));
286
287         mrBuilder.getEidItem().add(new EidItemBuilder().setEid(eid).build());
288
289         return mrBuilder;
290     }
291
292     /**
293      * Create a default ItrRloc List.
294      *
295      * @param rloc the single Rloc to be added to the list
296      * @return the ItrRloc List object
297      */
298     static List<ItrRloc> getDefaultItrRlocList(Rloc rloc) {
299         if (rloc == null) {
300             rloc = DEFAULT_IPV4_ITR_RLOC;
301         }
302
303         final List<ItrRloc> itrRlocList = new ArrayList<>();
304         final ItrRloc itrRloc = new ItrRlocBuilder()
305                 .setKey(new ItrRlocKey(LispAddressStringifier.getString(rloc)))
306                 .setItrRlocId(LispAddressStringifier.getString(rloc))
307                 .setRloc(rloc).build();
308         itrRlocList.add(itrRloc);
309
310         return itrRlocList;
311     }
312
313     /* Map-Register */
314
315     /**
316      * Create a default MapRegisterBuilder object with a non-empty default LocatorRecord.
317      *
318      * @param eid EID for the single mapping record, if null, a default will be added
319      * @return the MapRegisterBuilder object
320      */
321     static MapRegisterBuilder getDefaultMapRegisterBuilder(Eid eid) {
322         MapRegisterBuilder mapRegisterBuilder = getDefaultMapRegisterBuilder(eid, null);
323         mapRegisterBuilder.setMappingRecordItem(new ArrayList<>());
324         mapRegisterBuilder.getMappingRecordItem().add(getDefaultMappingRecordItemBuilder(eid,
325                 DEFAULT_IPV4_RLOC).build());
326
327         return mapRegisterBuilder;
328     }
329
330     /**
331      * Create a default MapRegisterBuilder object.
332      *
333      * @param eid EID for the single mapping record, if null, a default will be added
334      * @param rloc RLOC for the single mapping record, if null, no locator record will be added
335      * @return the MapRegisterBuilder object
336      */
337     static MapRegisterBuilder getDefaultMapRegisterBuilder(Eid eid, Rloc rloc) {
338         final MapRegisterBuilder mapRegisterBuilder = new MapRegisterBuilder()
339                 .setProxyMapReply(true)
340                 .setWantMapNotify(true)
341                 .setKeyId((short) 0)
342                 .setMappingRecordItem(new ArrayList<>())
343                 .setMergeEnabled(true)
344                 .setNonce(8L)
345                 .setSiteId(new SiteId(DEFAULT_SITE_ID_BYTES))
346                 .setXtrId(new XtrId(DEFAULT_XTR_ID_BYTES))
347                 .setXtrSiteIdPresent(true);
348         mapRegisterBuilder.getMappingRecordItem().add(getDefaultMappingRecordItemBuilder(eid, rloc).build());
349
350         return mapRegisterBuilder;
351     }
352
353     /**
354      * Create a default MappingRecordItemBuilder object.
355      *
356      * @param eid EID for the mapping record, if null, a default will be added
357      * @param rloc RLOC for the mapping record, if null, no locator record will be added
358      * @return the MappingRecordItemBuilder object
359      */
360     static MappingRecordItemBuilder getDefaultMappingRecordItemBuilder(Eid eid, Rloc rloc) {
361         return new MappingRecordItemBuilder()
362                 .setMappingRecordItemId("mapping-record-item-id")
363                 .setKey(new MappingRecordItemKey("mapping-record-item-key"))
364                 .setMappingRecord(getDefaultMappingRecordBuilder(eid, rloc).build());
365     }
366
367     /**
368      * Create a default MappingRecordBuilder object with a single default locator record.
369      *
370      * @param eid EID for the mapping record, if null, a default will be added
371      * @return the MappingRecordBuilder object
372      */
373     static MappingRecordBuilder getDefaultMappingRecordBuilder(Eid eid) {
374         return getDefaultMappingRecordBuilder(eid, DEFAULT_IPV4_RLOC);
375     }
376
377     /**
378      * Create a default MappingRecordBuilder object.
379      *
380      * @param eid EID for the mapping record, if null, a default will be added
381      * @param rloc RLOC for the mapping record, if null, no locator record will be added
382      * @return the MappingRecordBuilder object
383      */
384     static MappingRecordBuilder getDefaultMappingRecordBuilder(Eid eid, Rloc rloc) {
385         if (eid == null) {
386             eid = DEFAULT_IPV4_EID;
387             LOG.warn("getDefaultMappingRecordBuilder(): null EID received, using the default {}",
388                     DEFAULT_IPV4_EID_STRING);
389         }
390
391         MappingRecordBuilder mrb = new MappingRecordBuilder()
392                 .setEid(eid)
393                 .setAction(MappingRecord.Action.NoAction)
394                 .setAuthoritative(false)
395                 .setLocatorRecord(new ArrayList<>())
396                 .setMapVersion((short) 0)
397                 .setRecordTtl(60)
398                 .setTimestamp(System.currentTimeMillis());
399
400         // We want to allow for empty locator records, so we only add one if rloc is not null
401         if (rloc != null) {
402             mrb.getLocatorRecord().add(getDefaultLocatorBuilder(rloc).build());
403         }
404
405         return mrb;
406     }
407
408     /**
409      * Create a default LocatorRecordBuilder object.
410      *
411      * @param rloc RLOC for the mapping record, if null, a default will be added
412      * @return the LocatorRecordBuilder object
413      */
414     static LocatorRecordBuilder getDefaultLocatorBuilder(Rloc rloc) {
415         if (rloc == null) {
416             rloc = DEFAULT_IPV4_RLOC;
417             LOG.warn("getDefaultLocatorBuilder(): null RLOC received, using the default {}", DEFAULT_IPV4_RLOC_STRING);
418         }
419
420         return new LocatorRecordBuilder()
421                 .setLocalLocator(true)
422                 .setMulticastPriority((short) 255)
423                 .setMulticastWeight((short) 0)
424                 .setPriority((short) 1)
425                 .setRlocProbed(false)
426                 .setRouted(true)
427                 .setWeight((short) 1)
428                 .setKey(new LocatorRecordKey(LispAddressStringifier.getString(rloc)))
429                 .setRloc(rloc);
430     }
431 }