VOL-4028: Support ANI-G test message at openonu-go adapter

Change-Id: Ibcdcf67e3f80fc30d673c1d8cc657bff654e9ee6
diff --git a/internal/pkg/onuadaptercore/omci_cc.go b/internal/pkg/onuadaptercore/omci_cc.go
index 7d28169..b37230b 100644
--- a/internal/pkg/onuadaptercore/omci_cc.go
+++ b/internal/pkg/onuadaptercore/omci_cc.go
@@ -329,7 +329,9 @@
 	}
 	logger.Debugw(ctx, "omci-message-decoded:", log.Fields{"omciMsgType": omciMsg.MessageType,
 		"transCorrId": strconv.FormatInt(int64(omciMsg.TransactionID), 16), "DeviceIdent": omciMsg.DeviceIdentifier})
-	if byte(omciMsg.MessageType)&me.AK == 0 {
+	// TestResult is asynchronous indication that carries the same TID as the TestResponse.
+	// We expect to find the TID in the oo.rxSchedulerMap
+	if byte(omciMsg.MessageType)&me.AK == 0 && omciMsg.MessageType != omci.TestResultType {
 		// Not a response
 		oo.printRxMessage(ctx, rxMsg)
 		logger.Debug(ctx, "RxMsg is no Omci Response Message")
@@ -340,7 +342,6 @@
 			log.Fields{"msgType": omciMsg.MessageType, "payload": hex.EncodeToString(omciMsg.Payload),
 				"device-id": oo.deviceID})
 		return fmt.Errorf("autonomous Omci Message with TranSCorrId != 0 not acccepted %s", oo.deviceID)
-
 	}
 	//logger.Debug(ctx,"RxMsg is a Omci Response Message: try to schedule it to the requester")
 	oo.mutexRxSchedMap.Lock()
@@ -356,8 +357,12 @@
 			oo.pOnuDeviceEntry.incrementMibDataSync(ctx)
 		}
 
-		// having posted the response the request is regarded as 'done'
-		delete(oo.rxSchedulerMap, omciMsg.TransactionID)
+		// If omciMsg.MessageType is omci.TestResponseType, we still expect the TestResult OMCI message,
+		// so do not clean up the TransactionID in that case.
+		if omciMsg.MessageType != omci.TestResponseType {
+			// having posted the response the request is regarded as 'done'
+			delete(oo.rxSchedulerMap, omciMsg.TransactionID)
+		}
 		oo.mutexRxSchedMap.Unlock()
 		return nil
 	}
@@ -476,6 +481,12 @@
 }
 */
 
+// ReleaseTid releases OMCI transaction identifier from rxSchedulerMap
+func (oo *omciCC) ReleaseTid(ctx context.Context, tid uint16) {
+	logger.Debugw(ctx, "releasing tid from rxSchedulerMap", log.Fields{"tid": tid})
+	delete(oo.rxSchedulerMap, tid)
+}
+
 //Queue the OMCI Frame for a transmit to the ONU via the proxy_channel
 func (oo *omciCC) send(ctx context.Context, txFrame []byte, timeout int, retry int, highPrio bool,
 	receiveCallbackPair callbackPair) error {
@@ -2892,10 +2903,64 @@
 	return nil
 }
 
+func (oo *omciCC) sendSelfTestReq(ctx context.Context, classID me.ClassID, instdID uint16, timeout int, highPrio bool, rxChan chan Message) error {
+	tid := oo.getNextTid(highPrio)
+	logger.Debugw(ctx, "send self test request:", log.Fields{"device-id": oo.deviceID,
+		"SequNo": strconv.FormatInt(int64(tid), 16),
+		"InstId": strconv.FormatInt(int64(instdID), 16)})
+	omciLayer := &omci.OMCI{
+		TransactionID: tid,
+		MessageType:   omci.TestRequestType,
+		// DeviceIdentifier: omci.BaselineIdent,    // Optional, defaults to Baseline
+		// Length:           0x28,                                      // Optional, defaults to 40 octets
+	}
+
+	var request *omci.OpticalLineSupervisionTestRequest
+	switch classID {
+	case aniGClassID:
+		request = &omci.OpticalLineSupervisionTestRequest{
+			MeBasePacket: omci.MeBasePacket{
+				EntityClass:    classID,
+				EntityInstance: instdID,
+			},
+			SelectTest:               uint8(7), // self test
+			GeneralPurposeBuffer:     uint16(0),
+			VendorSpecificParameters: uint16(0),
+		}
+	default:
+		logger.Errorw(ctx, "unsupported class id for self test request", log.Fields{"device-id": oo.deviceID, "classID": classID})
+		return fmt.Errorf("unsupported-class-id-for-self-test-request-%v", classID)
+	}
+	// Test serialization back to former string
+	var options gopacket.SerializeOptions
+	options.FixLengths = true
+
+	buffer := gopacket.NewSerializeBuffer()
+	err := gopacket.SerializeLayers(buffer, options, omciLayer, request)
+	if err != nil {
+		logger.Errorw(ctx, "Cannot serialize self test request", log.Fields{"Err": err,
+			"device-id": oo.deviceID})
+		return err
+	}
+	outgoingPacket := buffer.Bytes()
+
+	omciRxCallbackPair := callbackPair{cbKey: tid,
+		cbEntry: callbackPairEntry{rxChan, oo.receiveOmciResponse, true},
+	}
+	err = oo.send(ctx, outgoingPacket, timeout, 0, highPrio, omciRxCallbackPair)
+	if err != nil {
+		logger.Errorw(ctx, "Cannot send self test request", log.Fields{"Err": err,
+			"device-id": oo.deviceID})
+		return err
+	}
+	logger.Debug(ctx, "send self test request done")
+	return nil
+}
+
 func isSuccessfulResponseWithMibDataSync(omciMsg *omci.OMCI, packet *gp.Packet) bool {
 	for _, v := range responsesWithMibDataSync {
 		if v == omciMsg.MessageType {
-			nextLayer, _ := omci.MsgTypeToNextLayer(v)
+			nextLayer, _ := omci.MsgTypeToNextLayer(v, false)
 			msgLayer := (*packet).Layer(nextLayer)
 			switch nextLayer {
 			case omci.LayerTypeCreateResponse: