blob: 94b31618b1749c7f34761ac12eed4a7f5410d502 [file] [log] [blame]
/*
* Copyright 2021-present Open Networking Foundation
*
* 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.kubevirtnetworking.impl;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.MoreExecutors;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestUtils;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreServiceAdapter;
import org.onosproject.core.DefaultApplicationId;
import org.onosproject.event.Event;
import org.onosproject.kubevirtnetworking.api.DefaultKubevirtFloatingIp;
import org.onosproject.kubevirtnetworking.api.DefaultKubevirtRouter;
import org.onosproject.kubevirtnetworking.api.KubevirtFloatingIp;
import org.onosproject.kubevirtnetworking.api.KubevirtPeerRouter;
import org.onosproject.kubevirtnetworking.api.KubevirtRouter;
import org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent;
import org.onosproject.kubevirtnetworking.api.KubevirtRouterListener;
import org.onosproject.store.service.TestStorageService;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_FLOATING_IP_ASSOCIATED;
import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_FLOATING_IP_CREATED;
import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_FLOATING_IP_DISASSOCIATED;
import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_FLOATING_IP_REMOVED;
import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_FLOATING_IP_UPDATED;
import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_CREATED;
import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_EXTERNAL_NETWORK_ATTACHED;
import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_EXTERNAL_NETWORK_DETACHED;
import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED;
import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED;
import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_REMOVED;
import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_UPDATED;
/**
* Unit tests for kubernetes router manager.
*/
public class KubevirtRouterManagerTest {
private static final ApplicationId TEST_APP_ID = new DefaultApplicationId(1, "test");
private static final String ROUTER_NAME = "router-1";
private static final String POD_NAME = "pod-1";
private static final String NETWORK_NAME = "flat-1";
private static final String UPDATED_DESCRIPTION = "router-updated";
private static final MacAddress UPDATED_MAC = MacAddress.valueOf("FF:FF:FF:FF:FF:FF");
private static final String FLOATING_IP_ID = "fip-1";
private static final String UNKNOWN_ID = "unknown";
private static final KubevirtRouter ROUTER = DefaultKubevirtRouter.builder()
.name(ROUTER_NAME)
.description(ROUTER_NAME)
.internal(ImmutableSet.of())
.external(ImmutableMap.of())
.enableSnat(true)
.build();
private static final KubevirtRouter ROUTER_UPDATED = DefaultKubevirtRouter.builder()
.name(ROUTER_NAME)
.description(UPDATED_DESCRIPTION)
.internal(ImmutableSet.of())
.external(ImmutableMap.of())
.enableSnat(true)
.build();
private static final KubevirtRouter ROUTER_WITH_INTERNAL = DefaultKubevirtRouter.builder()
.name(ROUTER_NAME)
.description(ROUTER_NAME)
.internal(ImmutableSet.of("vxlan-1", "vxlan-2"))
.external(ImmutableMap.of())
.enableSnat(true)
.build();
private static final KubevirtRouter ROUTER_WITH_SINGLE_INTERNAL = DefaultKubevirtRouter.builder()
.name(ROUTER_NAME)
.description(ROUTER_NAME)
.internal(ImmutableSet.of("vxlan-1"))
.external(ImmutableMap.of())
.enableSnat(true)
.build();
private static final KubevirtRouter ROUTER_WITH_EXTERNAL = DefaultKubevirtRouter.builder()
.name(ROUTER_NAME)
.description(ROUTER_NAME)
.internal(ImmutableSet.of())
.external(ImmutableMap.of("10.10.10.10", "flat"))
.enableSnat(true)
.peerRouter(new KubevirtPeerRouter(IpAddress.valueOf("20.20.20.20"),
MacAddress.valueOf("11:22:33:44:55:66")))
.build();
private static final KubevirtFloatingIp FLOATING_IP_DISASSOCIATED = DefaultKubevirtFloatingIp.builder()
.id(FLOATING_IP_ID)
.routerName(ROUTER_NAME)
.networkName(NETWORK_NAME)
.floatingIp(IpAddress.valueOf("10.10.10.10"))
.build();
private static final KubevirtFloatingIp FLOATING_IP_ASSOCIATED = DefaultKubevirtFloatingIp.builder()
.id(FLOATING_IP_ID)
.routerName(ROUTER_NAME)
.networkName(NETWORK_NAME)
.floatingIp(IpAddress.valueOf("10.10.10.10"))
.fixedIp(IpAddress.valueOf("20.20.20.20"))
.podName(POD_NAME)
.build();
private final TestKubevirtRouterListener testListener = new TestKubevirtRouterListener();
private KubevirtRouterManager target;
private DistributedKubevirtRouterStore kubevirtRouterStore;
@Before
public void setUp() throws Exception {
kubevirtRouterStore = new DistributedKubevirtRouterStore();
TestUtils.setField(kubevirtRouterStore, "coreService", new TestCoreService());
TestUtils.setField(kubevirtRouterStore, "storageService", new TestStorageService());
TestUtils.setField(kubevirtRouterStore, "eventExecutor", MoreExecutors.newDirectExecutorService());
kubevirtRouterStore.activate();
target = new KubevirtRouterManager();
TestUtils.setField(target, "coreService", new TestCoreService());
target.kubevirtRouterStore = kubevirtRouterStore;
target.addListener(testListener);
target.activate();
}
@After
public void tearDown() {
target.removeListener(testListener);
kubevirtRouterStore.deactivate();
target.deactivate();
kubevirtRouterStore = null;
target = null;
}
/**
* Tests if getting all routers returns correct set of values.
*/
@Test
public void testGetRouters() {
createBasicRouters();
assertEquals("Number of router did not match", 1, target.routers().size());
}
/**
* Tests if getting a router with name returns correct value.
*/
@Test
public void testGetRouterByName() {
createBasicRouters();
assertNotNull("Router did not match", target.router(ROUTER_NAME));
}
/**
* Tests creating and removing a router, and checks if proper event is triggered.
*/
@Test
public void testCreateAndRemoveRouter() {
target.createRouter(ROUTER);
assertEquals("Number of router did not match", 1, target.routers().size());
assertNotNull("Router was not created", target.router(ROUTER_NAME));
target.removeRouter(ROUTER_NAME);
assertEquals("Number of router did not match", 0, target.routers().size());
assertNull("Router was not created", target.router(ROUTER_NAME));
validateEvents(KUBEVIRT_ROUTER_CREATED, KUBEVIRT_ROUTER_REMOVED);
}
/**
* Tests creating and updating a port, and checks if proper event is triggered.
*/
@Test
public void testCreateAndUpdateRouter() {
target.createRouter(ROUTER);
assertEquals("Number of router did not match", 1, target.routers().size());
target.updateRouter(ROUTER_UPDATED);
assertEquals("Number of router did not match", 1, target.routers().size());
assertEquals("Router did not match", UPDATED_DESCRIPTION, target.router(ROUTER_NAME).description());
validateEvents(KUBEVIRT_ROUTER_CREATED, KUBEVIRT_ROUTER_UPDATED);
}
/**
* Tests updating peer router MAC address.
*/
@Test
public void testPeerRouterMacUpdate() {
target.createRouter(ROUTER_WITH_EXTERNAL);
target.updatePeerRouterMac(ROUTER_NAME, UPDATED_MAC);
assertEquals("MAC address was not updated", UPDATED_MAC,
target.router(ROUTER_NAME).peerRouter().macAddress());
validateEvents(KUBEVIRT_ROUTER_CREATED, KUBEVIRT_ROUTER_UPDATED);
}
/**
* Tests router's internal networks attached and detached.
*/
@Test
public void testRouterInternalAttachedAndDetached() {
target.createRouter(ROUTER);
assertEquals("Number of router did not match", 1, target.routers().size());
assertEquals("Router internal did not match", 0, target.router(ROUTER_NAME).internal().size());
target.updateRouter(ROUTER_WITH_INTERNAL);
assertEquals("Number of router did not match", 1, target.routers().size());
assertEquals("Router internal did not match", 2, target.router(ROUTER_NAME).internal().size());
target.updateRouter(ROUTER);
assertEquals("Number of router did not match", 1, target.routers().size());
assertEquals("Router internal did not match", 0, target.router(ROUTER_NAME).internal().size());
validateEvents(KUBEVIRT_ROUTER_CREATED, KUBEVIRT_ROUTER_UPDATED,
KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED, KUBEVIRT_ROUTER_UPDATED,
KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED);
}
@Test
public void testRouterInternalShrink() {
target.createRouter(ROUTER_WITH_INTERNAL);
assertEquals("Number of router did not match", 1, target.routers().size());
assertEquals("Router internal did not match", 2, target.router(ROUTER_NAME).internal().size());
target.updateRouter(ROUTER_WITH_SINGLE_INTERNAL);
assertEquals("Number of router did not match", 1, target.routers().size());
assertEquals("Router internal did not match", 1, target.router(ROUTER_NAME).internal().size());
validateEvents(KUBEVIRT_ROUTER_CREATED, KUBEVIRT_ROUTER_UPDATED,
KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED);
validateInternalRemoval(ImmutableSet.of("vxlan-2"));
}
/**
* Tests router's external networks attached and detached.
*/
@Test
public void testRouterExternalAttachedAndDetached() {
target.createRouter(ROUTER);
assertEquals("Number of router did not match", 1, target.routers().size());
assertNull(target.router(ROUTER_NAME).peerRouter());
assertEquals(0, target.router(ROUTER_NAME).external().size());
target.updateRouter(ROUTER_WITH_EXTERNAL);
assertEquals("Number of router did not match", 1, target.routers().size());
assertNotNull(target.router(ROUTER_NAME).peerRouter());
assertEquals(1, target.router(ROUTER_NAME).external().size());
target.updateRouter(ROUTER);
assertEquals("Number of router did not match", 1, target.routers().size());
assertNull(target.router(ROUTER_NAME).peerRouter());
assertEquals(0, target.router(ROUTER_NAME).external().size());
validateEvents(KUBEVIRT_ROUTER_CREATED, KUBEVIRT_ROUTER_UPDATED,
KUBEVIRT_ROUTER_EXTERNAL_NETWORK_ATTACHED, KUBEVIRT_ROUTER_UPDATED,
KUBEVIRT_ROUTER_EXTERNAL_NETWORK_DETACHED);
}
/**
* Tests if creating a null router fails with an exception.
*/
@Test(expected = NullPointerException.class)
public void testCreateNullRouter() {
target.createRouter(null);
}
/**
* Tests if creating a duplicate router fails with an exception.
*/
@Test(expected = IllegalArgumentException.class)
public void createDuplicateRouter() {
target.createRouter(ROUTER);
target.createRouter(ROUTER);
}
/**
* Tests if updating an unregistered router fails with an exception.
*/
@Test(expected = IllegalArgumentException.class)
public void testUpdateUnregisteredRouter() {
target.updateRouter(ROUTER);
}
/**
* Tests if updating a null router fails with an exception.
*/
@Test(expected = NullPointerException.class)
public void testUpdateNullRouter() {
target.updateRouter(null);
}
/**
* Tests if getting all floating IPs returns the correct set of floating IPs.
*/
@Test
public void testGetFloatingIps() {
createBasicFloatingIpDisassociated();
assertEquals("Number of floating IPs did not match", 1, target.floatingIps().size());
}
/**
* Tests if getting a floating IP with ID returns the correct floating IP.
*/
@Test
public void testGetFloatingIpById() {
createBasicFloatingIpDisassociated();
assertNotNull("Floating IP did not match", target.floatingIp(FLOATING_IP_ID));
assertNull("Floating IP did not match", target.floatingIp(UNKNOWN_ID));
}
/**
* Tests if getting a floating IP with POD name returns the correct floating IP.
*/
@Test
public void testGetFloatingIpByPodName() {
createBasicFloatingIpAssociated();
assertNotNull("Floating IP did not match", target.floatingIpByPodName(POD_NAME));
assertNull("Floating IP did not match", target.floatingIpByPodName(UNKNOWN_ID));
}
/**
* Tests if getting floating IPs with router name returns the correct floating IPs.
*/
@Test
public void testGetFloatingIpsByRouterName() {
createBasicFloatingIpDisassociated();
assertEquals("Number of floating IPs did not match", 1,
target.floatingIpsByRouter(ROUTER_NAME).size());
}
/**
* Tests creating and removing a floating IP, and checks if it triggers proper events.
*/
@Test
public void testCreateAndRemoveFloatingIp() {
target.createFloatingIp(FLOATING_IP_DISASSOCIATED);
assertEquals("Number of floating IP did not match", 1, target.floatingIps().size());
assertNotNull("Floating IP was not created", target.floatingIp(FLOATING_IP_ID));
target.removeFloatingIp(FLOATING_IP_ID);
assertEquals("Number of floating IP did not match", 0, target.floatingIps().size());
assertNull("Floating IP was not created", target.floatingIp(FLOATING_IP_ID));
validateEvents(KUBEVIRT_FLOATING_IP_CREATED, KUBEVIRT_FLOATING_IP_REMOVED);
}
/**
* Tests associating a floating IP, and checks if it triggers proper events.
*/
@Test
public void testAssociateFloatingIp() {
target.createFloatingIp(FLOATING_IP_DISASSOCIATED);
assertEquals("Number of floating IP did not match", 1, target.floatingIps().size());
assertNotNull("Floating IP was not created", target.floatingIp(FLOATING_IP_ID));
target.updateFloatingIp(FLOATING_IP_ASSOCIATED);
assertEquals("Number of floating IP did not match", 1, target.floatingIps().size());
assertNotNull("Floating IP was not created", target.floatingIp(FLOATING_IP_ID));
validateEvents(KUBEVIRT_FLOATING_IP_CREATED, KUBEVIRT_FLOATING_IP_UPDATED,
KUBEVIRT_FLOATING_IP_ASSOCIATED);
}
/**
* Tests disassociating a floating IP, and checks if it triggers proper events.
*/
@Test
public void testDisassociateFloatingIp() {
target.createFloatingIp(FLOATING_IP_ASSOCIATED);
assertEquals("Number of floating IP did not match", 1, target.floatingIps().size());
assertNotNull("Floating IP was not created", target.floatingIp(FLOATING_IP_ID));
target.updateFloatingIp(FLOATING_IP_DISASSOCIATED);
assertEquals("Number of floating IP did not match", 1, target.floatingIps().size());
assertNotNull("Floating IP was not created", target.floatingIp(FLOATING_IP_ID));
validateEvents(KUBEVIRT_FLOATING_IP_CREATED, KUBEVIRT_FLOATING_IP_UPDATED,
KUBEVIRT_FLOATING_IP_DISASSOCIATED);
}
/**
* Tests if creating a null floating IP fails with an exception.
*/
@Test(expected = NullPointerException.class)
public void testCreateNullFloatingIp() {
target.createFloatingIp(null);
}
/**
* Tests if creating a duplicate floating IP fails with an exception.
*/
@Test(expected = IllegalArgumentException.class)
public void testCreateDuplicateFloatingIp() {
target.createFloatingIp(FLOATING_IP_ASSOCIATED);
target.createFloatingIp(FLOATING_IP_DISASSOCIATED);
}
/**
* Tests if removing floating IP with null ID fails with an exception.
*/
@Test(expected = IllegalArgumentException.class)
public void testRemoveFloatingIpWithNull() {
target.removeFloatingIp(null);
}
/**
* Tests if updating an unregistered floating IP fails with an exception.
*/
@Test(expected = IllegalArgumentException.class)
public void testUpdateUnregisteredFloatingIp() {
target.updateFloatingIp(FLOATING_IP_ASSOCIATED);
}
private void createBasicRouters() {
target.createRouter(ROUTER);
}
private void createBasicFloatingIpDisassociated() {
target.createFloatingIp(FLOATING_IP_DISASSOCIATED);
}
private void createBasicFloatingIpAssociated() {
target.createFloatingIp(FLOATING_IP_ASSOCIATED);
}
private static class TestCoreService extends CoreServiceAdapter {
@Override
public ApplicationId registerApplication(String name) {
return TEST_APP_ID;
}
}
private static class TestKubevirtRouterListener implements KubevirtRouterListener {
private List<KubevirtRouterEvent> events = Lists.newArrayList();
private Set<String> internalAdded = new HashSet<>();
private Set<String> internalRemoved = new HashSet<>();
@Override
public void event(KubevirtRouterEvent event) {
events.add(event);
if (event.type() == KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED) {
internalAdded = event.internal();
}
if (event.type() == KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED) {
internalRemoved = event.internal();
}
}
}
private void validateEvents(Enum... types) {
int i = 0;
assertEquals("Number of events did not match", types.length, testListener.events.size());
for (Event event : testListener.events) {
assertEquals("Incorrect event received", types[i], event.type());
i++;
}
testListener.events.clear();
}
private void validateInternalAddition(Set<String> internal) {
assertEquals("internal addition entries", internal, testListener.internalAdded);
testListener.internalAdded.clear();
}
private void validateInternalRemoval(Set<String> internal) {
assertEquals("internal addition entries", internal, testListener.internalRemoved);
testListener.internalRemoved.clear();
}
}