Files
cloud-services/pkg/dbc/dbc_parsestate_test.go

449 lines
13 KiB
Go

package dbc_test
import (
"fmt"
"reflect"
"regexp"
"testing"
"github.com/fiskerinc/cloud-services/pkg/dbc"
fm29_frs90 "github.com/fiskerinc/cloud-services/pkg/dbc/fm29_frs90"
fm29_frsd0 "github.com/fiskerinc/cloud-services/pkg/dbc/fm29_frsd0"
fm29_frsd21 "github.com/fiskerinc/cloud-services/pkg/dbc/fm29_frsd21"
fm29_frsd390 "github.com/fiskerinc/cloud-services/pkg/dbc/fm29_frsd390"
"github.com/fiskerinc/cloud-services/pkg/dbc/state"
"github.com/fiskerinc/cloud-services/pkg/grpc/kafka_grpc"
"github.com/fiskerinc/cloud-services/pkg/testhelper"
"github.com/golang/protobuf/proto"
"github.com/jinzhu/copier"
)
const vin = "11111111111111111"
var epoch = int64(1642455023642165)
var payloadFRS90 = kafka_grpc.GRPC_BatchPayload{
Version: fm29_frs90.Hash,
Data: &kafka_grpc.GRPC_CANData{
Frames: []*kafka_grpc.GRPC_CANFrame{
{
Epoch: epoch,
ID: 608,
Value: []byte("AAEAAAAAAAA="),
},
{
Epoch: epoch,
ID: 757,
Value: []byte("CgAAAAAUAAA="),
},
{
Epoch: epoch,
ID: 801,
Value: []byte("AAAUKDxQ/wA="),
},
{
Epoch: epoch,
ID: 816,
Value: []byte("AAAAfQAAAAA="),
},
{
Epoch: epoch,
ID: 821,
Value: []byte("AAAAAAgAAP8="),
},
{
Epoch: epoch,
ID: 835,
Value: []byte("AAAFbAAAMgA="),
},
{
Epoch: epoch,
ID: 873,
Value: []byte("AAB4jKAAAAE="),
},
{
Epoch: epoch,
ID: 882,
Value: []byte("AAAwADCKADA="),
},
{
Epoch: epoch,
ID: 883,
Value: []byte("AAAAAACcAAA="),
},
{
Epoch: epoch,
ID: 902,
Value: []byte("AQAAAAAAAAA="),
},
{
Epoch: epoch,
ID: 1284,
Value: []byte("AAAAAAAwNAA="),
},
{
Epoch: epoch,
ID: 1298,
Value: []byte("EAAAAAAAAAA="),
},
{
Epoch: epoch,
ID: 1304,
Value: []byte("AgAAAAAAAAA="),
},
{
Epoch: epoch,
ID: 1329,
Value: []byte("AAADlAQAAAA="),
},
{
Epoch: epoch,
ID: 1408,
Value: []byte("AAAAABOIAAA="),
},
{
Epoch: epoch,
ID: 1410,
Value: []byte("nAB4AAAAAAA="),
},
{
Epoch: epoch,
ID: 1317,
Value: []byte("AABAg6NJ64c="),
},
},
},
}
var payloadFRSD0 = kafka_grpc.GRPC_BatchPayload{
Version: fm29_frsd0.Hash,
Data: &kafka_grpc.GRPC_CANData{
Frames: []*kafka_grpc.GRPC_CANFrame{
{
Epoch: epoch,
ID: 608,
Value: []byte("AAAA+gH0Aec="),
},
{
Epoch: epoch,
ID: 757,
Value: []byte("CgAAAAAUAAA="),
},
{
Epoch: epoch,
ID: 801,
Value: []byte("AAAUKDxQ/wA="),
},
{
Epoch: epoch,
ID: 816,
Value: []byte("AAAAfQAAAAA="),
},
{
Epoch: epoch,
ID: 821,
Value: []byte("AAAAAAgAAP8="),
},
{
Epoch: epoch,
ID: 835,
Value: []byte("AAAFbAAAZAA="),
},
{
Epoch: epoch,
ID: 873,
Value: []byte("AAB4jKAAAAE="),
},
{
Epoch: epoch,
ID: 882,
Value: []byte("AAAwADCKADA="),
},
{
Epoch: epoch,
ID: 883,
Value: []byte("AAAAAACcAAA="),
},
{
Epoch: epoch,
ID: 902,
Value: []byte("AQAAAAAAAAA="),
},
{
Epoch: epoch,
ID: 1284,
Value: []byte("AAAAAAAwNAA="),
},
{
Epoch: epoch,
ID: 1298,
Value: []byte("EAAAAAAAAAA="),
},
{
Epoch: epoch,
ID: 1304,
Value: []byte("AgAAAAAAAAA="),
},
{
Epoch: epoch,
ID: 1329,
Value: []byte("AAADlAQAAAA="),
},
{
Epoch: epoch,
ID: 1408,
Value: []byte("AMgBLBOIAZA="),
},
{
Epoch: epoch,
ID: 1410,
Value: []byte("nAB4AAAAAAA="),
},
{
Epoch: epoch,
ID: 1317,
Value: []byte("ZAVAgAAAAAA="),
},
{
Epoch: epoch,
ID: 1318,
Value: []byte("A414OAeAC0A="),
},
},
},
}
var expectedValuesFRS90 = map[string]interface{}{
state.BCM_AP_FL_LeFrntWinPosnInfo: interface{}(10),
state.BCM_AP_FL_LeReWinPosnInfo: interface{}(30),
state.BCM_AP_FL_RiFrntWinPosnInfo: interface{}(20),
state.BCM_AP_FL_RiReWinPosnInfo: interface{}(40),
state.BCM_AP_RW_WinPosnInfo: interface{}(80),
state.BCM_AP_TL_LeReWinPosnInfo: interface{}(60),
state.BCM_AP_TL_RiReWinPosnInfo: interface{}(70),
state.BCM_CenLockSwtSts: interface{}(3),
state.BCM_DrFrntDoorSts: interface{}(false),
state.BCM_FrntDrDoorLockSts: interface{}(true),
state.BCM_FrntHoodLidSts: interface{}(true),
state.BCM_HeatedSteerWhlSt: interface{}(true),
state.BCM_LeReDoorSts: interface{}(true),
state.BCM_PasFrntDoorSts: interface{}(false),
state.BCM_ReDefrstHeatgCmd: interface{}(true),
state.BCM_RiReDoorSts: interface{}(true),
state.BCM_SunroofPosnInfo: interface{}(50),
state.BMS_Bat_SOH: interface{}(20),
state.BMS_Bat_SoC_usable: interface{}(10),
state.BMS_BattAvrgT: interface{}(90),
state.BMS_PwrBattRmngCpSOC: interface{}(50),
state.DSMC_DrvrSeatHeatgSts: interface{}(2),
state.ECC_InsdT: interface{}(30),
state.ECC_OutdT: interface{}(30),
state.ECC_RemTSetSts: interface{}(120),
state.ICC_TotMilg_ODO: interface{}(float64(2345)),
state.PSM_PassSeatHeatgSts: interface{}(4),
state.TBOX_GPSHei: interface{}(float64(16)),
state.TBOX_GPSLati: interface{}(float64(35.831)),
state.TBOX_GPSLongi: interface{}(float64(-120.398)),
state.VCU_DCChrgRmngTi: interface{}(5000),
state.VCU_DrvgMilg: interface{}(1234),
state.VCU_VehChrgDchgMod: interface{}("DC_charging"),
state.UPDATED_AT: interface{}([]byte{34, 50, 48, 50, 50, 45, 48, 49, 45, 49, 55, 84, 50, 49, 58, 51, 48, 58, 50, 51, 46, 54, 52, 50, 49, 54, 53, 90, 34}),
}
var expectedValuesFRSD0 = map[string]interface{}{
state.BCM_AP_FL_LeFrntWinPosnInfo: interface{}(10),
state.BCM_AP_FL_LeReWinPosnInfo: interface{}(30),
state.BCM_AP_FL_RiFrntWinPosnInfo: interface{}(20),
state.BCM_AP_FL_RiReWinPosnInfo: interface{}(40),
state.BCM_AP_RW_WinPosnInfo: interface{}(80),
state.BCM_AP_TL_LeReWinPosnInfo: interface{}(60),
state.BCM_AP_TL_RiReWinPosnInfo: interface{}(70),
state.BCM_CenLockSwtSts: interface{}(3),
state.BCM_DrFrntDoorSts: interface{}(false),
state.BCM_FrntDrDoorLockSts: interface{}(true),
state.BCM_FrntHoodLidSts: interface{}(true),
state.BCM_HeatedSteerWhlSt: interface{}(true),
state.BCM_LeReDoorSts: interface{}(true),
state.BCM_PasFrntDoorSts: interface{}(false),
state.BCM_ReDefrstHeatgCmd: interface{}(true),
state.BCM_RiReDoorSts: interface{}(true),
state.BCM_SunroofPosnInfo: interface{}(50),
state.BMS_Bat_SOH: interface{}(20),
state.BMS_Bat_SoC_usable: interface{}(10),
state.BMS_BattAvrgT: interface{}(90),
state.BMS_PwrBattRmngCpSOC: interface{}(50),
state.DSMC_DrvrSeatHeatgSts: interface{}(2),
state.ECC_InsdT: interface{}(30),
state.ECC_OutdT: interface{}(30),
state.ECC_RemTSetSts: interface{}(120),
state.ICC_TotMilg_ODO: interface{}(float64(2345)),
state.PSM_PassSeatHeatgSts: interface{}(4),
state.TBOX_GPSHei: interface{}(float64(16)),
state.TBOX_GPSLati: interface{}(float64(35.832)),
state.TBOX_GPSLongi: interface{}(float64(-120.397)),
state.VCU_DCChrgRmngTi: interface{}(5000),
state.VCU_DrvgMilg: interface{}(1234),
state.VCU_VehChrgDchgMod: interface{}("DC_charging"),
state.UPDATED_AT: interface{}([]byte{34, 50, 48, 50, 50, 45, 48, 49, 45, 49, 55, 84, 50, 49, 58, 51, 48, 58, 50, 51, 46, 54, 52, 50, 49, 54, 53, 90, 34}),
}
var expectedValuesFRSD21 = map[string]interface{}{
state.BCM_AP_FL_LeFrntWinPosnInfo: interface{}(10),
state.BCM_AP_FL_LeReWinPosnInfo: interface{}(30),
state.BCM_AP_FL_RiFrntWinPosnInfo: interface{}(20),
state.BCM_AP_FL_RiReWinPosnInfo: interface{}(40),
state.BCM_AP_RW_WinPosnInfo: interface{}(80),
state.BCM_AP_TL_LeReWinPosnInfo: interface{}(60),
state.BCM_AP_TL_RiReWinPosnInfo: interface{}(70),
state.BCM_CenLockSwtSts: interface{}(3),
state.BCM_DrFrntDoorSts: interface{}(false),
state.BCM_FrntDrDoorLockSts: interface{}(true),
state.BCM_FrntHoodLidSts: interface{}(true),
state.BCM_HeatedSteerWhlSt: interface{}(true),
state.BCM_LeReDoorSts: interface{}(true),
state.BCM_PasFrntDoorSts: interface{}(false),
state.BCM_ReDefrstHeatgCmd: interface{}(true),
state.BCM_RiReDoorSts: interface{}(true),
state.BCM_SunroofPosnInfo: interface{}(50),
state.BMS_Bat_SOH: interface{}(20),
state.BMS_Bat_SoC_usable: interface{}(10),
state.BMS_BattAvrgT: interface{}(90),
state.BMS_PwrBattRmngCpSOC: interface{}(50),
state.DSMC_DrvrSeatHeatgSts: interface{}(2),
state.ECC_InsdT: interface{}(30),
state.ECC_OutdT: interface{}(30),
state.ECC_RemTSetSts: interface{}(120),
state.ICC_TotMilg_ODO: interface{}(2345),
state.PSM_PassSeatHeatgSts: interface{}(4),
state.TBOX_GPSHei: interface{}(float64(2802.4)),
state.TBOX_GPSLati: interface{}(float64(-54.168)),
state.TBOX_GPSLongi: interface{}(float64(-300.397)),
state.VCU_DCChrgRmngTi: interface{}(5000),
state.VCU_DrvgMilg: interface{}(1234),
state.VCU_VehChrgDchgMod: interface{}("DC_charging"),
state.UPDATED_AT: interface{}([]byte{34, 50, 48, 50, 50, 45, 48, 49, 45, 49, 55, 84, 50, 49, 58, 51, 48, 58, 50, 51, 46, 54, 52, 50, 49, 54, 53, 90, 34}),
}
func getExpectedValuesFRS390() map[string]interface{} {
expectedValuesFRS390 := map[string]interface{}{}
copier.Copy(&expectedValuesFRS390, &expectedValuesFRSD21)
// DBC 390 does not have a definition for VCU_DCChrgRmngTi
delete(expectedValuesFRS390, state.VCU_DCChrgRmngTi)
expectedValuesFRS390[state.TBOX_GPSLati] = interface{}(float64(35.832))
expectedValuesFRS390[state.TBOX_GPSLongi] = interface{}(float64(-120.397))
return expectedValuesFRS390
}
func copyPayload(source *kafka_grpc.GRPC_BatchPayload, hash string) *kafka_grpc.GRPC_BatchPayload {
payload := kafka_grpc.GRPC_BatchPayload{}
proto.Merge(&payload, source)
payload.Version = hash
return &payload
}
func ignoreSignalUpdateTimestamp(input map[string]interface{}) map[string]interface{} {
m := make(map[string]interface{})
pattern, _ := regexp.Compile(`:updated$`)
for key, val := range input {
matched := pattern.MatchString(key)
if matched {
continue
}
m[key] = val
}
return m
}
func TestFM29_FRS90_ParseState(t *testing.T) {
payloadFRSD21 := copyPayload(&payloadFRSD0, fm29_frsd21.Hash)
payloadFRSD390 := copyPayload(&payloadFRSD0, fm29_frsd390.Hash)
expectedValuesFRS390 := getExpectedValuesFRS390()
collection := dbc.NewDBCCollection()
type testCase struct {
name string
payload *kafka_grpc.GRPC_BatchPayload
expected map[string]interface{}
expectedCommandCount int
}
tests := []testCase{
{
name: "FRS90",
payload: &payloadFRS90,
expected: expectedValuesFRS90,
expectedCommandCount: 34,
},
{
name: "FRSD0",
payload: &payloadFRSD0,
expected: expectedValuesFRSD0,
expectedCommandCount: 34,
},
{
name: "FRSD21",
payload: payloadFRSD21,
expected: expectedValuesFRSD21,
expectedCommandCount: 34,
},
{
name: "FRSD390",
payload: payloadFRSD390,
expected: expectedValuesFRS390,
expectedCommandCount: 33,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
keyvalues, err := collection.ParseState(vin, test.payload, nil)
if err != nil {
t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("ParseState %s", test.name), nil, err)
}
expectedCommandCount := 2*test.expectedCommandCount - 1
if len(keyvalues) != expectedCommandCount {
t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("key value len %s", test.name), expectedCommandCount, len(keyvalues))
}
mKeyVal := ignoreSignalUpdateTimestamp(keyvalues)
if !reflect.DeepEqual(mKeyVal, test.expected) {
t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("key value compare %s", test.name), test.expected, keyvalues)
}
})
}
}
func TestBadMsgID(t *testing.T) {
collection := dbc.NewDBCCollection()
payload := kafka_grpc.GRPC_BatchPayload{
Version: fm29_frsd0.Hash,
Data: &kafka_grpc.GRPC_CANData{
Frames: []*kafka_grpc.GRPC_CANFrame{
{
Epoch: epoch,
ID: 576,
Value: []byte("AAAAA414OAeAC0A="),
},
},
},
}
// This test should not set anything in Redis cache
keyvalues, _ := collection.ParseState(vin, &payload, nil)
if len(keyvalues) != 0 {
t.Errorf(testhelper.TestErrorTemplate, "bad message id", 0, len(keyvalues))
}
}
func BenchmarkNewFM29_FRS90_DBC(b *testing.B) {
for n := 0; n < b.N; n++ {
dbc.NewFM29_FRS90_DBC()
}
}
func BenchmarkParseState(b *testing.B) {
collection := dbc.NewDBCCollection()
for n := 0; n < b.N; n++ {
collection.ParseState(vin, &payloadFRS90, nil)
}
}