aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/core/net/src/test/java/org/onosproject/net/edgeservice/impl/EdgeManagerTest.java
blob: 319412feafab8a98d5645c68ea79140325b64132 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
/*
 * Copyright 2015 Open Networking Laboratory
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.onosproject.net.edgeservice.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onosproject.common.event.impl.TestEventDispatcher;
import org.onosproject.event.Event;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultPort;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.NetTestTools;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceServiceAdapter;
import org.onosproject.net.edge.EdgePortEvent;
import org.onosproject.net.edge.EdgePortListener;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.link.LinkEvent;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketServiceAdapter;
import org.onosproject.net.topology.Topology;
import org.onosproject.net.topology.TopologyEvent;
import org.onosproject.net.topology.TopologyListener;
import org.onosproject.net.topology.TopologyServiceAdapter;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import static org.junit.Assert.*;
import static org.onosproject.net.NetTestTools.injectEventDispatcher;
import static org.onosproject.net.device.DeviceEvent.Type.*;
import static org.onosproject.net.edge.EdgePortEvent.Type.EDGE_PORT_ADDED;
import static org.onosproject.net.edge.EdgePortEvent.Type.EDGE_PORT_REMOVED;
import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED;
import static org.onosproject.net.topology.TopologyEvent.Type.TOPOLOGY_CHANGED;

/**
 * Test of the edge port manager. Each device has ports '0' through 'numPorts - 1'
 * as specified by the variable 'numPorts'.
 */
public class EdgeManagerTest {

    private EdgeManager mgr;
    private int totalPorts = 10;
    private boolean alwaysReturnPorts = false;
    private final Set<ConnectPoint> infrastructurePorts = Sets.newConcurrentHashSet();
    private List<EdgePortEvent> events = Lists.newArrayList();
    private final Map<DeviceId, Device> devices = Maps.newConcurrentMap();
    private Set<OutboundPacket> packets = Sets.newConcurrentHashSet();
    private final EdgePortListener testListener = new TestListener(events);
    private TestTopologyManager testTopologyManager;

    @Before
    public void setUp() {
        mgr = new EdgeManager();
        injectEventDispatcher(mgr, new TestEventDispatcher());
        testTopologyManager = new TestTopologyManager(infrastructurePorts);
        mgr.topologyService = testTopologyManager;
        mgr.deviceService = new TestDeviceManager(devices);
        mgr.packetService = new TestPacketManager();
        mgr.activate();
        mgr.addListener(testListener);

    }


    @After
    public void tearDown() {
        mgr.removeListener(testListener);
        mgr.deactivate();
    }

    @Test
    public void testBasics() {
        //Setup
        int numDevices = 20;
        int numPorts = 4;
        defaultPopulator(numDevices, numPorts);

        assertEquals("Unexpected number of ports", numDevices * numPorts, infrastructurePorts.size());

        assertFalse("no ports expected", mgr.getEdgePoints().iterator().hasNext());

        assertFalse("Expected isEdge to return false",
                mgr.isEdgePoint(NetTestTools.connectPoint(Integer.toString(1), 1)));

        removeInfraPort(NetTestTools.connectPoint(Integer.toString(1), 1));
        assertTrue("Expected isEdge to return false",
                mgr.isEdgePoint(NetTestTools.connectPoint(Integer.toString(1), 1)));
    }

    @Test
    public void testLinkUpdates() {
        //Setup
        ConnectPoint testPoint, referencePoint;

        //Testing link removal
        List<Event> eventsToAdd = Lists.newArrayList();
        eventsToAdd.add(new LinkEvent(LINK_REMOVED, NetTestTools.link("a", 1, "b", 2)));
        TopologyEvent event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
        testTopologyManager.listener.event(event);

        assertTrue("The list contained an unexpected number of events", events.size() == 2);
        assertTrue("The first element is of the wrong type.",
                events.get(0).type() == EDGE_PORT_ADDED);
        assertTrue("The second element is of the wrong type.",
                events.get(1).type() == EDGE_PORT_ADDED);

        testPoint = events.get(0).subject();
        referencePoint = NetTestTools.connectPoint("a", 1);
        assertTrue("The port numbers of the first element are incorrect",
                testPoint.port().toLong() == referencePoint.port().toLong());
        assertTrue("The device id of the first element is incorrect.",
                testPoint.deviceId().equals(referencePoint.deviceId()));

        testPoint = events.get(1).subject();
        referencePoint = NetTestTools.connectPoint("b", 2);
        assertTrue("The port numbers of the second element are incorrect",
                testPoint.port().toLong() == referencePoint.port().toLong());
        assertTrue("The device id of the second element is incorrect.",
                testPoint.deviceId().equals(referencePoint.deviceId()));

        //Rebroadcast event to ensure it results in no additional events
        testTopologyManager.listener.event(event);
        assertTrue("The list contained an unexpected number of events", events.size() == 2);

        //Testing link adding when links to remove exist
        eventsToAdd.clear();
        events.clear();
        eventsToAdd.add(new LinkEvent(LINK_ADDED, NetTestTools.link("a", 1, "b", 2)));
        event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
        testTopologyManager.listener.event(event);

        assertTrue("The list contained an unexpected number of events", events.size() == 2);
        assertTrue("The first element is of the wrong type.",
                events.get(0).type() == EDGE_PORT_REMOVED);
        assertTrue("The second element is of the wrong type.",
                events.get(1).type() == EDGE_PORT_REMOVED);

        testPoint = events.get(0).subject();
        referencePoint = NetTestTools.connectPoint("a", 1);
        assertTrue("The port numbers of the first element are incorrect",
                testPoint.port().toLong() == referencePoint.port().toLong());
        assertTrue("The device id of the first element is incorrect.",
                testPoint.deviceId().equals(referencePoint.deviceId()));

        testPoint = events.get(1).subject();
        referencePoint = NetTestTools.connectPoint("b", 2);
        assertTrue("The port numbers of the second element are incorrect",
                testPoint.port().toLong() == referencePoint.port().toLong());
        assertTrue("The device id of the second element is incorrect.",
                testPoint.deviceId().equals(referencePoint.deviceId()));

        //Apparent duplicate of previous method tests removal when the elements have already been removed
        eventsToAdd.clear();
        events.clear();
        eventsToAdd.add(new LinkEvent(LINK_ADDED, NetTestTools.link("a", 1, "b", 2)));
        event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
        testTopologyManager.listener.event(event);

        assertTrue("The list should contain no events, the removed elements don't exist.", events.size() == 0);
    }

    @Test
    public void testDeviceUpdates() {
        //Setup

        Device referenceDevice;
        TopologyEvent event;
        List<Event> eventsToAdd = Lists.newArrayList();
        int numDevices = 10;
        int numInfraPorts = 5;
        totalPorts = 10;
        defaultPopulator(numDevices, numInfraPorts);

        //Test response to device added events
        referenceDevice = NetTestTools.device("1");
        eventsToAdd.add(new DeviceEvent(DEVICE_ADDED, referenceDevice,
                new DefaultPort(referenceDevice, PortNumber.portNumber(1), true)));
        event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
        testTopologyManager.listener.event(event);

        //Check that ports were populated correctly
        assertTrue("Unexpected number of new ports added",
                mgr.deviceService.getPorts(NetTestTools.did("1")).size() == 10);

        //Check that of the ten ports the half that are infrastructure ports aren't added
        assertEquals("Unexpected number of new edge ports added", (totalPorts - numInfraPorts), events.size());

        for (int index = 0; index < numInfraPorts; index++) {
            assertTrue("Unexpected type of event", events.get(index).type() == EDGE_PORT_ADDED);
        }
        //Names here are irrelevant, the first 5 ports are populated as infrastructure, 6-10 are edge
        for (int index = 0; index < events.size(); index++) {
            assertEquals("Port added had unexpected port number.",
                    events.get(index).subject().port(),
                    NetTestTools.connectPoint("a", index + numInfraPorts + 1).port());
        }
        events.clear();

        //Repost the event to test repeated posts
        testTopologyManager.listener.event(event);
        assertEquals("The redundant notification should not have created additional notifications.",
                0, events.size());
        //Calculate the size of the returned iterable of edge points.
        Iterable<ConnectPoint> pts = mgr.getEdgePoints();
        Iterator pointIterator = pts.iterator();
        int count = 0;
        for (; pointIterator.hasNext(); count++) {
            pointIterator.next();
        }
        assertEquals("Unexpected number of edge points", totalPorts - numInfraPorts, count);
        //Testing device removal
        events.clear();
        eventsToAdd.clear();
        eventsToAdd.add(new DeviceEvent(DEVICE_REMOVED, referenceDevice,
                new DefaultPort(referenceDevice, PortNumber.portNumber(1), true)));
        event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
        testTopologyManager.listener.event(event);

        assertEquals("There should be five new events from removal of edge points",
                totalPorts - numInfraPorts, events.size());
        for (int index = 0; index < events.size(); index++) {
            //Assert that the correct port numbers were removed in the correct order
            assertEquals("Port removed had unexpected port number.",
                    events.get(index).subject().port(),
                    (NetTestTools.connectPoint("a", index + numInfraPorts + 1).port()));
            //Assert that the events are of the correct type
            assertEquals("Unexpected type of event", events.get(index).type(), EDGE_PORT_REMOVED);
        }
        events.clear();
        //Rebroadcast event to check that it triggers no new behavior
        testTopologyManager.listener.event(event);
        assertEquals("Rebroadcast of removal event should not produce additional events",
                0, events.size());

        //Testing device status change, changed from unavailable to available
        events.clear();
        eventsToAdd.clear();
        //Make sure that the devicemanager shows the device as available.
        addDevice(referenceDevice, "1", 5);
        devices.put(referenceDevice.id(), referenceDevice);

        eventsToAdd.add(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, referenceDevice));
        event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
        testTopologyManager.listener.event(event);
        //An earlier setup set half of the reference device ports to infrastructure
        assertEquals("An unexpected number of events were generated.", totalPorts - numInfraPorts, events.size());
        for (int i = 0; i < 5; i++) {
            assertEquals("The event was not of the right type", events.get(i).type(), EDGE_PORT_ADDED);
        }
        events.clear();
        testTopologyManager.listener.event(event);
        assertEquals("No events should have been generated for a set of existing ports.", 0, events.size());

        //Test removal when state changes when the device becomes unavailable

        //Ensure that the deviceManager shows the device as unavailable
        removeDevice(referenceDevice);
        /*This variable copies the behavior of the topology by returning ports attached to an unavailable device
        //this behavior is necessary for the following event to execute properly, if these statements are removed
        no events will be generated since no ports will be provided in getPorts() to EdgeManager.
        */
        alwaysReturnPorts = true;
        testTopologyManager.listener.event(event);
        alwaysReturnPorts = false;
        assertEquals("An unexpected number of events were created.", totalPorts - numInfraPorts, events.size());
        for (int i = 0; i < 5; i++) {
            EdgePortEvent edgeEvent = events.get(i);
            assertEquals("The event is of an unexpected type.",
                    EdgePortEvent.Type.EDGE_PORT_REMOVED, edgeEvent.type());
            assertEquals("The event pertains to an unexpected port", PortNumber.portNumber(i + numInfraPorts + 1),
                    edgeEvent.subject().port());
        }
    }

    @Test
    public void testInternalCache() {
        List<Event> eventsToAdd = Lists.newArrayList();
        int numDevices = 10;
        //Number of infrastructure ports per device
        int numPorts = 5;
        //Total ports per device when requesting all devices
        totalPorts = 10;
        defaultPopulator(numDevices, numPorts);
        for (int i = 0; i < numDevices; i++) {
            Device newDevice = NetTestTools.device(Integer.toString(i));
            devices.put(newDevice.id(), newDevice);
            eventsToAdd.add(new DeviceEvent(DEVICE_ADDED, newDevice));
        }
        TopologyEvent event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
        testTopologyManager.listener.event(event);

        //Check all ports have correct designations
        ConnectPoint testPoint;
        for (int deviceNum = 0; deviceNum < numDevices; deviceNum++) {
            for (int portNum = 1; portNum <= totalPorts; portNum++) {
                testPoint = NetTestTools.connectPoint(Integer.toString(deviceNum), portNum);
                if (portNum <= numPorts) {
                    assertFalse("This should not be an edge point", mgr.isEdgePoint(testPoint));
                } else {
                    assertTrue("This should be an edge point", mgr.isEdgePoint(testPoint));
                }
            }
        }
        int count = 0;
        for (ConnectPoint ignored : mgr.getEdgePoints()) {
            count++;
        }
        assertEquals("There are an unexpeceted number of edge points returned.",
                (totalPorts - numPorts) * numDevices, count);
        for (int deviceNumber = 0; deviceNumber < numDevices; deviceNumber++) {
            count = 0;
            for (ConnectPoint ignored : mgr.getEdgePoints(NetTestTools.did("1"))) {
                count++;
            }
            assertEquals("This element has an unexpected number of edge points.", (totalPorts - numPorts), count);
        }
    }


    @Test
    public void testEmit() {
        byte[] arr = new byte[10];
        Device referenceDevice;
        TopologyEvent event;
        List<Event> eventsToAdd = Lists.newArrayList();
        int numDevices = 10;
        int numInfraPorts = 5;
        totalPorts = 10;
        defaultPopulator(numDevices, numInfraPorts);
        for (byte byteIndex = 0; byteIndex < arr.length; byteIndex++) {
            arr[byteIndex] = byteIndex;
        }
        for (int i = 0; i < numDevices; i++) {
            referenceDevice = NetTestTools.device(Integer.toString(i));
            eventsToAdd.add(new DeviceEvent(DEVICE_ADDED, referenceDevice,
                    new DefaultPort(referenceDevice, PortNumber.portNumber(1), true)));
        }
        event = new TopologyEvent(TOPOLOGY_CHANGED, null, eventsToAdd);
        testTopologyManager.listener.event(event);

        mgr.emitPacket(ByteBuffer.wrap(arr), Optional.<TrafficTreatment>empty());

        assertEquals("There were an unexpected number of emitted packets",
                (totalPorts - numInfraPorts) * numDevices, packets.size());
        Iterator<OutboundPacket> packetIter = packets.iterator();
        OutboundPacket packet;
        while (packetIter.hasNext()) {
            packet = packetIter.next();
            assertEquals("The packet had an incorrect payload.", arr, packet.data().array());
        }
        //Start testing emission to a specific device
        packets.clear();
        mgr.emitPacket(NetTestTools.did(Integer.toString(1)), ByteBuffer.wrap(arr), Optional.<TrafficTreatment>empty());

        assertEquals("Unexpected number of outbound packets were emitted.",
                totalPorts - numInfraPorts, packets.size());
        packetIter = packets.iterator();
        while (packetIter.hasNext()) {
            packet = packetIter.next();
            assertEquals("The packet had an incorrect payload", arr, packet.data().array());
        }
    }


    /**
     * @param numDevices    the number of devices to populate.
     * @param numInfraPorts the number of ports to be set as infrastructure on each device, numbered base 0, ports 0
     *                      through numInfraPorts - 1
     */
    private void defaultPopulator(int numDevices, int numInfraPorts) {
        for (int device = 0; device < numDevices; device++) {
            String str = Integer.toString(device);
            Device deviceToAdd = NetTestTools.device(str);
            devices.put(deviceToAdd.id(), deviceToAdd);
            for (int port = 1; port <= numInfraPorts; port++) {
                infrastructurePorts.add(NetTestTools.connectPoint(str, port));
            }
        }
    }

    /**
     * Adds the specified device with the specified number of edge ports so long as it is less than the total ports.
     *
     * @param device        The device to be added
     * @param deviceName    The name given to generate the devices DID
     * @param numInfraPorts The number of ports to be added numbered 1 ... numInfraPorts
     */
    private void addDevice(Device device, String deviceName, int numInfraPorts) {
        if (!devices.keySet().contains(device.id())) {
            devices.put(device.id(), device);
            for (int i = 1; i <= numInfraPorts && i <= totalPorts; i++) {
                infrastructurePorts.add(NetTestTools.connectPoint(deviceName, i));
            }
        }
    }

    private void removeDevice(Device device) {
        devices.remove(device.id());
    }

    private void removeInfraPort(ConnectPoint port) {
        infrastructurePorts.remove(port);
    }

    private class TestTopologyManager extends TopologyServiceAdapter {
        private TopologyListener listener;
        private Set<ConnectPoint> infrastructurePorts;

        public TestTopologyManager(Set<ConnectPoint> infrastructurePorts) {
            this.infrastructurePorts = infrastructurePorts;
        }

        @Override
        public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) {
            return infrastructurePorts.contains(connectPoint);
        }

        @Override
        public void addListener(TopologyListener listener) {
            this.listener = listener;
        }

        @Override
        public void removeListener(TopologyListener listener) {
            this.listener = null;
        }
    }

    private class TestDeviceManager extends DeviceServiceAdapter {

        private Map<DeviceId, Device> devices;

        public TestDeviceManager(Map<DeviceId, Device> devices) {
            this.devices = devices;
        }

        @Override
        public boolean isAvailable(DeviceId deviceId) {
            for (DeviceId id : devices.keySet()) {
                if (id.equals(deviceId)) {
                    return true;
                }
            }
            return false;
        }

        @Override
        public List<Port> getPorts(DeviceId deviceId) {
            List<Port> ports = new ArrayList<>();
            Device device = devices.get(deviceId);
            if (device == null && !alwaysReturnPorts) {
                return ports;
            }
            for (int portNum = 1; portNum <= totalPorts; portNum++) {
                //String is generated using 'of:' + the passed name, this creates a
                ports.add(new DefaultPort(device, PortNumber.portNumber(portNum), true));
            }
            return ports;
        }

        @Override
        public Iterable<Device> getAvailableDevices() {
            return devices.values();
        }
    }

    private class TestPacketManager extends PacketServiceAdapter {
        @Override
        public void emit(OutboundPacket packet) {
            packets.add(packet);
        }
    }

    private class TestListener implements EdgePortListener {
        private List<EdgePortEvent> events;

        public TestListener(List<EdgePortEvent> events) {
            this.events = events;
        }

        @Override
        public void event(EdgePortEvent event) {
            events.add(event);
        }
    }
}