gt:             int [][] linkArray = {
context: /*
   * Copyright (c) 2013 Big Switch Networks, Inc.
   *
   * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html
   *
   * 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.sdnplatform.topology;
  
  import static org.junit.Assert.*;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import org.easymock.EasyMock;
  import static org.easymock.EasyMock.expect;
  import static org.easymock.EasyMock.replay;
  import static org.easymock.EasyMock.verify;
  import org.junit.Before;
  import org.junit.Test;
  import org.sdnplatform.core.IControllerService;
  import org.sdnplatform.core.IOFSwitch;
  import org.sdnplatform.core.module.ModuleContext;
  import org.sdnplatform.core.test.MockControllerProvider;
  import org.sdnplatform.core.test.MockThreadPoolService;
  import org.sdnplatform.linkdiscovery.ILinkDiscoveryService;
  import org.sdnplatform.routing.Route;
  import org.sdnplatform.threadpool.IThreadPoolService;
  import org.sdnplatform.topology.BetterTopologyInstance;
  import org.sdnplatform.topology.BetterTopologyManager;
  import org.sdnplatform.topology.NodePortTuple;
  import org.sdnplatform.topology.OrderedNodePair;
  
  
  
  public class BetterTopologyInstanceTest extends TopologyInstanceTest {
  
      @Before
      public void SetUp() throws Exception {
          fmc = new ModuleContext();
          linkDiscovery = EasyMock.createMock(ILinkDiscoveryService.class);
          mockControllerProvider = new MockControllerProvider();
          fmc.addService(IControllerService.class, mockControllerProvider);
          MockThreadPoolService tp = new MockThreadPoolService();
          fmc.addService(IThreadPoolService.class, tp);
          fmc.addService(ILinkDiscoveryService.class, linkDiscovery);
          topologyManager  = new BetterTopologyManager();
          topologyManager.init(fmc);
          tp.init(fmc);
          tp.startUp(fmc);
      }
  
      private void verifyBroadcastDomains(int [][][] ebd) {
          verifyBroadcastDomains(ebd, true);
      }
  
      private void verifyBroadcastDomains(int [][][] ebd, boolean tunnelsEnabled){
          NodePortTuple npt = null;
          Set<NodePortTuple> expected = new HashSet<NodePortTuple>();
          for(int i=0; i<ebd.length; ++i) {
              int [][] nptList = ebd[i];
              expected.clear();
              for(int j=0; j<nptList.length; ++j) {
                  npt = new NodePortTuple((long)nptList[j][0], (short)nptList[j][1]);
                  expected.add(npt);
              }
              BetterTopologyInstance ti = (BetterTopologyInstance) 
                      topologyManager.getCurrentInstance(tunnelsEnabled);
  
              Set<NodePortTuple> computed = ti.getBroadcastDomainPorts(npt);
  
              if (computed != null)
                  assertTrue(computed.equals(expected));
              else if (computed == null)
                  assertTrue(expected.isEmpty());
          }
      }
  
      private void verifyBlockedPorts(int [][] bports) {
          Set<NodePortTuple> expected = new HashSet<NodePortTuple>();
          for(int i=0; i<bports.length; ++i) {
              int [] entry = bports[i];
              NodePortTuple npt = new NodePortTuple((long)entry[0], (short)entry[1]);
              expected.add(npt);
          }
  
          BetterTopologyInstance ti = (BetterTopologyInstance) topologyManager.getCurrentInstance();
          Set<NodePortTuple> computed = ti.getBlockedPorts();
  
          if (bports.length == 0) {
              assertTrue (ti.getBlockedPorts().isEmpty() == true);
          } else {
              assertTrue(expected.equals(computed));
          }
      }
      
      private void verifyExternalBroadcastPorts (int [][][] ebports) {
          BetterTopologyInstance ti = (BetterTopologyInstance) topologyManager.getCurrentInstance();
          int count;
          for(int i=0; i<ebports.length; ++i) {
              int [][] nptList = ebports[i];
              count = 0;
              for(int j=0; j<nptList.length; ++j) {
                  if (ti.isIncomingBroadcastAllowedOnSwitchPort(
                          (long)nptList[j][0], (short)nptList[j][1])) {
                      count++;
                  }
              }
              assertTrue(count == 0 || count == 1);
          }
      }
  
      private void verifyHigherLevelTopology(int numberOfNodes) {
          BetterTopologyInstance ti = (BetterTopologyInstance) topologyManager.getCurrentInstance();
          assertTrue(ti.getHTNeighbors().keySet().size() == numberOfNodes);
          Set<OrderedNodePair> allowedNodePairs = ti.getAllowedNodePairs();
          assertTrue(allowedNodePairs.size() <= 2*(numberOfNodes-1));
          Map<Long, Map<Long,Long>> nexthop = ti.getNextHopMap();
  
          for(long s: nexthop.keySet()) {
              HashSet<Long> neighbors = new HashSet<Long>(nexthop.get(s).values());
              for(long nbr: neighbors) {
                  if (s == nbr) continue;
                  OrderedNodePair onp = new OrderedNodePair(s,nbr);
                  assertTrue(allowedNodePairs.contains(onp));
                  assertTrue(nexthop.get(s).size() == nexthop.get(nbr).size());
              }
          }
      }
  
      @Test
      public void testBroadcastDomains() throws Exception {
          BetterTopologyManager tm = (BetterTopologyManager) getTopologyManager();
          tm.clear();
          {
              int [][] linkArray = {
                      {1, 2, 2, 1, MULTIHOP_LINK},
                      {2, 1, 1, 2, MULTIHOP_LINK},
                      {2, 2, 3, 1, DIRECT_LINK},
                      {3, 1, 2, 2, DIRECT_LINK},
                      {3, 2, 4, 1, MULTIHOP_LINK},
                      {4, 1, 3, 2, MULTIHOP_LINK},
                      {4, 2, 1, 1, DIRECT_LINK},
                      {1, 1, 4, 2, DIRECT_LINK},
                      {1, 2, 4, 5, MULTIHOP_LINK},
                      {4, 5, 1, 2, MULTIHOP_LINK},
                      {1, 5, 3, 2, MULTIHOP_LINK},
                      {3, 2, 1, 5, MULTIHOP_LINK},
  
              };
              int [][] expectedClusters = {
                      {1,4},
                      {2,3},
              };
              int [][][] ebd = {
                      {{1,2},{2,1},{4,5}},
                      {{1,5},{3,2},{4,1}},
              };
              int [][][] ebports = {
                      {{1,2},{4,5}},
                      {{2,1}},
                      {{3,2}},
                      {{4,1},{1,5}}
              };
              int [][]blockedPorts = {
                      {1,2}, {4,5},
              };
  
              createTopologyFromLinks(linkArray);
  
              topologyManager.updateTopology();
              verifyClusters(expectedClusters);
              verifyBroadcastDomains(ebd, false);
              verifyExternalBroadcastPorts(ebports);
              verifyBlockedPorts(blockedPorts);
              verifyHigherLevelTopology(4); // give the number of nodes
          }
  
          tm.clear();
          {
              int [][] linkArray = {
                      {1, 2, 2, 1, MULTIHOP_LINK},
                      {2, 1, 1, 2, MULTIHOP_LINK},
                      {2, 2, 3, 1, DIRECT_LINK},
                      {3, 1, 2, 2, DIRECT_LINK},
                      {3, 2, 4, 1, MULTIHOP_LINK},
                      {4, 1, 3, 2, MULTIHOP_LINK},
                      {4, 2, 1, 1, DIRECT_LINK},
                      {1, 1, 4, 2, DIRECT_LINK},
  
              };
              int [][] expectedClusters = {
                      {1,4},
                      {2,3},
              };
              int [][][] ebd = {
                      {{1,2},{2,1}},
                      {{3,2},{4,1}},
              };
  
              int [][][] ebports = {
                      {{1,2}},
                      {{2,1}},
                      {{3,2}},
                      {{4,1}},
              };
              int [][]blockedPorts = {
                      {1,2}
              };
              createTopologyFromLinks(linkArray);
              verifyClusters(expectedClusters);
              verifyBroadcastDomains(ebd);
              verifyBlockedPorts(blockedPorts);
              verifyExternalBroadcastPorts(ebports);
          }
  
          // The following are a bit of weird test cases.
          tm.clear();
          {
              int [][] linkArray = {
                      {1, 1, 2, 1, MULTIHOP_LINK},
                      {2, 1, 1, 1, MULTIHOP_LINK},
  
                      {2, 1, 3, 1, DIRECT_LINK},
                      {3, 1, 2, 1, DIRECT_LINK},
  
                      {3, 1, 4, 1, DIRECT_LINK},
                      {4, 1, 3, 1, DIRECT_LINK},
  
                      {4, 1, 5, 1, MULTIHOP_LINK},
                      {5, 1, 4, 1, MULTIHOP_LINK},
  
              };
              int [][] expectedClusters = {
                      {1},
                      {2},
                      {3},
                      {4},
                      {5}
              };
              int [][][] ebd = {
                      {{1,1},{2,1},{3,1},{4,1},{5,1}}
              };
  
              createTopologyFromLinks(linkArray);
              verifyClusters(expectedClusters);
              verifyBroadcastDomains(ebd);
          }
          {
              int [][] linkArray = {
                                    {1, 1, 3, 1, MULTIHOP_LINK},
                                    {3, 1, 1, 1, MULTIHOP_LINK},
              };
              createTopologyFromLinks(linkArray);
              boolean flag = tm.updateTopology();
              assertFalse(flag);
          }
          {
              tm.removeLink((long)1,(short)1,(long)3,(short)1);
              tm.removeLink((long)3,(short)1,(long)1,(short)1);
              boolean flag = tm.updateTopology();
              assertFalse(flag);
          }
          {
              tm.removeLink((long)1,(short)1,(long)2,(short)1);
              tm.removeLink((long)2,(short)1,(long)1,(short)1);
              int [][] expectedClusters = {
                      {2},
                      {3},
                      {4},
                      {5}
              };
              int [][][] ebd = {
                      {{2,1},{3,1},{4,1},{5,1}}
              };
  
              tm.applyUpdates();
              boolean flag = tm.updateTopology();
              assertTrue(flag);
              verifyClusters(expectedClusters);
              verifyBroadcastDomains(ebd);
          }
  
          {
              tm.removeLink((long)4,(short)1,(long)5,(short)1);
              tm.removeLink((long)5,(short)1,(long)4,(short)1);
              int [][] expectedClusters = {
                      {2}, {3}, {4},
              };
              int [][][] ebd = {};
  
              topologyManager.updateTopology();
              verifyClusters(expectedClusters);
              verifyBroadcastDomains(ebd);
          }
  
          {
              tm.removeLink((long)3,(short)1,(long)4,(short)1);
              tm.removeLink((long)4,(short)1,(long)3,(short)1);
              int [][] expectedClusters = {
                      {2,3}, {4},
              };
              int [][][] ebd = {};
  
              topologyManager.updateTopology();
              verifyClusters(expectedClusters);
              verifyBroadcastDomains(ebd);
          }
  
      }
  
      /**
       *  Same test as in sdnplatform, but the tunnel links should be ignored
       *  in the SDN Platform part of the code and must only be used as
       *  needed.
       */
      @Test @Override
      public void testLoopDetectionWithIslands() throws Exception {
  
          //      +-------+             +-------+
          //      |       |             |       |
          //      |   1  1|-------------|1  2   |
          //      |   2   |             |   2   |
          //      +-------+             +-------+
          //          |                     |
          //          |                     |
          //      +-------+                 |
          //      |   1   |                 |
          //      |   3  2|-----------------+
          //      |   3   |
          //      +-------+
          //
          //
          //      +-------+
          //      |   1   |
          //      |   4  2|----------------+
          //      |   3   |                |
          //      +-------+                |
          //          |                    |
          //          |                    |
          //      +-------+             +-------+
          //      |   1   |             |   2   |
          //      |   5  2|-------------|1  6   |
          //      |       |             |       |
          //      +-------+             +-------+
          {
              int [][] linkArray = {
                      {1, 1, 2, 1, DIRECT_LINK},
                      {2, 1, 1, 1, DIRECT_LINK},
                      {1, 2, 3, 1, DIRECT_LINK},
                      {3, 1, 1, 2, DIRECT_LINK},
                      {2, 2, 3, 2, DIRECT_LINK},
                      {3, 2, 2, 2, DIRECT_LINK},
  
                      {4, 2, 6, 2, DIRECT_LINK},
                      {6, 2, 4, 2, DIRECT_LINK},
                      {4, 3, 5, 1, DIRECT_LINK},
                      {5, 1, 4, 3, DIRECT_LINK},
                      {5, 2, 6, 1, DIRECT_LINK},
                      {6, 1, 5, 2, DIRECT_LINK},
  
              };
  
              int [][] expectedClusters = {
                      {1, 2, 3},
                      {4, 5, 6}
              };
              int [][][] expectedBroadcastPorts = {
                      {{1,2}, {3,1}, {1,1}, {2,1}},
                      {{4,2}, {4,3}, {5,1}, {6,2}},
              };
  
              createTopologyFromLinks(linkArray);
              topologyManager.updateTopology();
              verifyClusters(expectedClusters);
              verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts);
  
              BetterTopologyInstance ti = (BetterTopologyInstance)
                      topologyManager.getCurrentInstance(false);
              assertNull(ti.multiroute(3L, 5L, 0));
  
          }
  
          //      +-------+             +-------+
          //      |       |             |       |
          //      |   1  1|-------------|1  2   |
          //      |   2   |             |   2   |
          //      +-------+             +-------+
          //          |                     |
          //          |                     |
          //      +-------+                 |
          //      |   1   |                 |
          //      |   3  2|-----------------+
          //      |   3   |
          //      +-------+
          //          |
          //          |
          //          |
          //      +-------+
          //      |   1   |
          //      |   4  2|----------------+
          //      |   3   |                |
          //      +-------+                |
          //          |                    |
          //          |                    |
          //      +-------+             +-------+
          //      |   1   |             |   2   |
          //      |   5  2|-------------|1  6   |
          //      |       |             |       |
          //      +-------+             +-------+
  
          {
              int [][] linkArray = {
                      {3, 3, 4, 1, DIRECT_LINK},
                      {4, 1, 3, 3, DIRECT_LINK},
  
              };
              int [][] expectedClusters = {
                      {1, 2, 3, 4, 5, 6}
              };
              int [][][] expectedBroadcastPorts = {
                   {{1,1}, {2,1}, {1,2}, {3,1}, {3,3}, {4,1}, 
                         {4,3}, {5,1}, {4,2}, {6,2}}
              };
  
              createTopologyFromLinks(linkArray);
              verifyClusters(expectedClusters);
              verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts);
          }
      }
  
      /**
       * This test ensures that tunnel links are not getting added to topology.
       * @throws Exception
       */
      @Test
      public void testBroadcastDomainLoopDetection() throws Exception {
          BetterTopologyManager tm = (BetterTopologyManager) getTopologyManager();
  
          tm.clear();
          {
              int [][] linkArray = {
                      {1, 2, 2, 1, MULTIHOP_LINK},
                      {2, 1, 1, 2, MULTIHOP_LINK},
  
                      {2, 2, 3, 1, TUNNEL_LINK},
                      {3, 1, 2, 2, TUNNEL_LINK},
  
                      {3, 2, 4, 1, MULTIHOP_LINK},
                      {4, 1, 3, 2, MULTIHOP_LINK},
  
                      {4, 2, 1, 1, TUNNEL_LINK},
                      {1, 1, 4, 2, TUNNEL_LINK},
                      {4, 3, 5, 3, TUNNEL_LINK},
                      {5, 3, 4, 3, TUNNEL_LINK},
                      {5, 4, 6, 4, TUNNEL_LINK},
                      {6, 5, 1, 5, TUNNEL_LINK},
              };
              int [][] expectedClusters = {
                                           {1},{2},{3},{4}
              };
              int [][][] ebd = {
                      {{1,2},{2,1}},
                      {{3,2},{4,1}},
              };
  
              createTopologyFromLinks(linkArray);
  
              verifyClusters(expectedClusters);
              verifyBroadcastDomains(ebd);
              verifyHigherLevelTopology(6); // give the number of nodes
          }
      }
  
      @Test
      public void testBroadcastPortsBetweenClusters() throws Exception {
          //      +-------+             +-------+
          //      |       |             |       |
          //      |   1  1|-------------|1  2   |
          //      |   2   |             |   2   |
          //      +-------+             +-------+
          //          |                     |
          //          |                     |
          //      +-------+                 |
          //      |   1   |                 |
          //      |   3  2|-----------------+
          //      |   3   |
          //      +-------+
          //
          //
          //
          //      +-------+
          //      |   1   |
          //      |   4  2|----------------+
          //      |   3   |                |
          //      +-------+                |
          //          |                    |
          //          |                    |
          //      +-------+             +-------+
          //      |   1   |             |   2   |
          //      |   5  2|-------------|1  6   |
          //      |       |             |       |
          //      +-------+             +-------+
          BetterTopologyManager tm = (BetterTopologyManager) getTopologyManager();
  
          {
              int [][] linkArray = {
                      {1, 1, 2, 1, DIRECT_LINK},
                      {2, 1, 1, 1, DIRECT_LINK},
                      {1, 2, 3, 1, DIRECT_LINK},
                      {3, 1, 1, 2, DIRECT_LINK},
                      {2, 2, 3, 2, DIRECT_LINK},
                      {3, 2, 2, 2, DIRECT_LINK},
  
                      {4, 2, 6, 2, DIRECT_LINK},
                      {6, 2, 4, 2, DIRECT_LINK},
                      {4, 3, 5, 1, DIRECT_LINK},
                      {5, 1, 4, 3, DIRECT_LINK},
                      {5, 2, 6, 1, DIRECT_LINK},
                      {6, 1, 5, 2, DIRECT_LINK},
  
                      {1, 7, 4, 7, DIRECT_LINK},
                      {2, 7, 5, 7, DIRECT_LINK},
                      {3, 7, 6, 7, DIRECT_LINK},
              };
  
              int [][] expectedClusters = {
                      {1, 2, 3},
                      {4, 5, 6}
              };
              int [][][] expectedBroadcastPorts = {
                      {{1,1}, {2,1}, {1,2}, {3,1}},
                      {{4,3}, {5,1}, {4,2}, {6,2}},
              };
  
              // Use the same switch object for all values.
              IOFSwitch sw1 = EasyMock.createMock(IOFSwitch.class);
              Map<Long, IOFSwitch> switchMap = new HashMap<Long, IOFSwitch>();
              switchMap.put(1L, sw1);
              switchMap.put(2L, sw1);
              switchMap.put(3L, sw1);
              switchMap.put(4L, sw1);
              switchMap.put(5L, sw1);
              switchMap.put(6L, sw1);
              expect(linkDiscovery.isTunnelPort(1L, (short)7)).andReturn(false).anyTimes();
              expect(linkDiscovery.isTunnelPort(2L, (short)7)).andReturn(false).anyTimes();
              expect(linkDiscovery.isTunnelPort(3L, (short)7)).andReturn(false).anyTimes();
              expect(linkDiscovery.isTunnelPort(4L, (short)7)).andReturn(false).anyTimes();
              expect(linkDiscovery.isTunnelPort(5L, (short)7)).andReturn(false).anyTimes();
              expect(linkDiscovery.isTunnelPort(6L, (short)7)).andReturn(false).anyTimes();
              mockControllerProvider.setSwitches(switchMap);
              expect(sw1.portEnabled(EasyMock.anyShort())).andReturn(true).anyTimes();
              replay(sw1, linkDiscovery);
  
              createTopologyFromLinks(linkArray);
              verifyClusters(expectedClusters);
              verifyExpectedBroadcastPortsInClusters(expectedBroadcastPorts);
  
  
              assertTrue(tm.isAttachmentPointPort(1L, (short)7));
              assertTrue(tm.isAttachmentPointPort(2L, (short)7));
              assertTrue(tm.isAttachmentPointPort(3L, (short)7));
              assertTrue(tm.isAttachmentPointPort(4L, (short)7));
              assertTrue(tm.isAttachmentPointPort(5L, (short)7));
              assertTrue(tm.isAttachmentPointPort(6L, (short)7));
              verify(sw1, linkDiscovery);
          }
      }
  
      @Test
      public void testUnicastPortMappings() throws Exception {
          BetterTopologyManager tm = (BetterTopologyManager) getTopologyManager();
          tm.clear();
          {
  