blob: 63cab05cc02e8862b817289826ba7a4ec7ec2c5e [file] [log] [blame]
/*
* Copyright 2021-2023 Open Networking Foundation (ONF) and the ONF Contributors
*
* 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.opencord.olt.impl;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.onlab.packet.ChassisId;
import org.onosproject.cfg.ComponentConfigAdapter;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreServiceAdapter;
import org.onosproject.core.DefaultApplicationId;
import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DefaultDevice;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.store.service.TestStorageService;
import org.opencord.olt.DiscoveredSubscriber;
import org.opencord.sadis.SadisService;
import org.opencord.sadis.SubscriberAndDeviceInformation;
import org.opencord.sadis.UniTagInformation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.onlab.util.Tools.groupedThreads;
import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_BP_ID_DEFAULT;
/**
* Set of tests of the ONOS application component.
*/
@RunWith(MockitoJUnitRunner.class)
public class OltTest extends OltTestHelpers {
private Olt component;
private final ApplicationId testAppId = new DefaultApplicationId(1, "org.opencord.olt.test");
private final Logger log = LoggerFactory.getLogger(getClass());
private DeviceId deviceId = DeviceId.deviceId("test-device");
private Device testDevice = new DefaultDevice(ProviderId.NONE, deviceId, Device.Type.OLT,
"testManufacturer", "1.0", "1.0", "SN", new ChassisId(1));
private Port uniUpdateEnabled = new OltPort(testDevice, true, PortNumber.portNumber(16),
DefaultAnnotations.builder().set(AnnotationKeys.PORT_NAME, "uni-1")
.build());
private ConnectPoint cp = new ConnectPoint(deviceId, uniUpdateEnabled.number());
private DiscoveredSubscriber sub;
@Before
public void setUp() {
component = new Olt();
component.requeueDelay = 0; // avoid delays in the queue add to make things easier in testing
component.cfgService = new ComponentConfigAdapter();
component.deviceService = Mockito.mock(DeviceService.class);
component.storageService = new TestStorageService();
component.coreService = Mockito.spy(new CoreServiceAdapter());
component.oltDeviceService = Mockito.mock(OltDeviceService.class);
doReturn(testAppId).when(component.coreService).registerApplication("org.opencord.olt");
component.discoveredSubscriberExecutor =
Executors.newSingleThreadScheduledExecutor(
groupedThreads("onos/olt",
"discovered-cp-%d", log));
component.flowsExecutor =
Executors.newFixedThreadPool(component.flowProcessingThreads,
groupedThreads("onos/olt-service",
"flows-installer-%d"));
component.subscriberExecutor = Executors.newFixedThreadPool(component.subscriberProcessingThreads,
groupedThreads("onos/olt-service",
"subscriber-installer-%d"));
SadisService sadisService = Mockito.mock(SadisService.class);
component.oltFlowService = Mockito.mock(OltFlowService.class);
component.sadisService = sadisService;
// reset the spy on oltFlowService
reset(component.oltFlowService);
component.bindSadisService(sadisService);
component.eventsQueues = new HashMap<>();
component.eventsQueues.put(cp, new LinkedBlockingQueue<>());
component.discoveredSubscriberExecutor.execute(() -> {
component.processDiscoveredSubscribers();
});
// create empty service for testing
List<UniTagInformation> uniTagInformationList = new LinkedList<>();
UniTagInformation empty = new UniTagInformation.Builder().build();
uniTagInformationList.add(empty);
SubscriberAndDeviceInformation si = new SubscriberAndDeviceInformation();
si.setUniTagList(uniTagInformationList);
sub = new DiscoveredSubscriber(testDevice,
uniUpdateEnabled, DiscoveredSubscriber.Status.ADDED,
false, si);
}
@After
public void tearDown() {
component.deactivate(null);
}
@Test
public void testProcessDiscoveredSubscribersBasicPortSuccess() throws Exception {
doReturn(true).when(component.deviceService).isAvailable(any());
doReturn(sub.port).when(component.deviceService).getPort(any(), any());
doReturn(true).when(component.oltFlowService).handleBasicPortFlows(eq(sub), eq(DEFAULT_BP_ID_DEFAULT),
eq(DEFAULT_BP_ID_DEFAULT));
doReturn(true).when(component.oltDeviceService).isLocalLeader(cp.deviceId());
// adding the discovered subscriber to the queue
LinkedBlockingQueue<DiscoveredSubscriber> q = component.eventsQueues.get(cp);
q.add(sub);
component.eventsQueues.put(cp, q);
// check that we're calling the correct method
TimeUnit.MILLISECONDS.sleep(600);
verify(component.oltFlowService, atLeastOnce()).handleBasicPortFlows(eq(sub), eq(DEFAULT_BP_ID_DEFAULT),
eq(DEFAULT_BP_ID_DEFAULT));
// check if the method doesn't throw an exception we're removing the subscriber from the queue
LinkedBlockingQueue<DiscoveredSubscriber> updatedQueue = component.eventsQueues.get(cp);
assert updatedQueue.isEmpty();
}
@Test
public void testProcessDiscoveredSubscribersBasicPortException() throws Exception {
doReturn(true).when(component.deviceService).isAvailable(any());
doReturn(sub.port).when(component.deviceService).getPort(any(), any());
doReturn(false).when(component.oltFlowService).handleBasicPortFlows(any(), eq(DEFAULT_BP_ID_DEFAULT),
eq(DEFAULT_BP_ID_DEFAULT));
doReturn(true).when(component.oltDeviceService).isLocalLeader(cp.deviceId());
// replace the queue with a spy
LinkedBlockingQueue<DiscoveredSubscriber> q = component.eventsQueues.get(cp);
LinkedBlockingQueue<DiscoveredSubscriber> spiedQueue = spy(q);
// adding the discovered subscriber to the queue
spiedQueue.add(sub);
component.eventsQueues.put(cp, spiedQueue);
TimeUnit.MILLISECONDS.sleep(600);
// check that we're calling the correct method,
// since the subscriber is not removed from the queue we're calling the method multiple times
verify(component.oltFlowService, atLeastOnce()).handleBasicPortFlows(eq(sub), eq(DEFAULT_BP_ID_DEFAULT),
eq(DEFAULT_BP_ID_DEFAULT));
// check if the method throws an exception we are not removing the subscriber from the queue
verify(spiedQueue, never()).remove(sub);
}
@Test
public void testAddSubscriberToQueue() {
// replace the queue with a spy
LinkedBlockingQueue<DiscoveredSubscriber> q = component.eventsQueues.get(cp);
LinkedBlockingQueue<DiscoveredSubscriber> spiedQueue = spy(q);
component.eventsQueues.put(cp, spiedQueue);
component.addSubscriberToQueue(sub);
component.addSubscriberToQueue(sub);
verify(spiedQueue, times(2)).add(sub);
Assert.assertEquals(2, spiedQueue.size());
}
}