VOL-812: If fiber is pulled at ONU side, ONU LOS alarm will not get clear from kafka bus.
         ONU state is changed to active. (Refer to VOL-483)
         - When pon cable pulled out from OLT end, LoS event raised for Onu's connected to it
         - When pon cable connected back to OLT, Onu LoS Clear event raised for Onu's if
           Onu Discovery is received and Onu LoS already raised
         - When pon disconnection or connection from Onu end respective Onu LoS Raise/Clear
           Event raised
         - Included Onu serial number while formating onuAlarmIndication event context

Change-Id: Ic1e965da62fb3876ea896788c87d04f376af9e53
diff --git a/VERSION b/VERSION
index 81e9469..ad37abb 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.3.17
+2.3.18
diff --git a/internal/pkg/core/device_handler.go b/internal/pkg/core/device_handler.go
index 0e8d460..625ab63 100644
--- a/internal/pkg/core/device_handler.go
+++ b/internal/pkg/core/device_handler.go
@@ -90,6 +90,7 @@
 	intfID        uint32
 	proxyDeviceID string
 	uniPorts      map[uint32]struct{}
+	losRaised     bool
 }
 
 var pmNames = []string{
@@ -104,7 +105,7 @@
 }
 
 //NewOnuDevice creates a new Onu Device
-func NewOnuDevice(devID, deviceTp, serialNum string, onuID, intfID uint32, proxyDevID string) *OnuDevice {
+func NewOnuDevice(devID, deviceTp, serialNum string, onuID, intfID uint32, proxyDevID string, losRaised bool) *OnuDevice {
 	var device OnuDevice
 	device.deviceID = devID
 	device.deviceType = deviceTp
@@ -113,6 +114,7 @@
 	device.intfID = intfID
 	device.proxyDeviceID = proxyDevID
 	device.uniPorts = make(map[uint32]struct{})
+	device.losRaised = losRaised
 	return &device
 }
 
@@ -769,7 +771,7 @@
 		deviceID = onuDevice.Id
 		proxyDeviceID = onuDevice.ProxyAddress.DeviceId
 		//if not exist in cache, then add to cache.
-		dh.onus.Store(onuKey, NewOnuDevice(deviceID, deviceType, onuDevice.SerialNumber, omciInd.OnuId, omciInd.IntfId, proxyDeviceID))
+		dh.onus.Store(onuKey, NewOnuDevice(deviceID, deviceType, onuDevice.SerialNumber, omciInd.OnuId, omciInd.IntfId, proxyDeviceID, false))
 	} else {
 		//found in cache
 		log.Debugw("omci indication for a device in cache.", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
@@ -922,7 +924,31 @@
 		return olterrors.NewErrInvalidValue(log.Fields{"serial-number": sn}, nil)
 	}
 
+	var alarmInd oop.OnuAlarmIndication
+	raisedTs := time.Now().UnixNano()
 	if _, loaded := dh.discOnus.LoadOrStore(sn, true); loaded {
+
+		/* When PON cable disconnected and connected back from OLT, it was expected OnuAlarmIndication
+		   with "los_status: off" should be raised but BAL does not raise this Alarm hence manually sending
+		   OnuLosClear event on receiving OnuDiscoveryIndication for the Onu after checking whether
+		   OnuLosRaise event sent for it */
+		dh.onus.Range(func(Onukey interface{}, onuInCache interface{}) bool {
+			if onuInCache.(*OnuDevice).serialNumber == sn && onuInCache.(*OnuDevice).losRaised {
+				if onuDiscInd.GetIntfId() != onuInCache.(*OnuDevice).intfID {
+					log.Warnw("ONU-is-on-a-different-intf-id-now", log.Fields{
+						"previousIntfId": onuInCache.(*OnuDevice).intfID,
+						"currentIntfId":  onuDiscInd.GetIntfId()})
+					// TODO:: Should we need to ignore raising OnuLosClear event
+					// when onu connected to different PON?
+				}
+				alarmInd.IntfId = onuInCache.(*OnuDevice).intfID
+				alarmInd.OnuId = onuInCache.(*OnuDevice).onuID
+				alarmInd.LosStatus = statusCheckOff
+				go dh.eventMgr.onuAlarmIndication(&alarmInd, onuInCache.(*OnuDevice).deviceID, raisedTs)
+			}
+			return true
+		})
+
 		log.Warnw("onu-sn-is-already-being-processed", log.Fields{"sn": sn})
 		return nil
 	}
@@ -989,7 +1015,7 @@
 		"intfId": onuDiscInd.GetIntfId(), "sn": sn})
 	onuKey := dh.formOnuKey(onuDiscInd.GetIntfId(), onuID)
 
-	onuDev := NewOnuDevice(onuDevice.Id, onuDevice.Type, onuDevice.SerialNumber, onuID, onuDiscInd.GetIntfId(), onuDevice.ProxyAddress.DeviceId)
+	onuDev := NewOnuDevice(onuDevice.Id, onuDevice.Type, onuDevice.SerialNumber, onuID, onuDiscInd.GetIntfId(), onuDevice.ProxyAddress.DeviceId, false)
 	dh.onus.Store(onuKey, onuDev)
 	log.Debugw("new-onu-device-discovered", log.Fields{"onu": onuDev, "sn": sn})
 
@@ -1059,7 +1085,7 @@
 	if !foundInCache {
 		onuKey := dh.formOnuKey(onuInd.GetIntfId(), onuInd.GetOnuId())
 
-		dh.onus.Store(onuKey, NewOnuDevice(onuDevice.Id, onuDevice.Type, onuDevice.SerialNumber, onuInd.GetOnuId(), onuInd.GetIntfId(), onuDevice.ProxyAddress.DeviceId))
+		dh.onus.Store(onuKey, NewOnuDevice(onuDevice.Id, onuDevice.Type, onuDevice.SerialNumber, onuInd.GetOnuId(), onuInd.GetIntfId(), onuDevice.ProxyAddress.DeviceId, false))
 
 	}
 	if err := dh.updateOnuStates(onuDevice, onuInd); err != nil {
diff --git a/internal/pkg/core/device_handler_test.go b/internal/pkg/core/device_handler_test.go
index 07ada8c..6f84ba2 100644
--- a/internal/pkg/core/device_handler_test.go
+++ b/internal/pkg/core/device_handler_test.go
@@ -672,8 +672,8 @@
 	dh2 := negativeDeviceHandler()
 	dh3 := newMockDeviceHandler()
 	dh3.onus = sync.Map{}
-	dh3.onus.Store("onu1", NewOnuDevice("onu1", "onu1", "onu1", 1, 1, "onu1"))
-	dh3.onus.Store("onu2", NewOnuDevice("onu2", "onu2", "onu2", 2, 2, "onu2"))
+	dh3.onus.Store("onu1", NewOnuDevice("onu1", "onu1", "onu1", 1, 1, "onu1", false))
+	dh3.onus.Store("onu2", NewOnuDevice("onu2", "onu2", "onu2", 2, 2, "onu2", false))
 
 	type args struct {
 		indication *oop.Indication
@@ -1054,6 +1054,11 @@
 	dh1.discOnus = sync.Map{}
 	dh1.discOnus.Store("onu1", true)
 	dh1.discOnus.Store("onu2", false)
+	dh1.discOnus.Store("onu3", true)
+	dh1.discOnus.Store("onu4", true)
+	dh1.onus = sync.Map{}
+	dh1.onus.Store("onu3", NewOnuDevice("onu3", "onu3", "onu3", 3, 3, "onu3", true))
+	dh1.onus.Store("onu4", NewOnuDevice("onu4", "onu4", "onu4", 4, 4, "onu4", true))
 	dh2 := negativeDeviceHandler()
 	type args struct {
 		onuDiscInd *oop.OnuDiscIndication
@@ -1071,7 +1076,9 @@
 		{"onuDiscIndication-4", dh1, args{onuDiscInd: &oop.OnuDiscIndication{}}},
 		{"onuDiscIndication-5", dh1, args{onuDiscInd: &oop.OnuDiscIndication{IntfId: 1, SerialNumber: &oop.SerialNumber{VendorId: []byte("TWSH"), VendorSpecific: []byte("1234")}}, sn: "onu1"}},
 		{"onuDiscIndication-6", dh1, args{onuDiscInd: &oop.OnuDiscIndication{IntfId: 1, SerialNumber: &oop.SerialNumber{VendorId: []byte("TWSH"), VendorSpecific: []byte("1234")}}, sn: "onu2"}},
-		{"onuDiscIndication-7", dh2, args{onuDiscInd: &oop.OnuDiscIndication{IntfId: 1, SerialNumber: &oop.SerialNumber{VendorId: []byte("TWSH"), VendorSpecific: []byte("1234")}}}},
+		{"onuDiscIndication-7", dh1, args{onuDiscInd: &oop.OnuDiscIndication{IntfId: 3, SerialNumber: &oop.SerialNumber{VendorId: []byte("TWSH"), VendorSpecific: []byte("1234")}}, sn: "onu3"}},
+		{"onuDiscIndication-8", dh1, args{onuDiscInd: &oop.OnuDiscIndication{IntfId: 3, SerialNumber: &oop.SerialNumber{VendorId: []byte("TWSH"), VendorSpecific: []byte("1234")}}, sn: "onu4"}},
+		{"onuDiscIndication-9", dh2, args{onuDiscInd: &oop.OnuDiscIndication{IntfId: 1, SerialNumber: &oop.SerialNumber{VendorId: []byte("TWSH"), VendorSpecific: []byte("1234")}}}},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/internal/pkg/core/openolt_eventmgr.go b/internal/pkg/core/openolt_eventmgr.go
index a44d639..82f300e 100644
--- a/internal/pkg/core/openolt_eventmgr.go
+++ b/internal/pkg/core/openolt_eventmgr.go
@@ -207,7 +207,11 @@
 }
 
 func (em *OpenOltEventMgr) oltLosIndication(oltLos *oop.LosIndication, deviceID string, raisedTs int64) error {
+	var err error = nil
 	var de voltha.DeviceEvent
+	var alarmInd oop.OnuAlarmIndication
+	ponIntdID := PortNoToIntfID(oltLos.IntfId, voltha.Port_PON_OLT)
+
 	context := make(map[string]string)
 	/* Populating event context */
 	context["intf-id"] = strconv.FormatUint(uint64(oltLos.IntfId), base10)
@@ -216,6 +220,24 @@
 	de.ResourceId = deviceID
 	if oltLos.Status == statusCheckOn {
 		de.DeviceEventName = fmt.Sprintf("%s_%s", oltLosEvent, "RAISE_EVENT")
+
+		/* When PON cable disconnected from OLT, it was expected OnuAlarmIndication
+		   with "los_status: on" should be raised for each Onu connected to the PON
+		   but BAL does not raise this Alarm hence manually sending OnuLosRaise event
+		   for all the ONU's connected to PON on receiving LoSIndication for PON */
+		em.handler.onus.Range(func(Onukey interface{}, onuInCache interface{}) bool {
+			if onuInCache.(*OnuDevice).intfID == ponIntdID {
+				alarmInd.IntfId = ponIntdID
+				alarmInd.OnuId = onuInCache.(*OnuDevice).onuID
+				alarmInd.LosStatus = statusCheckOn
+				err = em.onuAlarmIndication(&alarmInd, deviceID, raisedTs)
+			}
+			return true
+		})
+		if err != nil {
+			/* Return if any error encountered while processing ONU LoS Event*/
+			return err
+		}
 	} else {
 		de.DeviceEventName = fmt.Sprintf("%s_%s", oltLosEvent, "CLEAR_EVENT")
 	}
@@ -254,40 +276,120 @@
 	return nil
 }
 
+//wasLosRaised checks whether los raised already. If already raised returns true else false
+func (em *OpenOltEventMgr) wasLosRaised(onuAlarm *oop.OnuAlarmIndication) bool {
+	onuKey := em.handler.formOnuKey(onuAlarm.IntfId, onuAlarm.OnuId)
+	if onuInCache, ok := em.handler.onus.Load(onuKey); ok {
+		log.Debugw("onu-device-found-in-cache.", log.Fields{"intfID": onuAlarm.IntfId, "onuID": onuAlarm.OnuId})
+
+		if onuAlarm.LosStatus == statusCheckOn {
+			if onuInCache.(*OnuDevice).losRaised {
+				log.Warnw("onu-los-raised-already", log.Fields{"onu_id": onuAlarm.OnuId,
+					"intf_id": onuAlarm.IntfId, "LosStatus": onuAlarm.LosStatus})
+				return true
+			}
+			return false
+		}
+	}
+	return true
+}
+
+//wasLosCleared checks whether los cleared already. If already cleared returns true else false
+func (em *OpenOltEventMgr) wasLosCleared(onuAlarm *oop.OnuAlarmIndication) bool {
+	onuKey := em.handler.formOnuKey(onuAlarm.IntfId, onuAlarm.OnuId)
+	if onuInCache, ok := em.handler.onus.Load(onuKey); ok {
+		log.Debugw("onu-device-found-in-cache.", log.Fields{"intfID": onuAlarm.IntfId, "onuID": onuAlarm.OnuId})
+
+		if onuAlarm.LosStatus == statusCheckOff {
+			if !onuInCache.(*OnuDevice).losRaised {
+				log.Warnw("onu-los-cleared-already", log.Fields{"onu_id": onuAlarm.OnuId,
+					"intf_id": onuAlarm.IntfId, "LosStatus": onuAlarm.LosStatus})
+				return true
+			}
+			return false
+		}
+	}
+	return true
+}
+
+func (em *OpenOltEventMgr) getDeviceEventName(onuAlarm *oop.OnuAlarmIndication) string {
+	var deviceEventName string
+	if onuAlarm.LosStatus == statusCheckOn {
+		deviceEventName = fmt.Sprintf("%s_%s", onuLosEvent, "RAISE_EVENT")
+	} else if onuAlarm.LosStatus == statusCheckOff {
+		deviceEventName = fmt.Sprintf("%s_%s", onuLosEvent, "CLEAR_EVENT")
+	} else if onuAlarm.LobStatus == statusCheckOn {
+		deviceEventName = fmt.Sprintf("%s_%s", onuLobEvent, "RAISE_EVENT")
+	} else if onuAlarm.LobStatus == statusCheckOff {
+		deviceEventName = fmt.Sprintf("%s_%s", onuLobEvent, "CLEAR_EVENT")
+	} else if onuAlarm.LopcMissStatus == statusCheckOn {
+		deviceEventName = fmt.Sprintf("%s_%s", onuLopcMissEvent, "RAISE_EVENT")
+	} else if onuAlarm.LopcMissStatus == statusCheckOff {
+		deviceEventName = fmt.Sprintf("%s_%s", onuLopcMissEvent, "CLEAR_EVENT")
+	} else if onuAlarm.LopcMicErrorStatus == statusCheckOn {
+		deviceEventName = fmt.Sprintf("%s_%s", onuLopcMicErrorEvent, "RAISE_EVENT")
+	} else if onuAlarm.LopcMicErrorStatus == statusCheckOff {
+		deviceEventName = fmt.Sprintf("%s_%s", onuLopcMicErrorEvent, "CLEAR_EVENT")
+	} else if onuAlarm.LofiStatus == statusCheckOn {
+		deviceEventName = fmt.Sprintf("%s_%s", onuLossOfFrameEvent, "RAISE_EVENT")
+	} else if onuAlarm.LofiStatus == statusCheckOff {
+		deviceEventName = fmt.Sprintf("%s_%s", onuLossOfFrameEvent, "CLEAR_EVENT")
+	} else if onuAlarm.LoamiStatus == statusCheckOn {
+		deviceEventName = fmt.Sprintf("%s_%s", onuLossOfPloamEvent, "RAISE_EVENT")
+	} else if onuAlarm.LoamiStatus == statusCheckOff {
+		deviceEventName = fmt.Sprintf("%s_%s", onuLossOfPloamEvent, "CLEAR_EVENT")
+	}
+	return deviceEventName
+}
+
 func (em *OpenOltEventMgr) onuAlarmIndication(onuAlarm *oop.OnuAlarmIndication, deviceID string, raisedTs int64) error {
 	var de voltha.DeviceEvent
+	var serialNumber string
 	context := make(map[string]string)
 	/* Populating event context */
 	context["intf-id"] = strconv.FormatUint(uint64(onuAlarm.IntfId), base10)
 	context["onu-id"] = strconv.FormatUint(uint64(onuAlarm.OnuId), base10)
+	serialNumber = ""
+	onuKey := em.handler.formOnuKey(onuAlarm.IntfId, onuAlarm.OnuId)
+	if onu, ok := em.handler.onus.Load(onuKey); ok {
+		serialNumber = onu.(*OnuDevice).serialNumber
+	}
+	context["serial-number"] = serialNumber
+
 	/* Populating device event body */
 	de.Context = context
 	de.ResourceId = deviceID
-	if onuAlarm.LosStatus == statusCheckOn {
-		de.DeviceEventName = fmt.Sprintf("%s_%s", onuLosEvent, "RAISE_EVENT")
-	} else if onuAlarm.LosStatus == statusCheckOff {
-		de.DeviceEventName = fmt.Sprintf("%s_%s", onuLosEvent, "CLEAR_EVENT")
-	} else if onuAlarm.LobStatus == statusCheckOn {
-		de.DeviceEventName = fmt.Sprintf("%s_%s", onuLobEvent, "RAISE_EVENT")
-	} else if onuAlarm.LobStatus == statusCheckOff {
-		de.DeviceEventName = fmt.Sprintf("%s_%s", onuLobEvent, "CLEAR_EVENT")
-	} else if onuAlarm.LopcMissStatus == statusCheckOn {
-		de.DeviceEventName = fmt.Sprintf("%s_%s", onuLopcMissEvent, "RAISE_EVENT")
-	} else if onuAlarm.LopcMissStatus == statusCheckOff {
-		de.DeviceEventName = fmt.Sprintf("%s_%s", onuLopcMissEvent, "CLEAR_EVENT")
-	} else if onuAlarm.LopcMicErrorStatus == statusCheckOn {
-		de.DeviceEventName = fmt.Sprintf("%s_%s", onuLopcMicErrorEvent, "RAISE_EVENT")
-	} else if onuAlarm.LopcMicErrorStatus == statusCheckOff {
-		de.DeviceEventName = fmt.Sprintf("%s_%s", onuLopcMicErrorEvent, "CLEAR_EVENT")
-	} else if onuAlarm.LofiStatus == statusCheckOn {
-		de.DeviceEventName = fmt.Sprintf("%s_%s", onuLossOfFrameEvent, "RAISE_EVENT")
-	} else if onuAlarm.LofiStatus == statusCheckOff {
-		de.DeviceEventName = fmt.Sprintf("%s_%s", onuLossOfFrameEvent, "CLEAR_EVENT")
-	} else if onuAlarm.LoamiStatus == statusCheckOn {
-		de.DeviceEventName = fmt.Sprintf("%s_%s", onuLossOfPloamEvent, "RAISE_EVENT")
-	} else if onuAlarm.LoamiStatus == statusCheckOff {
-		de.DeviceEventName = fmt.Sprintf("%s_%s", onuLossOfPloamEvent, "CLEAR_EVENT")
+	de.DeviceEventName = em.getDeviceEventName(onuAlarm)
+
+	switch onuAlarm.LosStatus {
+	case statusCheckOn:
+		if em.wasLosRaised(onuAlarm) {
+			/* No need to raise Onu Los Event as it might have already raised
+			   or Onu might have deleted */
+			return nil
+		}
+		onuKey := em.handler.formOnuKey(onuAlarm.IntfId, onuAlarm.OnuId)
+		if onuInCache, ok := em.handler.onus.Load(onuKey); ok {
+			/* Update onu device with LoS raised state as true */
+			em.handler.onus.Store(onuKey, NewOnuDevice(onuInCache.(*OnuDevice).deviceID, onuInCache.(*OnuDevice).deviceType,
+				onuInCache.(*OnuDevice).serialNumber, onuInCache.(*OnuDevice).onuID, onuInCache.(*OnuDevice).intfID,
+				onuInCache.(*OnuDevice).proxyDeviceID, true))
+		}
+	case statusCheckOff:
+		if em.wasLosCleared(onuAlarm) {
+			/* No need to clear Onu Los Event as it might have already cleared
+			   or Onu might have deleted */
+			return nil
+		}
+		onuKey := em.handler.formOnuKey(onuAlarm.IntfId, onuAlarm.OnuId)
+		if onuInCache, ok := em.handler.onus.Load(onuKey); ok {
+			/* Update onu device with LoS raised state as false */
+			em.handler.onus.Store(onuKey, NewOnuDevice(onuInCache.(*OnuDevice).deviceID, onuInCache.(*OnuDevice).deviceType,
+				onuInCache.(*OnuDevice).serialNumber, onuInCache.(*OnuDevice).onuID, onuInCache.(*OnuDevice).intfID,
+				onuInCache.(*OnuDevice).proxyDeviceID, false))
+		}
 	}
+
 	/* Send event to KAFKA */
 	if err := em.eventProxy.SendDeviceEvent(&de, communication, onu, raisedTs); err != nil {
 		log.Errorw("Failed to send ONU Los event", log.Fields{"onu-id": onuAlarm.OnuId, "intf-id": onuAlarm.IntfId})
diff --git a/internal/pkg/core/openolt_eventmgr_test.go b/internal/pkg/core/openolt_eventmgr_test.go
index 745ce3d..16f058f 100644
--- a/internal/pkg/core/openolt_eventmgr_test.go
+++ b/internal/pkg/core/openolt_eventmgr_test.go
@@ -28,16 +28,19 @@
 
 func mockEventMgr() *OpenOltEventMgr {
 	ep := &mocks.MockEventProxy{}
-	dh := &DeviceHandler{}
+	dh := newMockDeviceHandler()
 	dh.onus = sync.Map{}
 	dh.onus.Store(dh.formOnuKey(1, 1), &OnuDevice{deviceID: "TEST_ONU",
 		deviceType:   "ONU",
 		serialNumber: "TEST_ONU_123",
 		onuID:        1, intfID: 1})
+	dh.onus.Store("1.3", NewOnuDevice("onu3", "onu3", "onu3", 1, 3, "onu3", false))
+	dh.onus.Store("1.4", NewOnuDevice("onu4", "onu4", "onu4", 1, 4, "onu4", false))
 	return NewEventMgr(ep, dh)
 }
 func TestOpenOltEventMgr_ProcessEvents(t *testing.T) {
 	em := mockEventMgr()
+
 	type args struct {
 		alarmInd *oop.AlarmIndication
 		deviceID string
@@ -49,13 +52,17 @@
 	}{
 		// TODO: Add test cases.
 		// LosIndication alarms
-		{"ProcessEvents-", args{alarmInd: &oop.AlarmIndication{Data: &oop.AlarmIndication_LosInd{LosInd: &oop.LosIndication{IntfId: 1, Status: "on"}}}, deviceID: "olt", raisedTs: time.Now().Unix()}},
-		{"ProcessEvents-", args{alarmInd: &oop.AlarmIndication{Data: &oop.AlarmIndication_LosInd{LosInd: &oop.LosIndication{IntfId: 1}}}, deviceID: "olt", raisedTs: time.Now().Unix()}},
-		{"ProcessEvents-", args{alarmInd: &oop.AlarmIndication{Data: &oop.AlarmIndication_LosInd{LosInd: &oop.LosIndication{IntfId: 1, Status: "on"}}}}},
+		/* Pon Interface ID from Openolt agent is sent as port no while raising LoSIndication hence following same in test to have similar behavior
+		   0x2 << 28 ^ 536870913 = 1 --> pon Intf Id*/
+		{"ProcessEvents-", args{alarmInd: &oop.AlarmIndication{Data: &oop.AlarmIndication_LosInd{LosInd: &oop.LosIndication{IntfId: 536870913, Status: "on"}}}, deviceID: "olt", raisedTs: time.Now().Unix()}},
+		{"ProcessEvents-", args{alarmInd: &oop.AlarmIndication{Data: &oop.AlarmIndication_LosInd{LosInd: &oop.LosIndication{IntfId: 536870913}}}, deviceID: "olt", raisedTs: time.Now().Unix()}},
+		{"ProcessEvents-", args{alarmInd: &oop.AlarmIndication{Data: &oop.AlarmIndication_LosInd{LosInd: &oop.LosIndication{IntfId: 536870913, Status: "on"}}}}},
 
 		// OnuAlarmIndication alams
 		{"ProcessEvents-", args{alarmInd: &oop.AlarmIndication{Data: &oop.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &oop.OnuAlarmIndication{IntfId: 1, OnuId: 3, LosStatus: "on"}}}, deviceID: "olt", raisedTs: time.Now().Unix()}},
 		{"ProcessEvents-", args{alarmInd: &oop.AlarmIndication{Data: &oop.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &oop.OnuAlarmIndication{IntfId: 1, OnuId: 3, LosStatus: "off"}}}, deviceID: "olt", raisedTs: time.Now().Unix()}},
+		// Duplicate test to get onu los already cleared result
+		{"ProcessEvents-", args{alarmInd: &oop.AlarmIndication{Data: &oop.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &oop.OnuAlarmIndication{IntfId: 1, OnuId: 3, LosStatus: "off"}}}, deviceID: "olt", raisedTs: time.Now().Unix()}},
 		{"ProcessEvents-", args{alarmInd: &oop.AlarmIndication{Data: &oop.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &oop.OnuAlarmIndication{IntfId: 1, OnuId: 3, LobStatus: "on"}}}, deviceID: "olt", raisedTs: time.Now().Unix()}},
 		{"ProcessEvents-", args{alarmInd: &oop.AlarmIndication{Data: &oop.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &oop.OnuAlarmIndication{IntfId: 1, OnuId: 3, LobStatus: "off"}}}, deviceID: "olt", raisedTs: time.Now().Unix()}},
 		{"ProcessEvents-", args{alarmInd: &oop.AlarmIndication{Data: &oop.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &oop.OnuAlarmIndication{IntfId: 1, OnuId: 3, LopcMissStatus: "on"}}}, deviceID: "olt", raisedTs: time.Now().Unix()}},