Adding first fallback provider for flow rule subsystem.

Fixing onos-check-apps.

Change-Id: Ic8c2bac4403bb7a49813826262706e857932b6c0
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 24ade7e..47e74e3 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
@@ -21,25 +21,28 @@
 import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.junit.TestTools;
 import org.onosproject.cfg.ComponentConfigAdapter;
+import org.onosproject.common.event.impl.TestEventDispatcher;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreServiceAdapter;
 import org.onosproject.core.DefaultApplicationId;
 import org.onosproject.core.IdGenerator;
-import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.mastership.MastershipServiceAdapter;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.DefaultDevice;
 import org.onosproject.net.Device;
 import org.onosproject.net.Device.Type;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.driver.DefaultDriver;
+import org.onosproject.net.driver.impl.DriverManager;
 import org.onosproject.net.flow.CompletedBatchOperation;
 import org.onosproject.net.flow.DefaultFlowEntry;
 import org.onosproject.net.flow.DefaultFlowRule;
@@ -49,6 +52,7 @@
 import org.onosproject.net.flow.FlowRuleBatchOperation;
 import org.onosproject.net.flow.FlowRuleEvent;
 import org.onosproject.net.flow.FlowRuleListener;
+import org.onosproject.net.flow.FlowRuleProgrammable;
 import org.onosproject.net.flow.FlowRuleProvider;
 import org.onosproject.net.flow.FlowRuleProviderRegistry;
 import org.onosproject.net.flow.FlowRuleProviderService;
@@ -65,8 +69,10 @@
 import org.onosproject.store.trivial.SimpleFlowRuleStore;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -76,16 +82,9 @@
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicLong;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 import static org.onosproject.net.NetTestTools.injectEventDispatcher;
-import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_ADDED;
-import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_ADD_REQUESTED;
-import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
-import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVE_REQUESTED;
-import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_UPDATED;
+import static org.onosproject.net.flow.FlowRuleEvent.Type.*;
 
 /**
  * Test codifying the flow rule service & flow rule provider service contracts.
@@ -94,10 +93,19 @@
 
 
     private static final ProviderId PID = new ProviderId("of", "foo");
+    private static final ProviderId FOO_PID = new ProviderId("foo", "foo");
+
     private static final DeviceId DID = DeviceId.deviceId("of:001");
+    private static final DeviceId FOO_DID = DeviceId.deviceId("foo:002");
     private static final int TIMEOUT = 10;
-    private static final Device DEV = new DefaultDevice(
-            PID, DID, Type.SWITCH, "", "", "", "", null);
+
+    private static final DefaultAnnotations ANNOTATIONS =
+            DefaultAnnotations.builder().set(AnnotationKeys.DRIVER, "foo").build();
+
+    private static final Device DEV =
+            new DefaultDevice(PID, DID, Type.SWITCH, "", "", "", "", null);
+    private static final Device FOO_DEV =
+            new DefaultDevice(FOO_PID, FOO_DID, Type.SWITCH, "", "", "", "", null, ANNOTATIONS);
 
     private FlowRuleManager mgr;
 
@@ -108,6 +116,8 @@
     protected TestListener listener = new TestListener();
     private ApplicationId appId;
 
+    private TestDriverManager driverService;
+
 
     @Before
     public void setUp() {
@@ -115,6 +125,7 @@
         mgr.store = new SimpleFlowRuleStore();
         injectEventDispatcher(mgr, new TestEventDispatcher());
         mgr.deviceService = new TestDeviceService();
+        mgr.mastershipService = new TestMastershipService();
         mgr.coreService = new TestCoreService();
         mgr.operationsService = MoreExecutors.newDirectExecutorService();
         mgr.deviceInstallers = MoreExecutors.newDirectExecutorService();
@@ -122,6 +133,12 @@
         service = mgr;
         registry = mgr;
 
+        driverService = new TestDriverManager();
+        driverService.addDriver(new DefaultDriver("foo", ImmutableList.of(), "", "", "",
+                                                  ImmutableMap.of(FlowRuleProgrammable.class,
+                                                                  TestFlowRuleProgrammable.class),
+                                                  ImmutableMap.of()));
+
         mgr.activate(null);
         mgr.addListener(listener);
         provider = new TestProvider(PID);
@@ -143,10 +160,14 @@
     }
 
     private FlowRule flowRule(int tsval, int trval) {
+        return flowRule(DID, tsval, trval);
+    }
+
+    private FlowRule flowRule(DeviceId did, int tsval, int trval) {
         TestSelector ts = new TestSelector(tsval);
         TestTreatment tr = new TestTreatment(trval);
         return DefaultFlowRule.builder()
-                .forDevice(DID)
+                .forDevice(did)
                 .withSelector(ts)
                 .withTreatment(tr)
                 .withPriority(10)
@@ -155,7 +176,6 @@
                 .build();
     }
 
-
     private FlowRule addFlowRule(int hval) {
         FlowRule rule = flowRule(hval, hval);
         service.applyFlowRules(rule);
@@ -229,14 +249,14 @@
         FlowRule r3 = flowRule(3, 3);
 
         assertTrue("store should be empty",
-                Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
+                   Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
         mgr.applyFlowRules(r1, r2, r3);
         assertEquals("3 rules should exist", 3, flowCount());
         assertTrue("Entries should be pending add.",
-                validateState(ImmutableMap.of(
-                        r1, FlowEntryState.PENDING_ADD,
-                        r2, FlowEntryState.PENDING_ADD,
-                        r3, FlowEntryState.PENDING_ADD)));
+                   validateState(ImmutableMap.of(
+                           r1, FlowEntryState.PENDING_ADD,
+                           r2, FlowEntryState.PENDING_ADD,
+                           r3, FlowEntryState.PENDING_ADD)));
     }
 
     @Test
@@ -258,10 +278,10 @@
         validateEvents(RULE_REMOVE_REQUESTED, RULE_REMOVE_REQUESTED);
         assertEquals("3 rule should exist", 3, flowCount());
         assertTrue("Entries should be pending remove.",
-                validateState(ImmutableMap.of(
-                        f1, FlowEntryState.PENDING_REMOVE,
-                        f2, FlowEntryState.PENDING_REMOVE,
-                        f3, FlowEntryState.ADDED)));
+                   validateState(ImmutableMap.of(
+                           f1, FlowEntryState.PENDING_REMOVE,
+                           f2, FlowEntryState.PENDING_REMOVE,
+                           f3, FlowEntryState.ADDED)));
 
         mgr.removeFlowRules(f1);
         assertEquals("3 rule should still exist", 3, flowCount());
@@ -283,7 +303,7 @@
         providerService.flowRemoved(fe1);
 
         validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADDED,
-                RULE_ADDED, RULE_REMOVE_REQUESTED, RULE_REMOVED);
+                       RULE_ADDED, RULE_REMOVE_REQUESTED, RULE_REMOVED);
 
         providerService.flowRemoved(fe1);
         validateEvents();
@@ -322,7 +342,7 @@
                            f3, FlowEntryState.PENDING_ADD)));
 
         validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADD_REQUESTED,
-                RULE_ADDED, RULE_ADDED);
+                       RULE_ADDED, RULE_ADDED);
     }
 
     @Test
@@ -379,7 +399,7 @@
         mgr.applyFlowRules(f1, f2);
 
         assertTrue("should have two rules",
-                Lists.newLinkedList(mgr.getFlowRulesById(appId)).size() == 2);
+                   Lists.newLinkedList(mgr.getFlowRulesById(appId)).size() == 2);
     }
 
     @Test
@@ -398,6 +418,51 @@
                 f2, FlowEntryState.PENDING_REMOVE));
     }
 
+    @Test
+    public void fallbackBasics() {
+        FlowRule f1 = flowRule(FOO_DID, 1, 1);
+        flowRules.clear();
+        mgr.applyFlowRules(f1);
+        assertTrue("flow rule not applied", flowRules.contains(f1));
+
+        flowRules.clear();
+        mgr.removeFlowRules(f1);
+        assertTrue("flow rule not removed", flowRules.contains(f1));
+    }
+
+    @Test
+    public void fallbackFlowRemoved() {
+        FlowRule f1 = flowRule(FOO_DID, 1, 1);
+        mgr.applyFlowRules(f1);
+        flowRules.clear();
+        providerService.flowRemoved(new DefaultFlowEntry(f1));
+        assertTrue("flow rule not reapplied", flowRules.contains(f1));
+    }
+
+    @Test
+    public void fallbackExtraFlow() {
+        FlowRule f1 = flowRule(FOO_DID, 1, 1);
+        flowRules.clear();
+        providerService.pushFlowMetrics(FOO_DID, ImmutableList.of(new DefaultFlowEntry(f1)));
+        assertTrue("flow rule not removed", flowRules.contains(f1));
+    }
+
+    @Test
+    public void fallbackPoll() {
+        FlowRuleDriverProvider fallback = (FlowRuleDriverProvider) mgr.defaultProvider();
+        FlowRule f1 = flowRule(FOO_DID, 1, 1);
+        mgr.applyFlowRules(f1);
+        FlowEntry fe = mgr.getFlowEntries(FOO_DID).iterator().next();
+        assertEquals("incorrect state", FlowEntryState.PENDING_ADD, fe.state());
+
+        fallback.init(fallback.providerService, mgr.deviceService, mgr.mastershipService, 1);
+        TestTools.assertAfter(2000, () -> {
+            FlowEntry e = mgr.getFlowEntries(FOO_DID).iterator().next();
+            assertEquals("incorrect state", FlowEntryState.ADDED, e.state());
+        });
+    }
+
+
     private static class TestListener implements FlowRuleListener {
         final List<FlowRuleEvent> events = new ArrayList<>();
 
@@ -408,50 +473,25 @@
     }
 
     private static class TestDeviceService extends DeviceServiceAdapter {
-
         @Override
         public int getDeviceCount() {
-            return 1;
+            return 2;
         }
 
         @Override
         public Iterable<Device> getDevices() {
-            return Collections.singletonList(DEV);
+            return ImmutableList.of(DEV, FOO_DEV);
+        }
+
+        @Override
+        public Iterable<Device> getAvailableDevices() {
+            return getDevices();
         }
 
         @Override
         public Device getDevice(DeviceId deviceId) {
-            return DEV;
+            return deviceId.equals(FOO_DID) ? FOO_DEV : DEV;
         }
-
-        @Override
-        public MastershipRole getRole(DeviceId deviceId) {
-            return null;
-        }
-
-        @Override
-        public List<Port> getPorts(DeviceId deviceId) {
-            return null;
-        }
-
-        @Override
-        public Port getPort(DeviceId deviceId, PortNumber portNumber) {
-            return null;
-        }
-
-        @Override
-        public boolean isAvailable(DeviceId deviceId) {
-            return false;
-        }
-
-        @Override
-        public void addListener(DeviceListener listener) {
-        }
-
-        @Override
-        public void removeListener(DeviceListener listener) {
-        }
-
     }
 
     private class TestProvider extends AbstractProvider implements FlowRuleProvider {
@@ -474,7 +514,7 @@
 
         @Override
         public void executeBatch(FlowRuleBatchOperation batch) {
-         // TODO: need to call batchOperationComplete
+            // TODO: need to call batchOperationComplete
         }
 
         private class TestInstallationFuture
@@ -624,6 +664,7 @@
         public IdGenerator getIdGenerator(String topic) {
             return new IdGenerator() {
                 private AtomicLong counter = new AtomicLong(0);
+
                 @Override
                 public long getNewId() {
                     return counter.getAndIncrement();
@@ -632,4 +673,41 @@
         }
     }
 
+    private class TestMastershipService extends MastershipServiceAdapter {
+        @Override
+        public MastershipRole getLocalRole(DeviceId deviceId) {
+            return MastershipRole.MASTER;
+        }
+    }
+
+    private class TestDriverManager extends DriverManager {
+        TestDriverManager() {
+            this.deviceService = mgr.deviceService;
+            activate();
+        }
+    }
+
+    static Collection<FlowRule> flowRules = new HashSet<>();
+
+    public static class TestFlowRuleProgrammable extends AbstractHandlerBehaviour implements FlowRuleProgrammable {
+
+        @Override
+        public Collection<FlowEntry> getFlowEntries() {
+            ImmutableList.Builder<FlowEntry> builder = ImmutableList.builder();
+            flowRules.stream().map(DefaultFlowEntry::new).forEach(builder::add);
+            return builder.build();
+        }
+
+        @Override
+        public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
+            flowRules.addAll(rules);
+            return rules;
+        }
+
+        @Override
+        public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rules) {
+            flowRules.addAll(rules);
+            return rules;
+        }
+    }
 }