Repository: telstra/open-kilda
Issue: System is unable to create a protected flow with max_latency strategy

1. Given a topology, that has at least 2 non-overlapping paths
2. Try creating a protected flow with max_latency strategy and non-zero max_latency
```
{
  "flow_id" : "protected_flow_max_lat",
  "source" : {
    "switch_id" : "00:00:00:00:00:00:00:01",
    "port_number" : 13,
    "vlan_id" : 2043
  },
  "destination" : {
    "switch_id" : "00:00:00:00:00:00:00:02",
    "port_number" : 13,
    "vlan_id" : 4014
  },
  "maximum_bandwidth" : 123,
  "max_latency": 11,
  "path_computation_strategy": "max_latency",
  "allocate_protected_path": true
}
```
**Expected:** System is able to create such flow if there are at least 2 paths that match the max_latency SLA
**Actual:** System not able to create such flow, no matter how big max_latency is specified

note: special case with `max_latency: 0` works fine
autotest that reveals the issue is available

Changed files:
src-java/kilda-pce/src/main/java/org/openkilda/pce/impl/AvailableNetwork.java
src-java/kilda-pce/src/test/java/org/openkilda/pce/impl/AvailableNetworkTest.java
src-java/kilda-pce/src/main/java/org/openkilda/pce/AvailableNetworkFactory.java
src-java/kilda-pce/src/test/java/org/openkilda/pce/AvailableNetworkFactoryTest.java

diff --git a/src-java/kilda-pce/src/main/java/org/openkilda/pce/AvailableNetworkFactory.java b/src-java/kilda-pce/src/main/java/org/openkilda/pce/AvailableNetworkFactory.java
index 29a4b0225..def399f25 100644
--- a/src-java/kilda-pce/src/main/java/org/openkilda/pce/AvailableNetworkFactory.java
+++ b/src-java/kilda-pce/src/main/java/org/openkilda/pce/AvailableNetworkFactory.java
@@ -16,6 +16,7 @@
 package org.openkilda.pce;
 
 import org.openkilda.model.Flow;
+import org.openkilda.model.FlowPath;
 import org.openkilda.model.Isl;
 import org.openkilda.model.PathId;
 import org.openkilda.pce.exception.RecoverableException;
@@ -88,7 +89,7 @@ public class AvailableNetworkFactory {
             flowPaths.forEach(pathId ->
                     flowPathRepository.findById(pathId)
                             .ifPresent(flowPath -> {
-                                network.processDiversitySegments(flowPath.getSegments());
+                                network.processDiversitySegments(flowPath.getSegments(), flow);
                                 network.processDiversitySegmentsWithPop(flowPath.getSegments());
                             }));
         }
@@ -96,6 +97,11 @@ public class AvailableNetworkFactory {
         return network;
     }
 
+    private boolean isPrimaryPath(Flow flow, FlowPath flowPath) {
+        return flowPath.getPathId().equals(flow.getForwardPathId())
+                || flowPath.getPathId().equals(flow.getReversePathId());
+    }
+
     private Collection<Isl> getAvailableIsls(BuildStrategy buildStrategy, Flow flow) {
         if (buildStrategy == BuildStrategy.COST) {
             Collection<Isl> isls = flow.isIgnoreBandwidth()
diff --git a/src-java/kilda-pce/src/main/java/org/openkilda/pce/impl/AvailableNetwork.java b/src-java/kilda-pce/src/main/java/org/openkilda/pce/impl/AvailableNetwork.java
index b33692c2f..c7c4936ef 100644
--- a/src-java/kilda-pce/src/main/java/org/openkilda/pce/impl/AvailableNetwork.java
+++ b/src-java/kilda-pce/src/main/java/org/openkilda/pce/impl/AvailableNetwork.java
@@ -15,6 +15,9 @@
 
 package org.openkilda.pce.impl;
 
+import static com.google.common.collect.Sets.newHashSet;
+
+import org.openkilda.model.Flow;
 import org.openkilda.model.Isl;
 import org.openkilda.model.PathSegment;
 import org.openkilda.model.Switch;
@@ -88,15 +91,17 @@ public class AvailableNetwork {
     /**
      * Adds diversity weights into {@link AvailableNetwork} based on passed path segments and configuration.
      */
-    public void processDiversitySegments(List<PathSegment> segments) {
+    public void processDiversitySegments(List<PathSegment> segments, Flow flow) {
+        Set<SwitchId> terminatingSwitches = newHashSet(flow.getSrcSwitchId(), flow.getDestSwitchId());
         for (PathSegment segment : segments) {
             Node srcNode = getSwitch(segment.getSrcSwitchId());
             Node dstNode = getSwitch(segment.getDestSwitchId());
 
-            if (dstNode != null) {
+            if (dstNode != null && !terminatingSwitches.contains(dstNode.getSwitchId())) {
                 dstNode.increaseDiversityGroupUseCounter();
             }
-            if (srcNode != null && segment.getSeqId() == 0) {
+
+            if (srcNode != null && segment.getSeqId() == 0 && !terminatingSwitches.contains(srcNode.getSwitchId())) {
                 srcNode.increaseDiversityGroupUseCounter();
             }
 
diff --git a/src-java/kilda-pce/src/test/java/org/openkilda/pce/AvailableNetworkFactoryTest.java b/src-java/kilda-pce/src/test/java/org/openkilda/pce/AvailableNetworkFactoryTest.java
index 2405ccb4d..dd98393a3 100644
--- a/src-java/kilda-pce/src/test/java/org/openkilda/pce/AvailableNetworkFactoryTest.java
+++ b/src-java/kilda-pce/src/test/java/org/openkilda/pce/AvailableNetworkFactoryTest.java
@@ -142,6 +142,8 @@ public class AvailableNetworkFactoryTest {
         flow.setSrcSwitch(switchA);
         flow.setDestSwitch(switchC);
         flow.setGroupId(GROUP_ID);
+        flow.setForwardPathId(new PathId("forward_path_id"));
+        flow.setReversePathId(new PathId("reverse_path_id"));
 
         when(config.getNetworkStrategy()).thenReturn(BuildStrategy.COST.name());
         when(islRepository.findActiveWithAvailableBandwidth(flow.getBandwidth(), flow.getEncapsulationType()))
@@ -150,8 +152,6 @@ public class AvailableNetworkFactoryTest {
         when(flowPathRepository.findPathIdsByFlowGroupId(GROUP_ID))
                 .thenReturn(Lists.newArrayList(FORWARD_PATH_ID, REVERSE_PATH_ID));
 
-
-
         AvailableNetwork availableNetwork = availableNetworkFactory.getAvailableNetwork(flow, Collections.emptyList());
         assertEquals(2, availableNetwork.getSwitch(switchB.getSwitchId()).getDiversityGroupUseCounter());
     }
diff --git a/src-java/kilda-pce/src/test/java/org/openkilda/pce/impl/AvailableNetworkTest.java b/src-java/kilda-pce/src/test/java/org/openkilda/pce/impl/AvailableNetworkTest.java
index 1a0938a94..aaf1b703b 100644
--- a/src-java/kilda-pce/src/test/java/org/openkilda/pce/impl/AvailableNetworkTest.java
+++ b/src-java/kilda-pce/src/test/java/org/openkilda/pce/impl/AvailableNetworkTest.java
@@ -21,6 +21,7 @@ import static java.util.stream.Collectors.toList;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
 
+import org.openkilda.model.Flow;
 import org.openkilda.model.FlowPath;
 import org.openkilda.model.Isl;
 import org.openkilda.model.IslConfig;
@@ -58,6 +59,12 @@ public class AvailableNetworkTest {
     private static final SwitchId SRC_SWITCH = new SwitchId("00:00:00:22:3d:6c:00:b8");
     private static final SwitchId DST_SWITCH = new SwitchId("00:00:00:22:3d:5a:04:87");
 
+    private static final Flow DUMMY_FLOW = Flow.builder()
+            .flowId("flow-id")
+            .srcSwitch(Switch.builder().switchId(new SwitchId("1")).build())
+            .destSwitch(Switch.builder().switchId(new SwitchId("2")).build())
+            .build();
+
     @Test
     public void shouldNotAllowDuplicates() {
         AvailableNetwork network = new AvailableNetwork();
@@ -149,9 +156,8 @@ public class AvailableNetworkTest {
         addLink(network, DST_SWITCH, SRC_SWITCH, 2, 1, cost, 5);
         addLink(network, DST_SWITCH, SRC_SWITCH, 1, 3, cost, 5);
 
-        network.processDiversitySegments(
-                asList(buildPathWithSegment(SRC_SWITCH, DST_SWITCH, 3, 1, 0),
-                        buildPathWithSegment(DST_SWITCH, SRC_SWITCH, 1, 3, 0)));
+        network.processDiversitySegments(singletonList(buildPathSegment(SRC_SWITCH, DST_SWITCH, 3, 1, 0)), DUMMY_FLOW);
+        network.processDiversitySegments(singletonList(buildPathSegment(DST_SWITCH, SRC_SWITCH, 1, 3, 0)), DUMMY_FLOW);
         network.reduceByWeight(weightFunction);
 
         assertThat(network.getSwitch(SRC_SWITCH).getOutgoingLinks(), Matchers.hasSize(1));
@@ -271,8 +277,8 @@ public class AvailableNetworkTest {
 
 
         network.processDiversitySegmentsWithPop(
-                asList(buildPathWithSegment(SWITCH_1, SWITCH_3, 2, 1, 0),
-                        buildPathWithSegment(SWITCH_3, SWITCH_5, 2, 2, 1)));
+                asList(buildPathSegment(SWITCH_1, SWITCH_3, 2, 1, 0),
+                        buildPathSegment(SWITCH_3, SWITCH_5, 2, 2, 1)));
         for (Edge edge : network.edges) {
             long currentWeight = weightFunction.apply(edge).toLong();
             assertEquals(cost, currentWeight);
@@ -329,7 +335,7 @@ public class AvailableNetworkTest {
         addLink(network, SRC_SWITCH, DST_SWITCH,
                 7, 60, 10, 3);
         network.processDiversitySegments(
-                singletonList(buildPathWithSegment(SRC_SWITCH, DST_SWITCH, 7, 60, 0)));
+                singletonList(buildPathSegment(SRC_SWITCH, DST_SWITCH, 7, 60, 0)), DUMMY_FLOW);
 
         Node srcSwitch = network.getSwitch(SRC_SWITCH);
 
@@ -338,13 +344,35 @@ public class AvailableNetworkTest {
         assertEquals(1, edge.getDestSwitch().getDiversityGroupUseCounter());
     }
 
+    @Test
+    public void shouldFillEmptyDiversityWeightsForTerminatingSwitch() {
+        AvailableNetwork network = new AvailableNetwork();
+        addLink(network, SRC_SWITCH, DST_SWITCH, 7, 60, 10, 3);
+
+        Flow flow = Flow.builder()
+                .flowId("flow-id")
+                .srcSwitch(Switch.builder().switchId(SRC_SWITCH).build())
+                .destSwitch(Switch.builder().switchId(DST_SWITCH).build())
+                .build();
+
+        network.processDiversitySegments(
+                singletonList(buildPathSegment(SRC_SWITCH, DST_SWITCH, 7, 60, 0)), flow);
+
+        Node srcSwitch = network.getSwitch(SRC_SWITCH);
+
+        Edge edge = srcSwitch.getOutgoingLinks().iterator().next();
+        assertEquals(1, edge.getDiversityGroupUseCounter());
+        assertEquals(0, edge.getDestSwitch().getDiversityGroupUseCounter());
+        assertEquals(0, edge.getSrcSwitch().getDiversityGroupUseCounter());
+    }
+
     @Test
     public void shouldFillDiversityWeightsTransit() {
         AvailableNetwork network = new AvailableNetwork();
         addLink(network, SRC_SWITCH, DST_SWITCH,
                 7, 60, 10, 3);
         network.processDiversitySegments(
-                singletonList(buildPathWithSegment(SRC_SWITCH, DST_SWITCH, 7, 60, 1)));
+                singletonList(buildPathSegment(SRC_SWITCH, DST_SWITCH, 7, 60, 1)), DUMMY_FLOW);
 
         Node srcSwitch = network.getSwitch(SRC_SWITCH);
 
@@ -368,8 +396,8 @@ public class AvailableNetworkTest {
         addLink(network, switchB, switchC, 2, 2, 10, 3);
         addLink(network, switchC, switchD, 3, 3, 10, 3);
         network.processDiversitySegments(asList(
-                buildPathWithSegment(switchA, switchB, 1, 1, 0),
-                buildPathWithSegment(switchC, switchD, 3, 3, 0)));
+                buildPathSegment(switchA, switchB, 1, 1, 0),
+                buildPathSegment(switchC, switchD, 3, 3, 0)), DUMMY_FLOW);
 
         Node nodeB = network.getSwitch(switchB);
 
@@ -386,7 +414,7 @@ public class AvailableNetworkTest {
         addLink(network, SRC_SWITCH, DST_SWITCH,
                 7, 60, 10, 3);
         network.processDiversitySegments(
-                singletonList(buildPathWithSegment(SRC_SWITCH, DST_SWITCH, 1, 2, 0)));
+                singletonList(buildPathSegment(SRC_SWITCH, DST_SWITCH, 1, 2, 0)), DUMMY_FLOW);
 
         Node srcSwitch = network.getSwitch(SRC_SWITCH);
 
@@ -420,7 +448,7 @@ public class AvailableNetworkTest {
         network.addLink(isl);
     }
 
-    private PathSegment buildPathWithSegment(SwitchId srcDpid, SwitchId dstDpid, int srcPort, int dstPort, int seqId) {
+    private PathSegment buildPathSegment(SwitchId srcDpid, SwitchId dstDpid, int srcPort, int dstPort, int seqId) {
         return buildPathWithSegment(srcDpid, dstDpid, srcPort, dstPort, null, null, seqId);
     }