T3: Adding summary to pingall, false if any of the path in the trace fails and minor fixes

Change-Id: Ifa2777a37dc91ccec3401d1080bd3849878f9734
(cherry picked from commit 6207715317b140dd8d6e324a974c1d8a449c0fb8)
diff --git a/src/main/java/org/onosproject/t3/api/StaticPacketTrace.java b/src/main/java/org/onosproject/t3/api/StaticPacketTrace.java
index 084b25e..22db007 100644
--- a/src/main/java/org/onosproject/t3/api/StaticPacketTrace.java
+++ b/src/main/java/org/onosproject/t3/api/StaticPacketTrace.java
@@ -43,7 +43,7 @@
     private Map<DeviceId, List<FlowEntry>> flowsForDevice;
     private StringBuilder resultMessage;
     private Pair<Host, Host> hosts;
-    private boolean success = false;
+    private List<Boolean> success = new ArrayList<>();
 
     /**
      * Builds the trace with a given packet and a connect point.
@@ -197,21 +197,21 @@
     }
 
     /**
-     * Return if this trace is successful.
+     * Return if all the possible paths of this trace are successful.
      *
-     * @return true if successful
+     * @return true if all paths are successful
      */
     public boolean isSuccess() {
-        return success;
+        return !success.contains(false);
     }
 
     /**
-     * Sets if this trace is successful.
+     * Sets if a path from this trace is successful.
      *
-     * @param success true if trace is successful.
+     * @param success true if a path of trace is successful.
      */
     public void setSuccess(boolean success) {
-        this.success = success;
+        this.success.add(success);
     }
 
 
diff --git a/src/main/java/org/onosproject/t3/cli/TroubleshootPingAllCommand.java b/src/main/java/org/onosproject/t3/cli/TroubleshootPingAllCommand.java
index f8648d0..f9d7376 100644
--- a/src/main/java/org/onosproject/t3/cli/TroubleshootPingAllCommand.java
+++ b/src/main/java/org/onosproject/t3/cli/TroubleshootPingAllCommand.java
@@ -28,6 +28,8 @@
 import org.onosproject.t3.api.TroubleshootService;
 import org.onosproject.t3.impl.Generator;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Set;
 
 import static java.lang.Thread.sleep;
@@ -69,39 +71,27 @@
             //Create the generator for the list of traces.
             Generator<Set<StaticPacketTrace>> generator = service.pingAllGenerator(type);
             Host previousHost = null;
+            int totalTraces = 0;
+            List<StaticPacketTrace> failedTraces = new ArrayList<>();
+            boolean ipv4 = type.equals(EtherType.IPV4);
             while (generator.iterator().hasNext()) {
                 Set<StaticPacketTrace> traces = generator.iterator().next();
+                totalTraces++;
                 for (StaticPacketTrace trace : traces) {
-                    boolean ipv4 = type.equals(EtherType.IPV4);
                     //no verbosity is mininet style output
                     if (!verbosity1 && !verbosity2) {
                         if (trace.getEndpointHosts().isPresent()) {
                             Host src = trace.getEndpointHosts().get().getLeft();
                             if (previousHost == null || !previousHost.equals(src)) {
                                 print("%s", StringUtils.rightPad("", 125, '-'));
-                                IpAddress ipAddress = getIpAddress(trace, ipv4, src, true);
-                                if (ipAddress == null) {
-                                    print("%s", src.id() + " -->");
-                                } else {
-                                    print("%s (%s) -->", src.id(), ipAddress);
-                                }
-                                previousHost = src;
-                            } else {
-                                String host;
-                                IpAddress ipAddress = getIpAddress(trace, ipv4, src, false);
-                                if (ipAddress == null) {
-                                    host = String.format("       %s %s", trace.getEndpointHosts().get().getRight().id(),
-                                            trace.isSuccess());
-                                } else {
-                                    host = String.format("       %s (%s) %s",
-                                            trace.getEndpointHosts().get().getRight().id(), ipAddress,
-                                            trace.isSuccess());
-                                }
-                                if (!trace.isSuccess()) {
-                                    host = host + " " + trace.resultMessage();
-                                }
-                                print("%s", host);
+                                previousHost = printSrc(trace, ipv4, src);
                             }
+                            String host = getDstString(trace, ipv4, src);
+                            if (!trace.isSuccess()) {
+                                host = host + " " + trace.resultMessage();
+                                failedTraces.add(trace);
+                            }
+                            print("%s", host);
                         }
                     } else {
                         print("%s", StringUtils.leftPad("", 125, '-'));
@@ -129,9 +119,48 @@
                 }
             }
             print("%s", StringUtils.rightPad("", 125, '-'));
+            print("Failed Traces: %s", failedTraces.size());
+            print("%s", StringUtils.rightPad("", 125, '-'));
+            failedTraces.forEach(t -> {
+                if (t.getEndpointHosts().isPresent()) {
+                    printSrc(t, ipv4, t.getEndpointHosts().get().getLeft());
+                    String dst = getDstString(t, ipv4, t.getEndpointHosts().get().getRight());
+                    dst = dst + " " + t.resultMessage();
+                    print("%s", dst);
+                    print("%s", StringUtils.rightPad("", 125, '-'));
+                }
+            });
+            print("Summary");
+            print("Total Traces %s, errors %s", totalTraces, failedTraces.size());
         }
     }
 
+    private String getDstString(StaticPacketTrace trace, boolean ipv4, Host src) {
+        String host;
+        IpAddress ipAddress = getIpAddress(trace, ipv4, src, false);
+        if (ipAddress == null) {
+            host = String.format("       %s %s", trace.getEndpointHosts().get().getRight().id(),
+                    trace.isSuccess());
+        } else {
+            host = String.format("       %s (%s) %s",
+                    trace.getEndpointHosts().get().getRight().id(), ipAddress,
+                    trace.isSuccess());
+        }
+        return host;
+    }
+
+    private Host printSrc(StaticPacketTrace trace, boolean ipv4, Host src) {
+        Host previousHost;
+        IpAddress ipAddress = getIpAddress(trace, ipv4, src, true);
+        if (ipAddress == null) {
+            print("%s", src.id() + " -->");
+        } else {
+            print("%s (%s) -->", src.id(), ipAddress);
+        }
+        previousHost = src;
+        return previousHost;
+    }
+
     private IpAddress getIpAddress(StaticPacketTrace trace, boolean ipv4, Host host, boolean src) {
         IpAddress ipAddress;
         if (ipv4) {
diff --git a/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java b/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
index 3564750..b6934ad 100644
--- a/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
+++ b/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
@@ -180,11 +180,14 @@
 
         if (source == null) {
             failTrace.addResultMessage("Source Host " + sourceHost + " does not exist");
+            failTrace.setSuccess(false);
+
             return ImmutableSet.of(failTrace);
         }
 
         if (destination == null) {
             failTrace.addResultMessage("Destination Host " + destinationHost + " does not exist");
+            failTrace.setSuccess(false);
             return ImmutableSet.of(failTrace);
         }
 
@@ -225,6 +228,7 @@
             } else {
                 failTrace.addResultMessage("Host based trace supports only IPv4 or IPv6 as EtherType, " +
                         "please use packet based");
+                failTrace.setSuccess(false);
                 return ImmutableSet.of(failTrace);
             }
 
@@ -236,6 +240,7 @@
             } else {
                 failTrace.addResultMessage("Can't get " + source.location().deviceId() +
                         " router MAC from segment routing config can't perform L3 tracing.");
+                failTrace.setSuccess(false);
             }
             ImmutableSet.Builder<StaticPacketTrace> traces = ImmutableSet.builder();
             source.locations().forEach(hostLocation -> {
@@ -282,6 +287,7 @@
             }
         } else {
             failTrace.addResultMessage("Host " + host + " has no " + etherType + " address");
+            failTrace.setSuccess(false);
             return false;
         }
         return true;
@@ -393,6 +399,7 @@
             trace.addResultMessage("Loop encountered in device " + in.deviceId());
             completePath.add(in);
             trace.addCompletePath(completePath);
+            trace.setSuccess(false);
             return trace;
         }
 
@@ -403,6 +410,7 @@
         if (trace.getGroupOuputs(in.deviceId()) == null) {
             computePath(completePath, trace, null);
             trace.addResultMessage("No output out of device " + in.deviceId() + ". Packet is dropped");
+            trace.setSuccess(false);
             return trace;
         }
 
@@ -424,14 +432,13 @@
                     && ((VlanIdCriterion) trace.getInitialPacket().getCriterion(Criterion.Type.VLAN_VID)).vlanId()
                     .equals(((VlanIdCriterion) outputPath.getFinalPacket().getCriterion(Criterion.Type.VLAN_VID))
                             .vlanId())) {
-                if (computePath(completePath, trace, outputPath.getOutput())) {
+                if (trace.getGroupOuputs(in.deviceId()).size() == 1 &&
+                        computePath(completePath, trace, outputPath.getOutput())) {
                     trace.addResultMessage("Connect point out " + cp + " is same as initial input " + in);
+                    trace.setSuccess(false);
                 }
-                break;
-            }
-
-            //If the two host collections contain the same item it means we reached the proper output
-            if (!Collections.disjoint(hostsList, hosts)) {
+            } else if  (!Collections.disjoint(hostsList, hosts)) {
+                //If the two host collections contain the same item it means we reached the proper output
                 log.debug("Stopping here because host is expected destination {}, reached through", completePath);
                 if (computePath(completePath, trace, outputPath.getOutput())) {
                     trace.addResultMessage("Reached required destination Host " + cp);
@@ -536,6 +543,7 @@
                                 } else {
                                     trace.addResultMessage("Wrong output " + cp + " for required destination ip " +
                                             ipAddress);
+                                    trace.setSuccess(false);
                                 }
                             } else {
                                 trace.addResultMessage("Packet is " + ((EthTypeCriterion) outputPath.getFinalPacket()
@@ -552,6 +560,7 @@
                 log.warn("No links out of {}", cp);
                 computePath(completePath, trace, cp);
                 trace.addResultMessage("No links depart from " + cp + ". Packet is dropped");
+                trace.setSuccess(false);
             }
         }
         return trace;
@@ -712,6 +721,7 @@
         FlowEntry nextTableIdEntry = findNextTableIdEntry(in.deviceId(), -1);
         if (nextTableIdEntry == null) {
             trace.addResultMessage("No flow rules for device " + in.deviceId() + ". Aborting");
+            trace.setSuccess(false);
             return trace;
         }
         TableId tableId = nextTableIdEntry.table();
@@ -743,6 +753,7 @@
                 //(another possibility is max tableId)
                 if (nextTableIdEntry == null && flows.size() == 0) {
                     trace.addResultMessage("No matching flow rules for device " + in.deviceId() + ". Aborting");
+                    trace.setSuccess(false);
                     return trace;
 
                 } else if (nextTableIdEntry == null) {
@@ -761,6 +772,7 @@
             } else if (flowEntry == null) {
                 trace.addResultMessage("Packet has no match on table " + tableId + " in device " +
                         in.deviceId() + ". Dropping");
+                trace.setSuccess(false);
                 return trace;
             } else {
 
@@ -1091,10 +1103,12 @@
             }).findAny().orElse(null);
             if (group == null) {
                 trace.addResultMessage("Null group for Instruction " + instr);
+                trace.setSuccess(false);
                 break;
             }
             if (group.buckets().buckets().size() == 0) {
                 trace.addResultMessage("Group " + group.id() + "has no buckets");
+                trace.setSuccess(false);
                 break;
             }