[VOL-4302] Marking the software-image as downloaded only if the download completes successfully

Change-Id: I1595ace9a18c728a1d3f58495d9b84c9b32ec655
diff --git a/VERSION b/VERSION
index f8e233b..a5543c6 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.9.0
+1.9.1-dev
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index 11ace9f..e40c854 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -126,6 +126,7 @@
 	CommittedImageEntityId        uint16
 	StandbyImageVersion           string
 	ActiveImageVersion            string
+	InDownloadImageVersion        string
 	CommittedImageVersion         string
 	OmciResponseRate              uint8
 	OmciMsgCounter                uint8
@@ -1016,7 +1017,7 @@
 			}).Trace("received-download-section-request")
 			//Extracting the first 14 bytes to use as a version for this image.
 			if o.ImageSoftwareReceivedSections == 0 {
-				o.StandbyImageVersion = string(msgObj.SectionData[0:14])
+				o.InDownloadImageVersion = string(msgObj.SectionData[0:14])
 			}
 			o.ImageSectionData = append(o.ImageSectionData, msgObj.SectionData...)
 			o.ImageSoftwareReceivedSections++
@@ -1057,58 +1058,8 @@
 			o.ImageSoftwareReceivedSections++
 		}
 	case omci.EndSoftwareDownloadRequestType:
+		success := o.handleEndSoftwareDownloadRequest(msg)
 
-		// In the startSoftwareDownload we get the image size and the window size.
-		// We calculate how many DownloadSection we should receive and validate
-		// that we got the correct amount when we receive this message
-		success := true
-		if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
-			onuLogger.WithFields(log.Fields{
-				"OnuId":            o.ID,
-				"IntfId":           o.PonPortID,
-				"OnuSn":            o.Sn(),
-				"ExpectedSections": o.ImageSoftwareExpectedSections,
-				"ReceivedSections": o.ImageSoftwareReceivedSections,
-			}).Errorf("onu-did-not-receive-all-image-sections")
-			success = false
-		}
-		if success {
-			// Validate Image Crc.
-			msgObj, err := omcilib.ParseEndSoftwareDownloadRequest(msg.OmciPkt)
-			if err != nil {
-				onuLogger.WithFields(log.Fields{
-					"OmciMsgType":  msg.OmciMsg.MessageType,
-					"TransCorrId":  msg.OmciMsg.TransactionID,
-					"Err":          errResp.Error(),
-					"IntfId":       o.PonPortID,
-					"SerialNumber": o.Sn(),
-				}).Error("error-while-processing-end-software-download-request")
-			}
-			computedCRC := crc32a.Checksum(o.ImageSectionData[:int(msgObj.ImageSize)])
-			//Convert the crc to network byte order
-			var byteSlice []byte = make([]byte, 4)
-			binary.LittleEndian.PutUint32(byteSlice, uint32(computedCRC))
-			computedCRC = binary.BigEndian.Uint32(byteSlice)
-
-			onuLogger.WithFields(log.Fields{
-				"OnuId":         o.ID,
-				"IntfId":        o.PonPortID,
-				"OnuSn":         o.Sn(),
-				"ReceivedCRC":   msgObj.CRC32,
-				"CalculatedCRC": computedCRC,
-			}).Debug("onu-image-crc-validation-params")
-
-			if msgObj.CRC32 != computedCRC {
-				onuLogger.WithFields(log.Fields{
-					"OnuId":         o.ID,
-					"IntfId":        o.PonPortID,
-					"OnuSn":         o.Sn(),
-					"ReceivedCRC":   msgObj.CRC32,
-					"CalculatedCRC": computedCRC,
-				}).Errorf("onu-image-crc-validation-falied")
-				success = false
-			}
-		}
 		if success {
 			if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.Success); errResp == nil {
 				o.MibDataSync++
@@ -1127,7 +1078,7 @@
 					"Err":          errResp.Error(),
 					"IntfId":       o.PonPortID,
 					"SerialNumber": o.Sn(),
-				}).Error("error-while-processing-end-software-download-request")
+				}).Error("error-while-responding-to-end-software-download-request")
 			}
 		} else {
 			if responsePkt, errResp = omcilib.CreateEndSoftwareDownloadResponse(msg.OmciPkt, msg.OmciMsg, me.ProcessingError); errResp == nil {
@@ -1424,6 +1375,81 @@
 	return nil
 }
 
+// returns true if the request is successful, false otherwise
+func (o *Onu) handleEndSoftwareDownloadRequest(msg bbsim.OmciMessage) bool {
+	msgObj, err := omcilib.ParseEndSoftwareDownloadRequest(msg.OmciPkt)
+	if err != nil {
+		onuLogger.WithFields(log.Fields{
+			"OmciMsgType":  msg.OmciMsg.MessageType,
+			"TransCorrId":  msg.OmciMsg.TransactionID,
+			"Err":          err.Error(),
+			"IntfId":       o.PonPortID,
+			"SerialNumber": o.Sn(),
+		}).Error("error-while-processing-end-software-download-request")
+		return false
+	}
+
+	onuLogger.WithFields(log.Fields{
+		"OnuId":  o.ID,
+		"IntfId": o.PonPortID,
+		"OnuSn":  o.Sn(),
+		"msgObj": msgObj,
+	}).Trace("EndSoftwareDownloadRequest received message")
+
+	// if the image download is ongoing and we receive a message with
+	// ImageSize = 0 and Crc = 4294967295 (0xFFFFFFFF) respond with success
+	if o.ImageSoftwareReceivedSections > 0 &&
+		msgObj.ImageSize == 0 &&
+		msgObj.CRC32 == 4294967295 {
+		o.ImageSoftwareReceivedSections = 0
+		// NOTE potentially we may want to add a ONU state to reflect
+		// the software download abort
+		return true
+	}
+
+	// In the startSoftwareDownload we get the image size and the window size.
+	// We calculate how many DownloadSection we should receive and validate
+	// that we got the correct amount when we receive this message
+	// If the received sections are different from the expected sections
+	// respond with failure
+	if o.ImageSoftwareExpectedSections != o.ImageSoftwareReceivedSections {
+		onuLogger.WithFields(log.Fields{
+			"OnuId":            o.ID,
+			"IntfId":           o.PonPortID,
+			"OnuSn":            o.Sn(),
+			"ExpectedSections": o.ImageSoftwareExpectedSections,
+			"ReceivedSections": o.ImageSoftwareReceivedSections,
+		}).Errorf("onu-did-not-receive-all-image-sections")
+		return false
+	}
+
+	// check the received CRC vs the computed CRC
+	computedCRC := crc32a.Checksum(o.ImageSectionData[:int(msgObj.ImageSize)])
+	//Convert the crc to network byte order
+	var byteSlice = make([]byte, 4)
+	binary.LittleEndian.PutUint32(byteSlice, computedCRC)
+	computedCRC = binary.BigEndian.Uint32(byteSlice)
+	if msgObj.CRC32 != computedCRC {
+		onuLogger.WithFields(log.Fields{
+			"OnuId":         o.ID,
+			"IntfId":        o.PonPortID,
+			"OnuSn":         o.Sn(),
+			"ReceivedCRC":   msgObj.CRC32,
+			"CalculatedCRC": computedCRC,
+		}).Errorf("onu-image-crc-validation-failed")
+		return false
+	}
+
+	o.StandbyImageVersion = o.InDownloadImageVersion
+	onuLogger.WithFields(log.Fields{
+		"OnuId":          o.ID,
+		"IntfId":         o.PonPortID,
+		"OnuSn":          o.Sn(),
+		"StandbyVersion": o.StandbyImageVersion,
+	}).Debug("onu-image-version-updated")
+	return true
+}
+
 // BBR methods
 
 func sendOmciMsg(pktBytes []byte, intfId uint32, onuId uint32, sn *openolt.SerialNumber, msgType string, client openolt.OpenoltClient) {
diff --git a/internal/bbsim/devices/onu_omci_test.go b/internal/bbsim/devices/onu_omci_test.go
index 9f2444f..2c2b489 100644
--- a/internal/bbsim/devices/onu_omci_test.go
+++ b/internal/bbsim/devices/onu_omci_test.go
@@ -24,6 +24,7 @@
 	me "github.com/opencord/omci-lib-go/v2/generated"
 	"github.com/opencord/voltha-protos/v5/go/openolt"
 	"gotest.tools/assert"
+	"strconv"
 	"testing"
 )
 
@@ -128,13 +129,15 @@
 	return omciPkt
 }
 
-func makeOmciEndSoftwareDownloadRequest(t *testing.T) []byte {
+func makeOmciEndSoftwareDownloadRequest(t *testing.T, imageSize uint32, imageCrc uint32) []byte {
 	omciReq := &omci.EndSoftwareDownloadRequest{
 		MeBasePacket: omci.MeBasePacket{
 			EntityClass: me.SoftwareImageClassID,
 		},
 		NumberOfInstances: 1,
 		ImageInstances:    []uint16{0},
+		ImageSize:         imageSize,
+		CRC32:             imageCrc,
 	}
 	omciPkt, err := omcilib.Serialize(omci.EndSoftwareDownloadRequestType, omciReq, 66)
 	if err != nil {
@@ -250,9 +253,11 @@
 	assert.Equal(t, onu.MibDataSync, uint8(4))
 
 	// End software download
-	onu.ImageSoftwareReceivedSections = 1 // we fake that we have received the one download section we expect
+	onu.ImageSoftwareExpectedSections = 31
+	onu.ImageSoftwareReceivedSections = 31 // we fake that we have received all the download section we expect
+	onu.ImageSectionData = []byte{111, 114, 116, 116, 105, 116, 111, 114, 32, 113, 117, 105, 115, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 110, 101, 99, 32, 108, 105, 98, 101}
 	onu.InternalState.SetState(OnuStateImageDownloadInProgress)
-	err = onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciEndSoftwareDownloadRequest(t)), stream)
+	err = onu.handleOmciRequest(makeOmciMessage(t, onu, makeOmciEndSoftwareDownloadRequest(t, 31, 1523894119)), stream)
 	assert.NilError(t, err)
 	assert.Equal(t, onu.MibDataSync, uint8(5))
 
@@ -361,3 +366,37 @@
 		assert.Equal(t, stream.CallCount, int(onu.OmciResponseRate))
 	}
 }
+
+func Test_EndSoftwareDownloadRequestHandling(t *testing.T) {
+	onu := createTestOnu()
+
+	// test EndSoftwareDownloadRequest in case of abort
+	onu.ImageSoftwareReceivedSections = 2
+	imageCrc, _ := strconv.ParseInt("FFFFFFFF", 16, 64)
+	msg := makeOmciMessage(t, onu, makeOmciEndSoftwareDownloadRequest(t, 0, uint32(imageCrc)))
+	res := onu.handleEndSoftwareDownloadRequest(msg)
+	assert.Equal(t, res, true)
+	assert.Equal(t, onu.ImageSoftwareReceivedSections, 0)
+
+	// test EndSoftwareDownloadRequest if we received less sections than expected
+	onu.ImageSoftwareExpectedSections = 2
+	onu.ImageSoftwareReceivedSections = 1
+	msg = makeOmciMessage(t, onu, makeOmciEndSoftwareDownloadRequest(t, 2, 2))
+	res = onu.handleEndSoftwareDownloadRequest(msg)
+	assert.Equal(t, res, false)
+
+	// test CRC Mismatch
+	onu.ImageSectionData = []byte{111, 114, 116, 116, 105, 116, 111, 114, 32, 113, 117, 105, 115, 46, 32, 86, 105, 118, 97, 109, 117, 115, 32, 110, 101, 99, 32, 108, 105, 98, 101}
+	onu.ImageSoftwareExpectedSections = 2
+	onu.ImageSoftwareReceivedSections = 2
+	msg = makeOmciMessage(t, onu, makeOmciEndSoftwareDownloadRequest(t, 31, 12))
+	res = onu.handleEndSoftwareDownloadRequest(msg)
+	assert.Equal(t, res, false)
+
+	// if it's a valid case then set the StandbyImageVersion
+	onu.InDownloadImageVersion = "DownloadedImage"
+	msg = makeOmciMessage(t, onu, makeOmciEndSoftwareDownloadRequest(t, 31, 1523894119))
+	res = onu.handleEndSoftwareDownloadRequest(msg)
+	assert.Equal(t, res, true)
+	assert.Equal(t, onu.StandbyImageVersion, "DownloadedImage")
+}