Fix for wipe-out please command ONOS-4653

Change-Id: I26c841f2d67bc915b7e02e6d1e792a7e2d9ea329
diff --git a/cli/src/main/java/org/onosproject/cli/net/WipeOutCommand.java b/cli/src/main/java/org/onosproject/cli/net/WipeOutCommand.java
index c842acf..6da5daa 100644
--- a/cli/src/main/java/org/onosproject/cli/net/WipeOutCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/WipeOutCommand.java
@@ -21,11 +21,18 @@
 import org.onosproject.net.Host;
 import org.onosproject.net.Link;
 import org.onosproject.net.device.DeviceAdminService;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.group.GroupService;
 import org.onosproject.net.host.HostAdminService;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentService;
 import org.onosproject.net.intent.IntentState;
 import org.onosproject.net.link.LinkAdminService;
+import java.util.EnumSet;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import static org.onosproject.net.intent.IntentState.FAILED;
+import static org.onosproject.net.intent.IntentState.WITHDRAWN;
 
 /**
  * Wipes-out the entire network information base, i.e. devices, links, hosts, intents.
@@ -35,7 +42,7 @@
 public class WipeOutCommand extends ClustersListCommand {
 
     private static final String PLEASE = "please";
-
+    private static final EnumSet<IntentState> CAN_PURGE = EnumSet.of(WITHDRAWN, FAILED);
     @Argument(index = 0, name = "please", description = "Confirmation phrase",
             required = false, multiValued = false)
     String please = null;
@@ -49,6 +56,8 @@
 
         wipeOutIntents();
         wipeOutHosts();
+        wipeOutFlows();
+        wipeOutGroups();
         wipeOutDevices();
         wipeOutLinks();
     }
@@ -56,11 +65,38 @@
     private void wipeOutIntents() {
         print("Wiping intents");
         IntentService intentService = get(IntentService.class);
+        final CountDownLatch withdrawLatch;
+        withdrawLatch = new CountDownLatch(1);
         for (Intent intent : intentService.getIntents()) {
             if (intentService.getIntentState(intent.key()) != IntentState.WITHDRAWN) {
                 intentService.withdraw(intent);
+                try { // wait for withdraw event
+                    withdrawLatch.await(5, TimeUnit.SECONDS);
+                } catch (InterruptedException e) {
+                    print("Timed out waiting for intent {} withdraw");
+                }
             }
-            intentService.purge(intent);
+                if (CAN_PURGE.contains(intentService.getIntentState(intent.key()))) {
+                    intentService.purge(intent);
+                }
+            }
+        }
+
+    private void wipeOutFlows() {
+        print("Wiping Flows");
+        FlowRuleService flowRuleService = get(FlowRuleService.class);
+        DeviceAdminService deviceAdminService = get(DeviceAdminService.class);
+        for (Device device : deviceAdminService.getDevices()) {
+            flowRuleService.purgeFlowRules(device.id());
+        }
+    }
+
+    private void wipeOutGroups() {
+        print("Wiping groups");
+        GroupService groupService = get(GroupService.class);
+        DeviceAdminService deviceAdminService = get(DeviceAdminService.class);
+        for (Device device : deviceAdminService.getDevices()) {
+            groupService.purgeGroupEntries(device.id());
         }
     }
 
diff --git a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
index ee8d5a9..02f24c0 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
@@ -63,6 +63,12 @@
     void applyFlowRules(FlowRule... flowRules);
 
     /**
+     * Purges all the flow rules on the specified device.
+     * @param deviceId device identifier
+     */
+    void purgeFlowRules(DeviceId deviceId);
+
+    /**
      * Removes the specified flow rules from their respective devices. If the
      * device is not presently connected to the controller, these flow will
      * be removed once the device reconnects.
diff --git a/core/api/src/main/java/org/onosproject/net/group/GroupService.java b/core/api/src/main/java/org/onosproject/net/group/GroupService.java
index 4163248..88289c9 100644
--- a/core/api/src/main/java/org/onosproject/net/group/GroupService.java
+++ b/core/api/src/main/java/org/onosproject/net/group/GroupService.java
@@ -107,6 +107,12 @@
                                 ApplicationId appId);
 
     /**
+     * Purges all the group entries on the specified device.
+     * @param deviceId device identifier
+     */
+    void purgeGroupEntries(DeviceId deviceId);
+
+    /**
      * Deletes a group associated to an application cookie.
      * GROUP_DELETED or GROUP_DELETE_FAILED notifications would be
      * provided along with cookie depending on the result of the
diff --git a/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java
index 56e5911..68a2049 100644
--- a/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java
@@ -38,6 +38,10 @@
     }
 
     @Override
+    public void purgeFlowRules(DeviceId deviceId){
+    }
+
+    @Override
     public void removeFlowRules(FlowRule... flowRules) {
     }
 
diff --git a/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java b/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
index 93ddf1a..b59bd2c 100644
--- a/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
+++ b/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java
@@ -260,6 +260,12 @@
     }
 
     @Override
+    public void purgeFlowRules(DeviceId deviceId) {
+        checkPermission(FLOWRULE_WRITE);
+        store.purgeFlowRule(deviceId);
+    }
+
+    @Override
     public void removeFlowRules(FlowRule... flowRules) {
         checkPermission(FLOWRULE_WRITE);
 
diff --git a/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java b/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
index e9d76fb..cd0e15d 100644
--- a/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
+++ b/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
@@ -242,6 +242,13 @@
                                      newCookie);
     }
 
+    @Override
+    public void purgeGroupEntries(DeviceId deviceId) {
+        checkPermission(GROUP_WRITE);
+        store.purgeGroupEntry(deviceId);
+    }
+
+
     /**
      * Delete a group associated to an application cookie.
      * GROUP_DELETED or GROUP_DELETE_FAILED notifications would be
diff --git a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
index 47e74e3..c96b343 100644
--- a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
@@ -260,6 +260,22 @@
     }
 
     @Test
+    public void purgeFlowRules() {
+        FlowRule f1 = addFlowRule(1);
+        FlowRule f2 = addFlowRule(2);
+        FlowRule f3 = addFlowRule(3);
+        assertEquals("3 rules should exist", 3, flowCount());
+        FlowEntry fe1 = new DefaultFlowEntry(f1);
+        FlowEntry fe2 = new DefaultFlowEntry(f2);
+        FlowEntry fe3 = new DefaultFlowEntry(f3);
+        providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2, fe3));
+        validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADD_REQUESTED,
+                RULE_ADDED, RULE_ADDED, RULE_ADDED);
+        mgr.purgeFlowRules(DID);
+        assertEquals("0 rule should exist", 0, flowCount());
+    }
+
+    @Test
     public void removeFlowRules() {
         FlowRule f1 = addFlowRule(1);
         FlowRule f2 = addFlowRule(2);
diff --git a/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java b/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
index a171063..13c6c31 100644
--- a/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
@@ -188,6 +188,21 @@
     }
 
     /**
+     * Tests group Purge Operation.
+     */
+    @Test
+    public void testPurgeGroups() {
+        //Test Group creation before AUDIT process
+        testGroupCreationBeforeAudit(DID);
+        programmableTestCleanUp();
+        testAuditWithExtraneousMissingGroups(DID);
+        // Test group add bucket operations
+        testAddBuckets(DID);
+        // Test group Purge operations
+        testPurgeGroupEntry(DID);
+    }
+
+    /**
      * Tests group bucket modifications (additions and deletions) and
      * Tests group deletion.
      */
@@ -507,6 +522,13 @@
         internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATED));
     }
 
+    // Test purge group entry operations
+    private void testPurgeGroupEntry(DeviceId deviceId) {
+        assertEquals(1, Iterables.size(groupService.getGroups(deviceId, appId)));
+        groupService.purgeGroupEntries(deviceId);
+        assertEquals(0, Iterables.size(groupService.getGroups(deviceId, appId)));
+    }
+
     // Test group remove operations
     private void testRemoveGroup(DeviceId deviceId) {
         GroupKey currKey = new DefaultGroupKey("group1RemoveBuckets".getBytes());