[ONOS-7136] Removing Alarms when a device is from ONOS

Change-Id: I0556ca45741f38aacc6aca1d0173941a7e50acae
diff --git a/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/AlarmManager.java b/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/AlarmManager.java
index 2996101..f12bacb 100644
--- a/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/AlarmManager.java
+++ b/apps/faultmanagement/fmmgr/src/main/java/org/onosproject/faultmanagement/impl/AlarmManager.java
@@ -36,8 +36,12 @@
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmProviderService;
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmService;
 import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
+import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.provider.AbstractListenerProviderRegistry;
 import org.onosproject.net.provider.AbstractProviderService;
 import org.slf4j.Logger;
@@ -63,12 +67,19 @@
 
     private final Logger log = getLogger(getClass());
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected MastershipService mastershipService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected AlarmStore store;
 
     protected AlarmStoreDelegate delegate = this::post;
 
+    private InternalDeviceListener deviceListener = new InternalDeviceListener();
+
     //TODO improve implementation of AlarmId
     private final AtomicLong alarmIdGenerator = new AtomicLong(0);
 
@@ -78,11 +89,13 @@
     public void activate() {
         store.setDelegate(delegate);
         eventDispatcher.addSink(AlarmEvent.class, listenerRegistry);
+        deviceService.addListener(deviceListener);
         log.info("Started");
     }
 
     @Deactivate
     public void deactivate() {
+        deviceService.removeListener(deviceListener);
         store.unsetDelegate(delegate);
         eventDispatcher.removeSink(AlarmEvent.class);
         log.info("Stopped");
@@ -215,4 +228,27 @@
             alarms.forEach(alarm -> store.createOrUpdateAlarm(alarm));
         }
     }
+
+    /**
+     * Internal listener for device events.
+     */
+    private class InternalDeviceListener implements DeviceListener {
+
+        @Override
+        public boolean isRelevant(DeviceEvent event) {
+            return event.type().equals(DeviceEvent.Type.DEVICE_REMOVED);
+        }
+
+        @Override
+        public void event(DeviceEvent event) {
+            if (mastershipService.isLocalMaster(event.subject().id())) {
+                log.info("Device {} removed from ONOS, removing all related alarms", event.subject().id());
+                //TODO this can be improved when core supports multiple keys map and gets implemented in AlarmStore
+                store.getAlarms(event.subject().id()).forEach(alarm -> store.removeAlarm(alarm.id()));
+            } else {
+                log.info("This Node is not Master for device {}", event.subject().id());
+            }
+        }
+
+    }
 }
diff --git a/apps/faultmanagement/fmmgr/src/test/java/org/onosproject/faultmanagement/impl/AlarmManagerTest.java b/apps/faultmanagement/fmmgr/src/test/java/org/onosproject/faultmanagement/impl/AlarmManagerTest.java
index 6a3c376..d226c6b 100644
--- a/apps/faultmanagement/fmmgr/src/test/java/org/onosproject/faultmanagement/impl/AlarmManagerTest.java
+++ b/apps/faultmanagement/fmmgr/src/test/java/org/onosproject/faultmanagement/impl/AlarmManagerTest.java
@@ -35,9 +35,17 @@
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmProviderRegistry;
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmProviderService;
 import org.onosproject.incubator.net.faultmanagement.alarm.DefaultAlarm;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.mastership.MastershipServiceAdapter;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
 import org.onosproject.net.NetTestTools;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceServiceAdapter;
 import org.onosproject.net.provider.AbstractProvider;
 import org.onosproject.store.service.TestStorageService;
 
@@ -59,6 +67,7 @@
 public class AlarmManagerTest {
 
     private static final DeviceId DEVICE_ID = DeviceId.deviceId("foo:bar");
+
     private static final String UNIQUE_ID_1 = "unique_id_1";
     private static final String UNIQUE_ID_2 = "unique_id_2";
     private static final AlarmId A_ID = AlarmId.alarmId(DEVICE_ID, UNIQUE_ID_1);
@@ -82,6 +91,10 @@
     private TestProvider provider;
     protected AlarmProviderRegistry registry;
     protected TestListener listener = new TestListener();
+    private final MastershipService mastershipService = new MockMastershipService();
+    protected final MockDeviceService deviceService = new MockDeviceService();
+
+    private final Device device = new MockDevice(DEVICE_ID);
 
     @Rule
     public final ExpectedException exception = ExpectedException.none();
@@ -95,6 +108,8 @@
         registry = manager;
         manager.addListener(listener);
         NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
+        manager.deviceService = deviceService;
+        manager.mastershipService = mastershipService;
         manager.store = alarmStore;
         manager.activate();
         provider = new TestProvider();
@@ -191,6 +206,21 @@
 
     }
 
+    @Test
+    public void testRemoveWhenDeviceRemoved() {
+        providerService.updateAlarmList(DEVICE_ID, ImmutableSet.of(ALARM_B, ALARM_A));
+        verifyGettingSetsOfAlarms(manager, 2, 2);
+        validateEvents(AlarmEvent.Type.CREATED, AlarmEvent.Type.CREATED);
+        Map<Alarm.SeverityLevel, Long> critical2 = new CountsMapBuilder().with(CRITICAL, 2L).create();
+        assertEquals("A critical should be present", critical2, manager.getAlarmCounts());
+        assertEquals("A critical should be present", critical2, manager.getAlarmCounts(DEVICE_ID));
+        deviceService.deviceListener.event(new DeviceEvent(DeviceEvent.Type.DEVICE_REMOVED, device));
+        Map<Alarm.SeverityLevel, Long> zeroAlarms = new CountsMapBuilder().create();
+        assertEquals("The counts should be empty for removed device", zeroAlarms,
+                manager.getAlarmCounts(DEVICE_ID));
+
+    }
+
     private void verifyGettingSetsOfAlarms(AlarmManager am, int expectedTotal, int expectedActive) {
         assertEquals("Incorrect total alarms", expectedTotal, am.getAlarms().size());
         assertEquals("Incorrect active alarms count", expectedActive, am.getActiveAlarms().size());
@@ -229,6 +259,21 @@
     }
 
 
+    private class MockDeviceService extends DeviceServiceAdapter {
+        DeviceListener deviceListener = null;
+
+        @Override
+        public void addListener(DeviceListener listener) {
+            this.deviceListener = listener;
+        }
+
+        @Override
+        public void removeListener(DeviceListener listener) {
+            this.deviceListener = null;
+        }
+    }
+
+
     private class TestProvider extends AbstractProvider implements AlarmProvider {
         private DeviceId deviceReceived;
         private MastershipRole roleReceived;
@@ -242,6 +287,14 @@
         }
     }
 
+    private class MockMastershipService extends MastershipServiceAdapter {
+        int test = 0;
+        @Override
+        public boolean isLocalMaster(DeviceId deviceId) {
+            return true;
+        }
+    }
+
     /**
      * Test listener class to receive alarm events.
      */
@@ -255,4 +308,13 @@
         }
 
     }
+
+    private class MockDevice extends DefaultDevice {
+
+        MockDevice(DeviceId id) {
+            super(null, id, null, null, null, null, null,
+                    null, DefaultAnnotations.EMPTY);
+        }
+
+    }
 }