[ONOS-641] Update RouteEntryTest and RouterTest to include IPv6 as well

Change-Id: I51aad28cc830074597a2a8eea252ca61f6b06586
diff --git a/apps/routing-api/src/test/java/org/onosproject/routing/RouteEntryTest.java b/apps/routing-api/src/test/java/org/onosproject/routing/RouteEntryTest.java
index c47d276..b89eb2d 100644
--- a/apps/routing-api/src/test/java/org/onosproject/routing/RouteEntryTest.java
+++ b/apps/routing-api/src/test/java/org/onosproject/routing/RouteEntryTest.java
@@ -19,10 +19,15 @@
 import org.junit.Test;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.Ip6Address;
+import org.onlab.packet.Ip6Prefix;
 
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.not;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * Unit tests for the RouteEntry class.
@@ -35,17 +40,22 @@
     public void testConstructor() {
         Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
         Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-
         RouteEntry routeEntry = new RouteEntry(prefix, nextHop);
         assertThat(routeEntry.toString(),
                    is("RouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8}"));
+
+        Ip6Prefix prefix6 = Ip6Prefix.valueOf("1000::/64");
+        Ip6Address nextHop6 = Ip6Address.valueOf("2000::1");
+        RouteEntry routeEntry6 = new RouteEntry(prefix6, nextHop6);
+        assertThat(routeEntry6.toString(),
+                   is("RouteEntry{prefix=1000::/64, nextHop=2000::1}"));
     }
 
     /**
      * Tests invalid class constructor for null IPv4 prefix.
      */
     @Test(expected = NullPointerException.class)
-    public void testInvalidConstructorNullPrefix() {
+    public void testInvalidConstructorNullIpv4Prefix() {
         Ip4Prefix prefix = null;
         Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
 
@@ -53,10 +63,21 @@
     }
 
     /**
+     * Tests invalid class constructor for null IPv6 prefix.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testInvalidConstructorNullIpv6Prefix() {
+        Ip6Prefix prefix = null;
+        Ip6Address nextHop = Ip6Address.valueOf("2000::1");
+
+        new RouteEntry(prefix, nextHop);
+    }
+
+    /**
      * Tests invalid class constructor for null IPv4 next-hop.
      */
     @Test(expected = NullPointerException.class)
-    public void testInvalidConstructorNullNextHop() {
+    public void testInvalidConstructorNullIpv4NextHop() {
         Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
         Ip4Address nextHop = null;
 
@@ -64,16 +85,32 @@
     }
 
     /**
+     * Tests invalid class constructor for null IPv6 next-hop.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testInvalidConstructorNullIpv6NextHop() {
+        Ip6Prefix prefix = Ip6Prefix.valueOf("1000::/64");
+        Ip6Address nextHop = null;
+
+        new RouteEntry(prefix, nextHop);
+    }
+
+    /**
      * Tests getting the fields of a route entry.
      */
     @Test
     public void testGetFields() {
         Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
         Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
-
         RouteEntry routeEntry = new RouteEntry(prefix, nextHop);
         assertThat(routeEntry.prefix(), is(prefix));
         assertThat(routeEntry.nextHop(), is(nextHop));
+
+        Ip6Prefix prefix6 = Ip6Prefix.valueOf("1000::/64");
+        Ip6Address nextHop6 = Ip6Address.valueOf("2000::1");
+        RouteEntry routeEntry6 = new RouteEntry(prefix6, nextHop6);
+        assertThat(routeEntry6.prefix(), is(prefix6));
+        assertThat(routeEntry6.nextHop(), is(nextHop6));
     }
 
     /**
@@ -105,6 +142,33 @@
         prefix = Ip4Prefix.valueOf("255.255.255.255/32");
         assertThat(RouteEntry.createBinaryString(prefix),
                    is("11111111111111111111111111111111"));
+
+        Ip6Prefix prefix6;
+        Pattern pattern;
+        Matcher matcher;
+
+        prefix6 = Ip6Prefix.valueOf("::/0");
+        assertThat(RouteEntry.createBinaryString(prefix6), is(""));
+
+        prefix6 = Ip6Prefix.valueOf("2000::1000/112");
+        pattern = Pattern.compile("00100{108}");
+        matcher = pattern.matcher(RouteEntry.createBinaryString(prefix6));
+        assertTrue(matcher.matches());
+
+        prefix6 = Ip6Prefix.valueOf("2000::1000/116");
+        pattern = Pattern.compile("00100{108}0001");
+        matcher = pattern.matcher(RouteEntry.createBinaryString(prefix6));
+        assertTrue(matcher.matches());
+
+        prefix6 = Ip6Prefix.valueOf("2000::2000/116");
+        pattern = Pattern.compile("00100{108}0010");
+        matcher = pattern.matcher(RouteEntry.createBinaryString(prefix6));
+        assertTrue(matcher.matches());
+
+        prefix6 = Ip6Prefix.valueOf("2000::1234/128");
+        pattern = Pattern.compile("00100{108}0001001000110100");
+        matcher = pattern.matcher(RouteEntry.createBinaryString(prefix6));
+        assertTrue(matcher.matches());
     }
 
     /**
@@ -121,6 +185,16 @@
         RouteEntry routeEntry2 = new RouteEntry(prefix2, nextHop2);
 
         assertThat(routeEntry1, is(routeEntry2));
+
+        Ip6Prefix prefix3 = Ip6Prefix.valueOf("1000::/64");
+        Ip6Address nextHop3 = Ip6Address.valueOf("2000::2");
+        RouteEntry routeEntry3 = new RouteEntry(prefix3, nextHop3);
+
+        Ip6Prefix prefix4 = Ip6Prefix.valueOf("1000::/64");
+        Ip6Address nextHop4 = Ip6Address.valueOf("2000::2");
+        RouteEntry routeEntry4 = new RouteEntry(prefix4, nextHop4);
+
+        assertThat(routeEntry3, is(routeEntry4));
     }
 
     /**
@@ -142,6 +216,21 @@
 
         assertThat(routeEntry1, Matchers.is(not(routeEntry2)));
         assertThat(routeEntry1, Matchers.is(not(routeEntry3)));
+
+        Ip6Prefix prefix4 = Ip6Prefix.valueOf("1000::/64");
+        Ip6Address nextHop4 = Ip6Address.valueOf("2000::1");
+        RouteEntry routeEntry4 = new RouteEntry(prefix4, nextHop4);
+
+        Ip6Prefix prefix5 = Ip6Prefix.valueOf("1000::/65");
+        Ip6Address nextHop5 = Ip6Address.valueOf("2000::1");
+        RouteEntry routeEntry5 = new RouteEntry(prefix5, nextHop5);
+
+        Ip6Prefix prefix6 = Ip6Prefix.valueOf("1000::/64");
+        Ip6Address nextHop6 = Ip6Address.valueOf("2000::2");
+        RouteEntry routeEntry6 = new RouteEntry(prefix6, nextHop6);
+
+        assertThat(routeEntry4, Matchers.is(not(routeEntry5)));
+        assertThat(routeEntry4, Matchers.is(not(routeEntry6)));
     }
 
     /**
@@ -155,5 +244,12 @@
 
         assertThat(routeEntry.toString(),
                    is("RouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8}"));
+
+        Ip6Prefix prefix6 = Ip6Prefix.valueOf("1000::/64");
+        Ip6Address nextHop6 = Ip6Address.valueOf("2000::1");
+        RouteEntry routeEntry6 = new RouteEntry(prefix6, nextHop6);
+
+        assertThat(routeEntry6.toString(),
+                   is("RouteEntry{prefix=1000::/64, nextHop=2000::1}"));
     }
 }
diff --git a/apps/routing/src/test/java/org/onosproject/routing/impl/RouterTest.java b/apps/routing/src/test/java/org/onosproject/routing/impl/RouterTest.java
index 45bc309..c73e18c 100644
--- a/apps/routing/src/test/java/org/onosproject/routing/impl/RouterTest.java
+++ b/apps/routing/src/test/java/org/onosproject/routing/impl/RouterTest.java
@@ -22,6 +22,8 @@
 import org.junit.Test;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.Ip6Address;
+import org.onlab.packet.Ip6Prefix;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
@@ -81,6 +83,13 @@
             DeviceId.deviceId("of:0000000000000004"),
             PortNumber.portNumber(1));
 
+    private static final ConnectPoint SW5_ETH1 = new ConnectPoint(
+            DeviceId.deviceId("of:0000000000000005"),
+            PortNumber.portNumber(1));
+
+    private static final ConnectPoint SW6_ETH1 = new ConnectPoint(
+            DeviceId.deviceId("of:0000000000000006"),
+            PortNumber.portNumber(1));
     private Router router;
 
     @Before
@@ -132,7 +141,6 @@
         hostService.startMonitoringIp(host1Address);
         expectLastCall().anyTimes();
 
-
         IpAddress host2Address = IpAddress.valueOf("192.168.20.1");
         Host host2 = new DefaultHost(ProviderId.NONE, HostId.NONE,
                 MacAddress.valueOf("00:00:00:00:00:02"), VlanId.NONE,
@@ -148,7 +156,7 @@
         IpAddress host3Address = IpAddress.valueOf("192.168.40.1");
         Host host3 = new DefaultHost(ProviderId.NONE, HostId.NONE,
                 MacAddress.valueOf("00:00:00:00:00:03"), VlanId.vlanId((short) 1),
-                new HostLocation(SW4_ETH1, 1),
+                new HostLocation(SW3_ETH1, 1),
                 Sets.newHashSet(host3Address));
 
         expect(hostService.getHostsByIp(host3Address))
@@ -156,6 +164,41 @@
         hostService.startMonitoringIp(host3Address);
         expectLastCall().anyTimes();
 
+        IpAddress host4Address = IpAddress.valueOf("1000::1");
+        Host host4 = new DefaultHost(ProviderId.NONE, HostId.NONE,
+                 MacAddress.valueOf("00:00:00:00:00:04"), VlanId.NONE,
+                 new HostLocation(SW4_ETH1, 1),
+                 Sets.newHashSet(host4Address));
+
+        expect(hostService.getHostsByIp(host4Address))
+                .andReturn(Sets.newHashSet(host4)).anyTimes();
+        hostService.startMonitoringIp(host4Address);
+        expectLastCall().anyTimes();
+
+        IpAddress host5Address = IpAddress.valueOf("2000::1");
+        Host host5 = new DefaultHost(ProviderId.NONE, HostId.NONE,
+                 MacAddress.valueOf("00:00:00:00:00:05"), VlanId.NONE,
+                 new HostLocation(SW5_ETH1, 1),
+                 Sets.newHashSet(host5Address));
+
+        expect(hostService.getHostsByIp(host5Address))
+                .andReturn(Sets.newHashSet(host5)).anyTimes();
+        hostService.startMonitoringIp(host5Address);
+        expectLastCall().anyTimes();
+
+        // Next hop on a VLAN
+        IpAddress host6Address = IpAddress.valueOf("3000::1");
+        Host host6 = new DefaultHost(ProviderId.NONE, HostId.NONE,
+                 MacAddress.valueOf("00:00:00:00:00:06"), VlanId.vlanId((short) 1),
+                 new HostLocation(SW6_ETH1, 1),
+                 Sets.newHashSet(host6Address));
+
+        expect(hostService.getHostsByIp(host6Address))
+                .andReturn(Sets.newHashSet(host6)).anyTimes();
+        hostService.startMonitoringIp(host6Address);
+        expectLastCall().anyTimes();
+
+
         // Called during shutdown
         hostService.removeListener(anyObject(HostListener.class));
 
@@ -163,10 +206,10 @@
     }
 
     /**
-     * Tests adding a route entry.
+     * Tests adding a IPv4 route entry.
      */
     @Test
-    public void testRouteAdd() {
+    public void testIpv4RouteAdd() {
         // Construct a route entry
         IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
         IpAddress nextHopIp = Ip4Address.valueOf("192.168.10.1");
@@ -175,7 +218,7 @@
 
         // Expected FIB entry
         FibEntry fibEntry = new FibEntry(prefix, nextHopIp,
-                                         MacAddress.valueOf("00:00:00:00:00:01"));
+                MacAddress.valueOf("00:00:00:00:00:01"));
 
         fibListener.update(Collections.singletonList(new FibUpdate(
                 FibUpdate.Type.UPDATE, fibEntry)), Collections.emptyList());
@@ -188,13 +231,41 @@
         verify(fibListener);
     }
 
+
     /**
-     * Tests updating a route entry.
+     * Tests adding a IPv6 route entry.
+     */
+    @Test
+    public void testIpv6RouteAdd() {
+        // Construct a route entry
+        IpPrefix prefix = Ip6Prefix.valueOf("4000::/64");
+        IpAddress nextHopIp = Ip6Address.valueOf("1000::1");
+
+        RouteEntry routeEntry = new RouteEntry(prefix, nextHopIp);
+
+        // Expected FIB entry
+        FibEntry fibEntry = new FibEntry(prefix, nextHopIp,
+                MacAddress.valueOf("00:00:00:00:00:04"));
+
+        fibListener.update(Collections.singletonList(new FibUpdate(
+                FibUpdate.Type.UPDATE, fibEntry)), Collections.emptyList());
+
+        replay(fibListener);
+
+        router.processRouteUpdates(Collections.singletonList(
+                new RouteUpdate(RouteUpdate.Type.UPDATE, routeEntry)));
+
+        verify(fibListener);
+    }
+
+
+    /**
+     * Tests updating a IPv4 route entry.
      */
     @Test
     public void testRouteUpdate() {
         // Firstly add a route
-        testRouteAdd();
+        testIpv4RouteAdd();
 
         // Route entry with updated next hop for the original prefix
         RouteEntry routeEntryUpdate = new RouteEntry(
@@ -230,12 +301,53 @@
     }
 
     /**
-     * Tests deleting a route entry.
+     * Tests updating a IPv6 route entry.
      */
     @Test
-    public void testRouteDelete() {
+    public void testIpv6RouteUpdate() {
         // Firstly add a route
-        testRouteAdd();
+        testIpv6RouteAdd();
+
+        // Route entry with updated next hop for the original prefix
+        RouteEntry routeEntryUpdate = new RouteEntry(
+                Ip6Prefix.valueOf("4000::/64"),
+                Ip6Address.valueOf("2000::1"));
+
+        // The old FIB entry will be withdrawn
+        FibEntry withdrawFibEntry = new FibEntry(
+                Ip6Prefix.valueOf("4000::/64"), null, null);
+
+        // A new FIB entry will be added
+        FibEntry updateFibEntry = new FibEntry(
+                Ip6Prefix.valueOf("4000::/64"),
+                Ip6Address.valueOf("2000::1"),
+                MacAddress.valueOf("00:00:00:00:00:05"));
+
+        reset(fibListener);
+        fibListener.update(Collections.singletonList(new FibUpdate(
+                                   FibUpdate.Type.UPDATE, updateFibEntry)),
+                           Collections.singletonList(new FibUpdate(
+                                   FibUpdate.Type.DELETE, withdrawFibEntry)));
+        replay(fibListener);
+
+        reset(routingConfigurationService);
+        expect(routingConfigurationService.isIpPrefixLocal(
+                anyObject(IpPrefix.class))).andReturn(false);
+        replay(routingConfigurationService);
+
+        router.processRouteUpdates(Collections.singletonList(new RouteUpdate(
+                RouteUpdate.Type.UPDATE, routeEntryUpdate)));
+
+        verify(fibListener);
+    }
+
+    /**
+     * Tests deleting a IPv4 route entry.
+     */
+    @Test
+    public void testIpv4RouteDelete() {
+        // Firstly add a route
+        testIpv4RouteAdd();
 
         RouteEntry deleteRouteEntry = new RouteEntry(
                 Ip4Prefix.valueOf("1.1.1.0/24"),
@@ -257,10 +369,37 @@
     }
 
     /**
-     * Tests adding a route whose next hop is the local BGP speaker.
+     * Tests deleting a IPv6 route entry.
      */
     @Test
-    public void testLocalRouteAdd() {
+    public void testIpv6RouteDelete() {
+        // Firstly add a route
+        testIpv6RouteAdd();
+
+        RouteEntry deleteRouteEntry = new RouteEntry(
+                Ip6Prefix.valueOf("4000::/64"),
+                Ip6Address.valueOf("1000::1"));
+
+        FibEntry deleteFibEntry = new FibEntry(
+                Ip6Prefix.valueOf("4000::/64"), null, null);
+
+        reset(fibListener);
+        fibListener.update(Collections.emptyList(), Collections.singletonList(
+                new FibUpdate(FibUpdate.Type.DELETE, deleteFibEntry)));
+
+        replay(fibListener);
+
+        router.processRouteUpdates(Collections.singletonList(
+                new RouteUpdate(RouteUpdate.Type.DELETE, deleteRouteEntry)));
+
+        verify(fibListener);
+    }
+
+    /**
+     * Tests adding a IPv4 route whose next hop is the local BGP speaker.
+     */
+    @Test
+    public void testIpv4LocalRouteAdd() {
         // Construct a route entry, the next hop is the local BGP speaker
         RouteEntry routeEntry = new RouteEntry(
                 Ip4Prefix.valueOf("1.1.1.0/24"),
@@ -284,4 +423,33 @@
         assertTrue(router.getRoutes4().contains(routeEntry));
         verify(fibListener);
     }
+
+    /**
+     * Tests adding a IPv6 route whose next hop is the local BGP speaker.
+     */
+    @Test
+    public void testIpv6LocalRouteAdd() {
+        // Construct a route entry, the next hop is the local BGP speaker
+        RouteEntry routeEntry = new RouteEntry(
+                Ip6Prefix.valueOf("4000::/64"),
+                Ip6Address.valueOf("::"));
+
+        // No methods on the FIB listener should be called
+        replay(fibListener);
+
+        reset(routingConfigurationService);
+        expect(routingConfigurationService.isIpPrefixLocal(
+                anyObject(IpPrefix.class))).andReturn(true);
+        replay(routingConfigurationService);
+
+        // Call the processRouteUpdates() method in Router class
+        RouteUpdate routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
+                                                  routeEntry);
+        router.processRouteUpdates(Collections.singletonList(routeUpdate));
+
+        // Verify
+        assertEquals(1, router.getRoutes6().size());
+        assertTrue(router.getRoutes6().contains(routeEntry));
+        verify(fibListener);
+    }
 }