[ONOS-6371] (vnet) mastership manager tests

Test cases for virtual network mastership manager.

Change-Id: I129dfc7510c3a75fcca0ecd48a33cc77e1a641ce
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkMastershipManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkMastershipManager.java
index 7d973e0..352ae6c 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkMastershipManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkMastershipManager.java
@@ -45,9 +45,9 @@
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Lists.newArrayList;
 import static org.onlab.metrics.MetricsUtil.startTimer;
 import static org.onlab.metrics.MetricsUtil.stopTimer;
 import static org.slf4j.LoggerFactory.getLogger;
@@ -176,11 +176,15 @@
     @Override
     public void balanceRoles() {
         //FIXME: More advanced logic for balancing virtual network roles.
-        List<ControllerNode> nodes = newArrayList(clusterService.getNodes());
+        List<ControllerNode> nodes = clusterService.getNodes().stream()
+                .filter(n -> clusterService.getState(n.id())
+                        .equals(ControllerNode.State.ACTIVE))
+                .collect(Collectors.toList());
+
         nodes.sort(Comparator.comparing(ControllerNode::id));
 
         //Pick a node using network Id,
-        NodeId masterNode = nodes.get((int) (networkId.id() % nodes.size())).id();
+        NodeId masterNode = nodes.get((int) ((networkId.id() - 1) % nodes.size())).id();
 
         List<CompletableFuture<Void>> setRoleFutures = Lists.newLinkedList();
         for (VirtualDevice device : manager.getVirtualDevices(networkId)) {
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkMastershipManagerTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkMastershipManagerTest.java
new file mode 100644
index 0000000..ce9a433
--- /dev/null
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkMastershipManagerTest.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2017-present 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.incubator.net.virtual.impl;
+
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.Futures;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.junit.TestUtils;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.osgi.TestServiceDirectory;
+import org.onlab.packet.IpAddress;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.ClusterServiceAdapter;
+import org.onosproject.cluster.ControllerNode;
+import org.onosproject.cluster.DefaultControllerNode;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.core.CoreService;
+import org.onosproject.event.EventDeliveryService;
+import org.onosproject.incubator.net.virtual.TenantId;
+import org.onosproject.incubator.net.virtual.VirtualNetwork;
+import org.onosproject.incubator.net.virtual.VirtualNetworkMastershipStore;
+import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
+import org.onosproject.incubator.store.virtual.impl.DistributedVirtualNetworkStore;
+import org.onosproject.incubator.store.virtual.impl.SimpleVirtualMastershipStore;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.mastership.MastershipTermService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.NetTestTools;
+import org.onosproject.store.service.TestStorageService;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.onosproject.net.MastershipRole.MASTER;
+import static org.onosproject.net.MastershipRole.STANDBY;
+import static org.onosproject.net.MastershipRole.NONE;
+
+public class VirtualNetworkMastershipManagerTest {
+
+    private static final NodeId NID_LOCAL = new NodeId("local");
+    private static final NodeId NID_OTHER = new NodeId("foo");
+    private static final IpAddress LOCALHOST = IpAddress.valueOf("127.0.0.1");
+
+    private static final TenantId TID = TenantId.tenantId("1");
+
+    private static final DeviceId VDID1 = DeviceId.deviceId("foo:vd1");
+    private static final DeviceId VDID2 = DeviceId.deviceId("foo:vd2");
+    private static final DeviceId VDID3 = DeviceId.deviceId("foo:vd3");
+    private static final DeviceId VDID4 = DeviceId.deviceId("foo:vd4");
+
+    private static final NodeId NID1 = NodeId.nodeId("n1");
+    private static final NodeId NID2 = NodeId.nodeId("n2");
+    private static final NodeId NID3 = NodeId.nodeId("n3");
+    private static final NodeId NID4 = NodeId.nodeId("n4");
+
+    private static final ControllerNode CNODE1 =
+            new DefaultControllerNode(NID1, IpAddress.valueOf("127.0.1.1"));
+    private static final ControllerNode CNODE2 =
+            new DefaultControllerNode(NID2, IpAddress.valueOf("127.0.1.2"));
+    private static final ControllerNode CNODE3 =
+            new DefaultControllerNode(NID3, IpAddress.valueOf("127.0.1.3"));
+    private static final ControllerNode CNODE4 =
+            new DefaultControllerNode(NID4, IpAddress.valueOf("127.0.1.4"));
+
+    private VirtualNetworkManager manager;
+    private DistributedVirtualNetworkStore virtualNetworkManagerStore;
+
+    private VirtualNetworkMastershipManager mastershipMgr1;
+    private VirtualNetworkMastershipManager mastershipMgr2;
+    protected MastershipService service;
+    private TestClusterService testClusterService;
+    private EventDeliveryService eventDeliveryService;
+
+    private VirtualNetwork vnet1;
+    private VirtualNetwork vnet2;
+
+    @Before
+    public void setUp() throws Exception {
+        virtualNetworkManagerStore = new DistributedVirtualNetworkStore();
+
+        CoreService coreService = new TestCoreService();
+        TestUtils.setField(virtualNetworkManagerStore, "coreService", coreService);
+        TestUtils.setField(virtualNetworkManagerStore, "storageService", new TestStorageService());
+        virtualNetworkManagerStore.activate();
+
+        manager = new VirtualNetworkManager();
+        manager.store = virtualNetworkManagerStore;
+        TestUtils.setField(manager, "coreService", coreService);
+
+        eventDeliveryService = new TestEventDispatcher();
+        NetTestTools.injectEventDispatcher(manager, eventDeliveryService);
+
+        SimpleVirtualMastershipStore store = new SimpleVirtualMastershipStore();
+        TestUtils.setField(store, "coreService", coreService);
+        store.activate();
+
+        testClusterService = new TestClusterService();
+
+        ServiceDirectory testDirectory = new TestServiceDirectory()
+                .add(VirtualNetworkStore.class, virtualNetworkManagerStore)
+                .add(CoreService.class, coreService)
+                .add(EventDeliveryService.class, eventDeliveryService)
+                .add(ClusterService.class, testClusterService)
+                .add(VirtualNetworkMastershipStore.class, store);
+        TestUtils.setField(manager, "serviceDirectory", testDirectory);
+
+        manager.activate();
+
+        createVnets();
+
+        mastershipMgr1 = new VirtualNetworkMastershipManager(manager, vnet1.id());
+        mastershipMgr2 = new VirtualNetworkMastershipManager(manager, vnet2.id());
+        service = mastershipMgr1;
+    }
+
+    private void createVnets() {
+        manager.registerTenantId(TID);
+
+        vnet1 = manager.createVirtualNetwork(TID);
+        manager.createVirtualDevice(vnet1.id(), VDID1);
+        manager.createVirtualDevice(vnet1.id(), VDID2);
+
+        vnet2 = manager.createVirtualNetwork(TID);
+        manager.createVirtualDevice(vnet2.id(), VDID3);
+        manager.createVirtualDevice(vnet2.id(), VDID4);
+    }
+
+    @After
+    public void tearDown() {
+        manager.deactivate();
+        virtualNetworkManagerStore.deactivate();
+    }
+
+    @Test
+    public void setRole() {
+        mastershipMgr1.setRole(NID_OTHER, VDID1, MASTER);
+        assertEquals("wrong local role:", NONE, mastershipMgr1.getLocalRole(VDID1));
+        assertEquals("wrong obtained role:", STANDBY, Futures.getUnchecked(mastershipMgr1.requestRoleFor(VDID1)));
+
+        //set to master
+        mastershipMgr1.setRole(NID_LOCAL, VDID1, MASTER);
+        assertEquals("wrong local role:", MASTER, mastershipMgr1.getLocalRole(VDID1));
+    }
+
+    @Test
+    public void relinquishMastership() {
+        //no backups - should just turn to NONE for device.
+        mastershipMgr1.setRole(NID_LOCAL, VDID1, MASTER);
+        assertEquals("wrong role:", MASTER, mastershipMgr1.getLocalRole(VDID1));
+        mastershipMgr1.relinquishMastership(VDID1);
+        assertNull("wrong master:", mastershipMgr1.getMasterFor(VDID2));
+        assertEquals("wrong role:", NONE, mastershipMgr1.getLocalRole(VDID1));
+
+        //not master, nothing should happen
+        mastershipMgr1.setRole(NID_LOCAL, VDID2, NONE);
+        mastershipMgr1.relinquishMastership(VDID2);
+        assertNull("wrong role:", mastershipMgr1.getMasterFor(VDID2));
+
+        //provide NID_OTHER as backup and relinquish
+        mastershipMgr1.setRole(NID_LOCAL, VDID1, MASTER);
+        assertEquals("wrong master:", NID_LOCAL, mastershipMgr1.getMasterFor(VDID1));
+        mastershipMgr1.setRole(NID_OTHER, VDID1, STANDBY);
+        mastershipMgr1.relinquishMastership(VDID1);
+        assertEquals("wrong master:", NID_OTHER, mastershipMgr1.getMasterFor(VDID1));
+    }
+
+    @Test
+    public void requestRoleFor() {
+        mastershipMgr1.setRole(NID_LOCAL, VDID1, MASTER);
+        mastershipMgr1.setRole(NID_OTHER, VDID2, MASTER);
+
+        //local should be master for one but standby for other
+        assertEquals("wrong role:", MASTER, Futures.getUnchecked(mastershipMgr1.requestRoleFor(VDID1)));
+        assertEquals("wrong role:", STANDBY, Futures.getUnchecked(mastershipMgr1.requestRoleFor(VDID2)));
+    }
+
+    @Test
+    public void getMasterFor() {
+        mastershipMgr1.setRole(NID_LOCAL, VDID1, MASTER);
+        mastershipMgr1.setRole(NID_OTHER, VDID2, MASTER);
+        assertEquals("wrong master:", NID_LOCAL, mastershipMgr1.getMasterFor(VDID1));
+        assertEquals("wrong master:", NID_OTHER, mastershipMgr1.getMasterFor(VDID2));
+
+        //have NID_OTHER hand over VDID2 to NID_LOCAL
+        mastershipMgr1.setRole(NID_LOCAL, VDID2, MASTER);
+        assertEquals("wrong master:", NID_LOCAL, mastershipMgr1.getMasterFor(VDID2));
+    }
+
+    @Test
+    public void getDevicesOf() {
+        mastershipMgr1.setRole(NID_LOCAL, VDID1, MASTER);
+        mastershipMgr1.setRole(NID_LOCAL, VDID2, STANDBY);
+        assertEquals("should be one device:", 1, mastershipMgr1.getDevicesOf(NID_LOCAL).size());
+        //hand both devices to NID_LOCAL
+        mastershipMgr1.setRole(NID_LOCAL, VDID2, MASTER);
+        assertEquals("should be two devices:", 2, mastershipMgr1.getDevicesOf(NID_LOCAL).size());
+    }
+
+    @Test
+    public void termService() {
+        MastershipTermService ts = mastershipMgr1;
+
+        //term = 1 for both
+        mastershipMgr1.setRole(NID_LOCAL, VDID1, MASTER);
+        assertEquals("inconsistent term: ", 1,
+                     ts.getMastershipTerm(VDID1).termNumber());
+
+        //hand devices to NID_LOCAL and back: term = 1 + 2
+        mastershipMgr1.setRole(NID_OTHER, VDID1, MASTER);
+        mastershipMgr1.setRole(NID_LOCAL, VDID1, MASTER);
+        assertEquals("inconsistent terms: ",
+                     3, ts.getMastershipTerm(VDID1).termNumber());
+    }
+
+    @Test
+    public void balanceWithVnets() {
+
+        testClusterService.put(CNODE1, ControllerNode.State.ACTIVE);
+        testClusterService.put(CNODE2, ControllerNode.State.ACTIVE);
+
+        mastershipMgr1.setRole(NID_LOCAL, VDID1, MASTER);
+        mastershipMgr1.setRole(NID_LOCAL, VDID2, MASTER);
+        assertEquals("wrong local role:", MASTER, mastershipMgr1.getLocalRole(VDID1));
+        assertEquals("wrong local role:", MASTER, mastershipMgr1.getLocalRole(VDID2));
+        assertEquals("wrong master:", NID_LOCAL, mastershipMgr1.getMasterFor(VDID1));
+        assertEquals("wrong master:", NID_LOCAL, mastershipMgr1.getMasterFor(VDID2));
+
+        //do balancing according to vnet Id.
+        mastershipMgr1.balanceRoles();
+        assertEquals("wrong master:", NID1, mastershipMgr1.getMasterFor(VDID1));
+        assertEquals("wrong master:", NID1, mastershipMgr1.getMasterFor(VDID2));
+
+        mastershipMgr2.setRole(NID_LOCAL, VDID3, MASTER);
+        mastershipMgr2.setRole(NID_LOCAL, VDID4, MASTER);
+        assertEquals("wrong local role:", MASTER, mastershipMgr2.getLocalRole(VDID3));
+        assertEquals("wrong local role:", MASTER, mastershipMgr2.getLocalRole(VDID4));
+        assertEquals("wrong master:", NID_LOCAL, mastershipMgr2.getMasterFor(VDID3));
+        assertEquals("wrong master:", NID_LOCAL, mastershipMgr2.getMasterFor(VDID4));
+
+        //do balancing according to vnet Id.
+        mastershipMgr2.balanceRoles();
+        assertEquals("wrong master:", NID2, mastershipMgr2.getMasterFor(VDID3));
+        assertEquals("wrong master:", NID2, mastershipMgr2.getMasterFor(VDID4));
+
+        // make N1 inactive
+        testClusterService.put(CNODE1, ControllerNode.State.INACTIVE);
+        mastershipMgr1.balanceRoles();
+        assertEquals("wrong master:", NID2, mastershipMgr1.getMasterFor(VDID1));
+        assertEquals("wrong master:", NID2, mastershipMgr1.getMasterFor(VDID2));
+    }
+
+    private final class TestClusterService extends ClusterServiceAdapter {
+
+        final Map<NodeId, ControllerNode> nodes = new HashMap<>();
+        final Map<NodeId, ControllerNode.State> nodeStates = new HashMap<>();
+
+        ControllerNode local = new DefaultControllerNode(NID_LOCAL, LOCALHOST);
+
+        @Override
+        public ControllerNode getLocalNode() {
+            return local;
+        }
+
+        @Override
+        public Set<ControllerNode> getNodes() {
+            return Sets.newHashSet(nodes.values());
+        }
+
+        @Override
+        public ControllerNode getNode(NodeId nodeId) {
+            return nodes.get(nodeId);
+        }
+
+        @Override
+        public ControllerNode.State getState(NodeId nodeId) {
+            return nodeStates.get(nodeId);
+        }
+
+        public void put(ControllerNode cn, ControllerNode.State state) {
+            nodes.put(cn.id(), cn);
+            nodeStates.put(cn.id(), state);
+        }
+    }
+
+    private final class TestSimpleMastershipStore extends SimpleVirtualMastershipStore
+            implements VirtualNetworkMastershipStore {
+
+        public TestSimpleMastershipStore(ClusterService clusterService) {
+            super.clusterService = clusterService;
+        }
+    }
+}
\ No newline at end of file