Eliminate redundant flow programming when host moves

When a host moves from [1A/1, 1B/1] to [1A/2, 1B/1], there is no need to program the pair link flow first.
Also update unit tests to verify this behavior.

Change-Id: I97c7ee5f0db891226c7ed477f5f05af5d6c1faa8
diff --git a/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java b/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java
index ae35f7b..eee9900 100644
--- a/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java
+++ b/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java
@@ -216,8 +216,9 @@
             // Note: Do not continue removing any rule
             Optional<DeviceId> pairDeviceId = srManager.getPairDeviceId(prevLocation.deviceId());
             Optional<PortNumber> pairLocalPort = srManager.getPairLocalPort(prevLocation.deviceId());
-            if (pairDeviceId.isPresent() && pairLocalPort.isPresent() && newLocations.stream()
-                    .anyMatch(location -> location.deviceId().equals(pairDeviceId.get()))) {
+            if (pairDeviceId.isPresent() && pairLocalPort.isPresent() &&
+                    newLocations.stream().anyMatch(location -> location.deviceId().equals(pairDeviceId.get())) &&
+                    newLocations.stream().noneMatch(location -> location.deviceId().equals(prevLocation.deviceId()))) {
                 // NOTE: Since the pairLocalPort is trunk port, use assigned vlan of original port
                 //       when the host is untagged
                 VlanId vlanId = Optional.ofNullable(srManager.getInternalVlanId(prevLocation)).orElse(hostVlanId);
diff --git a/app/src/test/java/org/onosproject/segmentrouting/HostHandlerTest.java b/app/src/test/java/org/onosproject/segmentrouting/HostHandlerTest.java
index fd263bf..f72c264 100644
--- a/app/src/test/java/org/onosproject/segmentrouting/HostHandlerTest.java
+++ b/app/src/test/java/org/onosproject/segmentrouting/HostHandlerTest.java
@@ -548,6 +548,30 @@
     }
 
     @Test
+    public void testDualHomedHostMoveTransient() {
+        Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
+                Sets.newHashSet(HOST_LOC31, HOST_LOC41), Sets.newHashSet(HOST_IP11), false);
+        Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
+                Sets.newHashSet(HOST_LOC32, HOST_LOC41), Sets.newHashSet(HOST_IP11), false);
+        hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
+
+        // Mock DefaultRoutingHandler
+        DefaultRoutingHandler mockDefaultRoutingHandler = createMock(DefaultRoutingHandler.class);
+        hostHandler.srManager.defaultRoutingHandler = mockDefaultRoutingHandler;
+
+        // Host moved from [1A/1, 1B/1] to [1A/2, 1B/1]
+        // We should expect only one bridging flow and one routing flow programmed on 1A
+        mockDefaultRoutingHandler.populateBridging(DEV3, P2, HOST_MAC, HOST_VLAN_UNTAGGED);
+        expectLastCall().times(1);
+        mockDefaultRoutingHandler.populateRoute(DEV3, HOST_IP11.toIpPrefix(), HOST_MAC, HOST_VLAN_UNTAGGED, P2);
+        expectLastCall().times(1);
+        replay(mockDefaultRoutingHandler);
+
+        hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
+        verify(mockDefaultRoutingHandler);
+    }
+
+    @Test
     public void testHostMoveToInvalidLocation() {
         Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
                 Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);