Add depot, attendant, jetfire, optimus, ota services with kustomize overlays
This commit is contained in:
26
services/attendant/handlers/car_update_progress.go
Normal file
26
services/attendant/handlers/car_update_progress.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/controllers"
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func CarUpdateProgressStatus(db *services.DB, ka *services.KeepAwake, device common.Device, id string, data []byte) error {
|
||||
logger.Debug().Msgf("CarUpdateProgressStatus %v %s", device, id)
|
||||
|
||||
clientPool := services.RedisClientPool()
|
||||
|
||||
handler := controllers.NewCarUpdateProgress(clientPool, ka, db, device)
|
||||
if handler == nil {
|
||||
return errors.Errorf("NewCarUpdateProgress cannot handle device %v", device)
|
||||
}
|
||||
defer handler.Dispose()
|
||||
|
||||
err := handler.Process(id, data)
|
||||
return err
|
||||
}
|
||||
389
services/attendant/handlers/car_update_progress_func_test.go
Normal file
389
services/attendant/handlers/car_update_progress_func_test.go
Normal file
@@ -0,0 +1,389 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/handlers"
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis/tester"
|
||||
"github.com/fiskerinc/cloud-services/pkg/testhelper"
|
||||
)
|
||||
|
||||
func TestCarUpdateProgressFunctional(t *testing.T) {
|
||||
t.Skip()
|
||||
testVIN := "WBSEH93466B798124"
|
||||
conn := tester.NewRedisMock()
|
||||
db := services.GetDB()
|
||||
manifest, carUpdateID, err := setupCarUpdateProgressFunc(db, testVIN)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer func() {
|
||||
if carUpdateID > 0 {
|
||||
db.GetCarUpdates().Delete(&common.CarUpdate{ID: carUpdateID})
|
||||
conn.Delete(redis.CarUpdateStatusTBOXHashKey(carUpdateID), redis.CarUpdateStatusHMIHashKey(carUpdateID))
|
||||
}
|
||||
if manifest != nil && manifest.ID > 0 {
|
||||
db.GetUpdateManifests().Delete(manifest)
|
||||
}
|
||||
}()
|
||||
|
||||
ka := services.NewKeepAwakeService()
|
||||
ka.SetService(&services.MockKeepAwakeImplementation{})
|
||||
|
||||
type testCase struct {
|
||||
Name string
|
||||
Device common.Device
|
||||
Payload string
|
||||
ExpectedMsg string
|
||||
ExpectInstalled int
|
||||
ExpectInstallTotal int
|
||||
ExpectDBStatus string
|
||||
ExpectDownloadCurrent uint64
|
||||
ExpectDownloadTotal uint64
|
||||
ExpectErrorCode int
|
||||
}
|
||||
|
||||
tests := []testCase{
|
||||
{
|
||||
Name: "manifest_received",
|
||||
Device: common.TRex,
|
||||
Payload: fmt.Sprintf(`{
|
||||
"car_update_id": %d,
|
||||
"msg": "manifest_received"
|
||||
}`, carUpdateID),
|
||||
ExpectedMsg: "manifest_received",
|
||||
ExpectDBStatus: "manifest_received",
|
||||
},
|
||||
{
|
||||
Name: "install_approval_await",
|
||||
Device: common.TRex,
|
||||
Payload: fmt.Sprintf(`{
|
||||
"car_update_id": %d,
|
||||
"msg": "install_approval_await"
|
||||
}`, carUpdateID),
|
||||
ExpectedMsg: "install_approval_await",
|
||||
ExpectDBStatus: "install_approval_await",
|
||||
},
|
||||
{
|
||||
Name: "other error",
|
||||
Device: common.TRex,
|
||||
Payload: fmt.Sprintf(`{
|
||||
"car_update_id": %d,
|
||||
"ecu": "TEST",
|
||||
"installed": 3,
|
||||
"total_files": 10,
|
||||
"msg": "other error",
|
||||
"err": -100
|
||||
}`, carUpdateID),
|
||||
ExpectedMsg: "other error",
|
||||
ExpectDBStatus: "other error",
|
||||
ExpectInstalled: 3,
|
||||
ExpectInstallTotal: 10,
|
||||
ExpectErrorCode: -100,
|
||||
},
|
||||
{
|
||||
Name: "download_start",
|
||||
Device: common.TRex,
|
||||
Payload: fmt.Sprintf(`{
|
||||
"car_update_id": %d,
|
||||
"ecu": "TEST",
|
||||
"file_current": 0,
|
||||
"file_total": 100,
|
||||
"package_current": 0,
|
||||
"package_total": 100,
|
||||
"msg": "download_start",
|
||||
"err": 0
|
||||
}`, carUpdateID),
|
||||
ExpectedMsg: "downloading",
|
||||
ExpectDBStatus: "package_download_start",
|
||||
ExpectDownloadCurrent: 0,
|
||||
ExpectDownloadTotal: 100,
|
||||
},
|
||||
{
|
||||
Name: "downloading",
|
||||
Device: common.TRex,
|
||||
Payload: fmt.Sprintf(`{
|
||||
"car_update_id": %d,
|
||||
"ecu": "TEST",
|
||||
"file_current": 0,
|
||||
"file_total": 100,
|
||||
"package_current": 30,
|
||||
"package_total": 100,
|
||||
"msg": "downloading",
|
||||
"err": 0
|
||||
}`, carUpdateID),
|
||||
ExpectedMsg: "downloading",
|
||||
ExpectDBStatus: "package_download_start",
|
||||
ExpectDownloadCurrent: 30,
|
||||
ExpectDownloadTotal: 100,
|
||||
},
|
||||
{
|
||||
Name: "download_complete",
|
||||
Device: common.TRex,
|
||||
Payload: fmt.Sprintf(`{
|
||||
"car_update_id": %d,
|
||||
"ecu": "TEST",
|
||||
"file_current": 100,
|
||||
"file_total": 100,
|
||||
"package_current": 900,
|
||||
"package_total": 1000,
|
||||
"msg": "download_complete",
|
||||
"err": 0
|
||||
}`, carUpdateID),
|
||||
ExpectedMsg: "downloading",
|
||||
ExpectDBStatus: "package_download_start",
|
||||
ExpectDownloadCurrent: 900,
|
||||
ExpectDownloadTotal: 1000,
|
||||
},
|
||||
{
|
||||
Name: "package_download_complete",
|
||||
Device: common.TRex,
|
||||
Payload: fmt.Sprintf(`{
|
||||
"car_update_id": %d,
|
||||
"ecu": "TEST",
|
||||
"file_current": 100,
|
||||
"file_total": 100,
|
||||
"package_current": 1000,
|
||||
"package_total": 1000,
|
||||
"msg": "download_complete",
|
||||
"err": 0
|
||||
}`, carUpdateID),
|
||||
ExpectedMsg: "package_download_complete",
|
||||
ExpectDBStatus: "package_download_complete",
|
||||
ExpectDownloadCurrent: 1000,
|
||||
ExpectDownloadTotal: 1000,
|
||||
},
|
||||
{
|
||||
Name: "download_error",
|
||||
Device: common.TRex,
|
||||
Payload: fmt.Sprintf(`{
|
||||
"car_update_id": %d,
|
||||
"ecu": "TEST",
|
||||
"file_current": 0,
|
||||
"file_total": 100,
|
||||
"package_current": 0,
|
||||
"package_total": 1000,
|
||||
"msg": "download_error",
|
||||
"err": 0
|
||||
}`, carUpdateID),
|
||||
ExpectedMsg: "download_error",
|
||||
ExpectDBStatus: "download_error",
|
||||
ExpectDownloadCurrent: 0,
|
||||
ExpectDownloadTotal: 1000,
|
||||
},
|
||||
{
|
||||
Name: "install_start",
|
||||
Device: common.TRex,
|
||||
Payload: fmt.Sprintf(`{
|
||||
"car_update_id": %d,
|
||||
"ecu": "TEST",
|
||||
"installed": 0,
|
||||
"total_files": 10,
|
||||
"msg": "install_start",
|
||||
"err": 0
|
||||
}`, carUpdateID),
|
||||
ExpectedMsg: "installing",
|
||||
ExpectDBStatus: "package_install_start",
|
||||
ExpectInstalled: 0,
|
||||
ExpectInstallTotal: 10,
|
||||
},
|
||||
{
|
||||
Name: "installing",
|
||||
Device: common.TRex,
|
||||
Payload: fmt.Sprintf(`{
|
||||
"car_update_id": %d,
|
||||
"ecu": "TEST",
|
||||
"installed": 2,
|
||||
"total_files": 10,
|
||||
"msg": "installing",
|
||||
"err": 0
|
||||
}`, carUpdateID),
|
||||
ExpectedMsg: "installing",
|
||||
ExpectDBStatus: "package_install_start",
|
||||
ExpectInstalled: 2,
|
||||
ExpectInstallTotal: 10,
|
||||
},
|
||||
{
|
||||
Name: "install_complete",
|
||||
Device: common.TRex,
|
||||
Payload: fmt.Sprintf(`{
|
||||
"car_update_id": %d,
|
||||
"ecu": "TEST",
|
||||
"installed": 9,
|
||||
"total_files": 10,
|
||||
"msg": "install_complete",
|
||||
"err": 0
|
||||
}`, carUpdateID),
|
||||
ExpectedMsg: "installing",
|
||||
ExpectDBStatus: "package_install_start",
|
||||
ExpectInstalled: 9,
|
||||
ExpectInstallTotal: 10,
|
||||
},
|
||||
{
|
||||
Name: "package_install_complete",
|
||||
Device: common.TRex,
|
||||
Payload: fmt.Sprintf(`{
|
||||
"car_update_id": %d,
|
||||
"ecu": "TEST",
|
||||
"installed": 10,
|
||||
"total_files": 10,
|
||||
"msg": "install_complete",
|
||||
"err": 0
|
||||
}`, carUpdateID),
|
||||
ExpectedMsg: "package_install_complete",
|
||||
ExpectDBStatus: "package_install_complete",
|
||||
ExpectInstalled: 10,
|
||||
ExpectInstallTotal: 10,
|
||||
},
|
||||
{
|
||||
Name: "install_error",
|
||||
Device: common.TRex,
|
||||
Payload: fmt.Sprintf(`{
|
||||
"car_update_id": %d,
|
||||
"ecu": "TEST",
|
||||
"installed": 3,
|
||||
"total_files": 10,
|
||||
"msg": "install_error",
|
||||
"err": 0
|
||||
}`, carUpdateID),
|
||||
ExpectedMsg: "install_error",
|
||||
ExpectDBStatus: "install_error",
|
||||
ExpectInstalled: 3,
|
||||
ExpectInstallTotal: 10,
|
||||
},
|
||||
{
|
||||
Name: "package_download_complete",
|
||||
Device: common.HMI,
|
||||
Payload: fmt.Sprintf(`{
|
||||
"car_update_id":%d,
|
||||
"ecu":"ICC",
|
||||
"file_current":null,
|
||||
"file_total":null,
|
||||
"package_current":920639485,
|
||||
"package_total":920639485,
|
||||
"installed":null,
|
||||
"total_files":null,
|
||||
"msg":"package_download_complete",
|
||||
"err":null
|
||||
}`, carUpdateID),
|
||||
ExpectedMsg: "package_download_complete",
|
||||
ExpectDBStatus: "package_download_complete",
|
||||
ExpectInstalled: 3,
|
||||
ExpectInstallTotal: 10,
|
||||
ExpectDownloadCurrent: 920639485,
|
||||
ExpectDownloadTotal: 920639485,
|
||||
},
|
||||
}
|
||||
|
||||
keys := make([]string, 1)
|
||||
statuses := make([]interface{}, 1)
|
||||
|
||||
for _, test := range tests {
|
||||
err := handlers.CarUpdateProgressStatus(db, ka, test.Device, testVIN, []byte(test.Payload))
|
||||
if err != nil {
|
||||
t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("[%v] %s output error", test.Device, test.Name), nil, err)
|
||||
}
|
||||
|
||||
status := common.CarUpdateProgress{}
|
||||
keys[0] = redis.CarUpdateStatusHashKey(carUpdateID)
|
||||
statuses[0] = &status
|
||||
|
||||
err = conn.GetObjectsMulti(keys, statuses)
|
||||
if err != nil {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "GetObjectsMulti", nil, err)
|
||||
return
|
||||
}
|
||||
if status.Status != test.ExpectedMsg {
|
||||
t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("[%v] %s Status", test.Device, test.Name), test.ExpectedMsg, status.Status)
|
||||
}
|
||||
if status.InstalledFiles != test.ExpectInstalled {
|
||||
t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("[%v] %s InstalledFiles", test.Device, test.Name), test.ExpectInstalled, status.InstalledFiles)
|
||||
}
|
||||
if status.TotalFiles != test.ExpectInstallTotal {
|
||||
t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("[%v] %s TotalFiles", test.Device, test.Name), test.ExpectInstallTotal, status.TotalFiles)
|
||||
}
|
||||
if status.PackageCurrent != test.ExpectDownloadCurrent {
|
||||
t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("[%v] %s PackageCurrent", test.Device, test.Name), test.ExpectDownloadCurrent, status.PackageCurrent)
|
||||
}
|
||||
if status.PackageTotal != test.ExpectDownloadTotal {
|
||||
t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("[%v] %s PackageTotal", test.Device, test.Name), test.ExpectDownloadTotal, status.PackageTotal)
|
||||
}
|
||||
if status.ErrorCode != test.ExpectErrorCode {
|
||||
t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("[%v] %s ErrorCode", test.Device, test.Name), test.ExpectErrorCode, status.ErrorCode)
|
||||
}
|
||||
|
||||
cu, err := db.GetCarUpdates().SelectByID(carUpdateID)
|
||||
if err != nil {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "Get from DB", nil, err)
|
||||
return
|
||||
}
|
||||
if cu.Status != test.ExpectDBStatus {
|
||||
t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("[%v] %s DB Status", test.Device, test.Name), test.ExpectDBStatus, cu.Status)
|
||||
}
|
||||
if cu.ErrorCode != test.ExpectErrorCode {
|
||||
t.Errorf(testhelper.TestErrorTemplate, fmt.Sprintf("[%v] %s DB ErrorCode", test.Device, test.Name), test.ExpectErrorCode, cu.ErrorCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setupCarUpdateProgressFunc(db *services.DB, vin string) (*common.UpdateManifest, int64, error) {
|
||||
_, err := db.GetCars().SelectOrInsert(&common.Car{
|
||||
VIN: vin,
|
||||
Model: "Ocean",
|
||||
Year: 2022,
|
||||
Trim: "Sport",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
manifest := common.UpdateManifest{
|
||||
Name: "TestCarUpdateProgressFunctional",
|
||||
Version: "1000",
|
||||
Description: "For TestCarUpdateProgressFunctional",
|
||||
ReleaseNotes: "http://releasenotes.com",
|
||||
Country: "US",
|
||||
PowerTrain: "MD23",
|
||||
Restraint: "None",
|
||||
Model: "Ocean",
|
||||
Trim: "Sport",
|
||||
Year: 2022,
|
||||
BodyType: "truck",
|
||||
}
|
||||
_, err = db.GetUpdateManifests().Insert(&manifest)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
_, err = db.GetUpdateManifests().ECUInsert(&common.UpdateManifestECU{
|
||||
UpdateManifestID: manifest.ID,
|
||||
ECU: "ICC",
|
||||
Version: "ICCVERSION",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
_, err = db.GetUpdateManifests().ECUInsert(&common.UpdateManifestECU{
|
||||
UpdateManifestID: manifest.ID,
|
||||
ECU: "ADAS",
|
||||
Version: "ADASVERSION",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
carupdate := common.CarUpdate{
|
||||
VIN: vin,
|
||||
UpdateManifestID: manifest.ID,
|
||||
}
|
||||
_, err = db.GetCarUpdates().Insert(&carupdate)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return &manifest, carupdate.ID, nil
|
||||
}
|
||||
776
services/attendant/handlers/car_update_progress_test.go
Normal file
776
services/attendant/handlers/car_update_progress_test.go
Normal file
@@ -0,0 +1,776 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/controllers"
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/common/manifestfingerprintparams"
|
||||
"github.com/fiskerinc/cloud-services/pkg/db/queries/mocks"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis/tester"
|
||||
th "github.com/fiskerinc/cloud-services/pkg/testhelper"
|
||||
"github.com/fiskerinc/cloud-services/pkg/utils/elptr"
|
||||
vconfig "github.com/fiskerinc/cloud-services/pkg/vehicleconfig"
|
||||
)
|
||||
|
||||
var (
|
||||
schemaToTRex = "file://" + th.GetSchemaDirPath() + "/trex/RXMessage.json"
|
||||
schemaToHMI = "file://" + th.GetSchemaDirPath() + "/hmi/RXMessage.json"
|
||||
)
|
||||
|
||||
func TestCarUpdateProgress(t *testing.T) {
|
||||
testGetSetResult := `["valid-cognito-id-1","valid-cognito-id-2"]`
|
||||
testVIN := "JH4KA7680RC01"
|
||||
mobile1Key := "3:valid-cognito-id-1"
|
||||
mobile2Key := "3:valid-cognito-id-2"
|
||||
hmiKey := "2:JH4KA7680RC01"
|
||||
trexKey := common.TRex.Key(testVIN)
|
||||
carupdateKey := "carupdate:297"
|
||||
var bhex common.BinaryHex
|
||||
expectedExpire := 3600
|
||||
bhex = []byte("test")
|
||||
|
||||
fingerprintTime, _ := time.Parse("02/01/06", "19/01/24")
|
||||
fpp := manifestfingerprintparams.MockFingerprintParamer{
|
||||
ManifestSerialValue: "00000000000000000",
|
||||
Time: fingerprintTime,
|
||||
}
|
||||
manifestfingerprintparams.SetFPParams(&fpp)
|
||||
|
||||
manifest := common.UpdateManifest{
|
||||
ID: 1,
|
||||
Name: "test",
|
||||
Version: "MANIFEST_VERSION",
|
||||
SUMS: "2023.10.01.00.E",
|
||||
Description: "description",
|
||||
ReleaseNotes: "http://releasenotes.com",
|
||||
Country: "US",
|
||||
PowerTrain: "MD23",
|
||||
Restraint: "None",
|
||||
Model: "Ocean",
|
||||
Trim: "Sport",
|
||||
Year: 2022,
|
||||
BodyType: "truck",
|
||||
RollbackEnabled: true,
|
||||
Type: "standard",
|
||||
ECUs: []*common.UpdateManifestECU{
|
||||
{
|
||||
ECU: "ICC",
|
||||
Version: "version",
|
||||
HWVersions: []string{"hardware_version"},
|
||||
Mode: "D",
|
||||
SelfDownload: true,
|
||||
Files: []*common.UpdateManifestFile{
|
||||
{
|
||||
FileID: "fileid",
|
||||
URL: "http://download.com",
|
||||
Filename: "filename.bin",
|
||||
FileSize: 10000,
|
||||
FileType: common.Software,
|
||||
WriteRegionID: 2222,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
ID: 2000,
|
||||
Offset: 10000,
|
||||
Length: 20,
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
{
|
||||
ECU: "ADAS",
|
||||
Version: "version",
|
||||
HWVersions: []string{"hardware_version"},
|
||||
Mode: "A",
|
||||
InstallPriority: 10,
|
||||
Files: []*common.UpdateManifestFile{
|
||||
{
|
||||
FileID: "fileid",
|
||||
URL: "http://download.com",
|
||||
Filename: "adas.bin",
|
||||
FileSize: 9999,
|
||||
FileType: common.Software,
|
||||
WriteRegionID: 9999,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
ID: 8888,
|
||||
Offset: 8888,
|
||||
Length: 8888,
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
},
|
||||
ECCKeys: &common.ECCKeys{
|
||||
ECU: "ADAS",
|
||||
PrivKey1: &bhex,
|
||||
PrivKey2: &bhex,
|
||||
PrivKey3: &bhex,
|
||||
PubKey1: &bhex,
|
||||
PubKey2: &bhex,
|
||||
PubKey3: &bhex,
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
{
|
||||
ECU: "ECUA",
|
||||
Version: "version",
|
||||
HWVersions: []string{"hardware_version"},
|
||||
Mode: "A",
|
||||
InstallPriority: 5,
|
||||
Files: []*common.UpdateManifestFile{
|
||||
{
|
||||
FileID: "fileid",
|
||||
URL: "http://download.com",
|
||||
Filename: "adas.bin",
|
||||
FileSize: 9999,
|
||||
FileType: common.Software,
|
||||
WriteRegionID: 9999,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
ID: 8888,
|
||||
Offset: 8888,
|
||||
Length: 8888,
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
{
|
||||
FileID: "SHOULD_NOT_BE_IN_UPDATE",
|
||||
URL: "http://download.com/SHOULD_NOT_BE_IN_UPDATE.bin",
|
||||
FileSize: 1000,
|
||||
Checksum: "AAAAAAA",
|
||||
FileType: common.Calibration,
|
||||
EraseRegionID: 200,
|
||||
EraseRegion: &common.MemoryRegion{
|
||||
Offset: 201,
|
||||
Length: 202,
|
||||
},
|
||||
Parsed: elptr.ElPtr(false),
|
||||
WriteRegionID: 100,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 101,
|
||||
Length: 102,
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
{
|
||||
FileID: "MUST_BE_IN_UPDATE",
|
||||
URL: "http://download.com/MUST_BE_IN_UPDATE.bin",
|
||||
FileSize: 1000,
|
||||
Checksum: "AAAAAAA",
|
||||
FileType: common.Calibration,
|
||||
EraseRegionID: 200,
|
||||
EraseRegion: &common.MemoryRegion{
|
||||
Offset: 201,
|
||||
Length: 202,
|
||||
},
|
||||
Parsed: elptr.ElPtr(true),
|
||||
WriteRegionID: 100,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 101,
|
||||
Length: 102,
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
},
|
||||
ECCKeys: &common.ECCKeys{
|
||||
ECU: "ECUA",
|
||||
PrivKey1: &bhex,
|
||||
PrivKey2: &bhex,
|
||||
PrivKey3: &bhex,
|
||||
PubKey1: &bhex,
|
||||
PubKey2: &bhex,
|
||||
PubKey3: &bhex,
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
}
|
||||
ecuaRollback := []*common.UpdateManifestECU{
|
||||
{
|
||||
ID: 100,
|
||||
UpdateManifestID: 200,
|
||||
ECU: "ECUA",
|
||||
Version: "VERSIONOLD",
|
||||
HWVersions: []string{"hardware_version"},
|
||||
Mode: "A",
|
||||
DBModelBase: th.Timestamp,
|
||||
Files: []*common.UpdateManifestFile{
|
||||
{
|
||||
FileID: "FILEIDOLD",
|
||||
UpdateManifestECUID: 1001,
|
||||
Filename: "FILENAMEOLD",
|
||||
URL: "URLOLD",
|
||||
FileType: common.Software,
|
||||
WriteRegionID: 700,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 701,
|
||||
Length: 702,
|
||||
},
|
||||
FileSize: 240,
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
},
|
||||
ECCKeys: &common.ECCKeys{
|
||||
ECU: "ECUA",
|
||||
PrivKey1: &bhex,
|
||||
PrivKey2: &bhex,
|
||||
PrivKey3: &bhex,
|
||||
PubKey1: &bhex,
|
||||
PubKey2: &bhex,
|
||||
PubKey3: &bhex,
|
||||
},
|
||||
},
|
||||
}
|
||||
mockDB := &services.DB{}
|
||||
mockCars := &mocks.MockCars{}
|
||||
mockCarUpdates := &mocks.MockCarUpdates{
|
||||
SelectCarUpdateResponse: &common.CarUpdate{
|
||||
UpdateManifestID: 816,
|
||||
UpdateManifest: &common.UpdateManifest{
|
||||
ID: 816,
|
||||
},
|
||||
},
|
||||
}
|
||||
mockManifests := &mocks.MockUpdateManifests{
|
||||
ECUUpdatesMock: func(man *common.UpdateManifestECU, vin string) ([]*common.UpdateManifestECU, error) {
|
||||
if man.ECU == "ECUA" {
|
||||
return ecuaRollback, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
mockKeys := &mocks.MockEccKeys{
|
||||
MockListResponse: []common.ECCKeys{
|
||||
{
|
||||
ECU: "PDU",
|
||||
PrivKey1: &bhex,
|
||||
PrivKey2: &bhex,
|
||||
PrivKey3: &bhex,
|
||||
PubKey1: &bhex,
|
||||
PubKey2: &bhex,
|
||||
PubKey3: &bhex,
|
||||
},
|
||||
{
|
||||
ECU: "TBOX",
|
||||
PrivKey1: &bhex,
|
||||
PrivKey2: &bhex,
|
||||
PrivKey3: &bhex,
|
||||
PubKey1: &bhex,
|
||||
PubKey2: &bhex,
|
||||
PubKey3: &bhex,
|
||||
},
|
||||
},
|
||||
}
|
||||
mockDB.SetCars(mockCars)
|
||||
mockDB.SetCarUpdates(mockCarUpdates)
|
||||
mockDB.SetECCKeys(mockKeys)
|
||||
mockDB.SetManifests(mockManifests)
|
||||
|
||||
mockFoa := FoaServiceMock{}
|
||||
services.SetFoaService(&mockFoa)
|
||||
|
||||
mockRedis := tester.NewRedisMock()
|
||||
mockKeepAwake := services.NewKeepAwakeService()
|
||||
services.SetRedisClientPool(tester.NewMockClientPool(mockRedis))
|
||||
mockSap := vconfig.SAPServiceMock{GetConfigurationMock: func(vin string) (common.SAPResponse, error) {
|
||||
return common.SAPResponse{
|
||||
ModelYear: 2023,
|
||||
ModelType: "Ocean",
|
||||
VersionDuringModelYear: "1",
|
||||
Features: []common.SAPFeature{
|
||||
{
|
||||
FamilyCode: "FamilyCode1",
|
||||
FeatureCode: "FeatureCode1",
|
||||
},
|
||||
{
|
||||
FamilyCode: "FamilyCode2",
|
||||
FeatureCode: "FeatureCode2",
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}}
|
||||
mockConf := vconfig.ConfigMock{GetVODCDSCodingDataMock: func(request common.VODCDSRequest) (map[string]string, error) {
|
||||
return map[string]string{
|
||||
"ECUA": "config",
|
||||
"VOD": "00a62299027600000101012200010100010001010101000000000000000000fffeffff000101010101010101010100010001010101000101010100000000000000000000000000010101000100000100010101000201010101000101020101000101010200010101010101010101000101010100010001010101010101010201010000000000000100000101ff00000001010200000000000003ffffffff0000000201010200000100000000000000000000000000000000000000000000000000000000000000000001202310010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, nil
|
||||
}}
|
||||
|
||||
services.SetSapService(mockSap)
|
||||
services.SetVehicleConfig(mockConf)
|
||||
schemaTesterHMI := th.NewSchemaTestHelper(t, schemaToHMI)
|
||||
schemaTesterTRex := th.NewSchemaTestHelper(t, schemaToTRex)
|
||||
|
||||
tests := []AttendentRouteTestCase{
|
||||
{
|
||||
Name: "[HMI] install_error",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.HMI,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":5,"total_files":10,"msg":"install_error","err":0}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":5,"status":"install_failed","total_files":10,"total_size":0}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_failed","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_failed","err":0}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_failed","err":0}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[HMI] download_completed",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.HMI,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"ICC","file_current":null,"file_total":null,"package_current":920639485,"package_total":920639485,"installed":null,"total_files":null,"msg":"download_completed","err":null}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":920639485,"ecu":"ICC","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"package_download_complete","total_files":0,"total_size":920639485}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
trexKey: `{"handler":"update_manifest","data":{"ecu_updates":[{"name":"ICC","version":"version","hw_version":"hardware_version","self_download":true},{"name":"ECUA","version":"version","hw_version":"hardware_version","configuration":"config","files":[{"file_id":"fileid","url":"http://download.com","file_size":9999,"type":"software","write_region":{"offset":8888,"length":8888}},{"file_id":"MUST_BE_IN_UPDATE","url":"http://download.com/MUST_BE_IN_UPDATE.bin","file_size":1000,"checksum":"AAAAAAA","type":"calibration","write_region":{"offset":101,"length":102},"erase_region":{"offset":201,"length":202}}],"rollback":[{"version":"VERSIONOLD","files":[{"file_id":"FILEIDOLD","url":"URLOLD","file_size":240,"type":"software","write_region":{"offset":701,"length":702}}]}],"ecc_keys":{"level_1":"74657374","level_2":"74657374","level_3":"74657374"}},{"name":"ADAS","version":"version","hw_version":"hardware_version","files":[{"file_id":"fileid","url":"http://download.com","file_size":9999,"type":"software","write_region":{"offset":8888,"length":8888}}],"ecc_keys":{"level_1":"74657374","level_2":"74657374","level_3":"74657374"}}],"fingerprint":"240119FISKER00000000000000000","car_update_id":297,"rollback":true,"type":"standard","vod":"01012299027600000101012200010100010001010101000000000000000000fffeffff000101010101010101010100010001010101000101010100000000000000000000000000010101000100000100010101000201010101000101020101000101010200010101010101010101000101010100010001010101010101010201010000000000000100000101ff00000001010200000000000003ffffffff00000002010102000001000000000000000000000000000000000000000000000000000000000000000000012023100100010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021","update_duration":30}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":920639485,"package_total":920639485,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ICC","msg":"package_download_complete","err":0}}`,
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":920639485,"package_total":920639485,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ICC","msg":"package_download_complete","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":920639485,"package_total":920639485,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ICC","msg":"package_download_complete","err":0}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
MockLoadManifest: &manifest,
|
||||
},
|
||||
{
|
||||
Name: "[HMI] manifest_succeeded",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.HMI,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"ICC","file_current":null,"file_total":null,"package_current":920639485,"package_total":920639485,"installed":null,"total_files":null,"msg":"manifest_succeeded","err":null}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":920639485,"ecu":"ICC","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"manifest_succeeded","total_files":0,"total_size":920639485}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":920639485,"package_total":920639485,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ICC","msg":"manifest_succeeded","err":0}}`,
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":920639485,"package_total":920639485,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ICC","msg":"manifest_succeeded","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":920639485,"package_total":920639485,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ICC","msg":"manifest_succeeded","err":0}}`,
|
||||
"1:JH4KA7680RC01": `{"handler":"read_ecu_versions","data":{"ecu_name":"*"}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
SelectCarUpdate: &common.CarUpdate{
|
||||
UpdateManifest: &validUpdateManifest,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] manifest_received",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"msg":"manifest_received","err":-6,"extra_info":""}`,
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"manifest_received","err":-6}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"manifest_received","err":-6}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"manifest_received","err":-6}}`,
|
||||
},
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":0,"ecu":"","errorcode":-6,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"manifest_received","total_files":0,"total_size":0}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] manifest_accepted",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"msg":"manifest_accepted","err":-7,"extra_info":""}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":0,"ecu":"","errorcode":-7,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"manifest_accepted","total_files":0,"total_size":0}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"manifest_accepted","err":-7}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"manifest_accepted","err":-7}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"manifest_accepted","err":-7}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] download_started",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"msg":"download_started","err":-14,"extra_info":""}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":0,"ecu":"","errorcode":-14,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"downloading","total_files":0,"total_size":0}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"downloading","err":-14}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"downloading","err":-14}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"downloading","err":-14}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] downloading",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"ADAS","file_current":1048576,"file_total":1264672,"package_current":1048576,"package_total":2529856,"msg":"downloading","err":0}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":1048576,"ecu":"ADAS","errorcode":0,"file_size":1048576,"file_total":1264672,"id":297,"installed":0,"status":"downloading","total_files":0,"total_size":2529856}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1048576,"file_total":1264672,"package_current":1048576,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ADAS","msg":"downloading","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1048576,"file_total":1264672,"package_current":1048576,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ADAS","msg":"downloading","err":0}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":1048576,"file_total":1264672,"package_current":1048576,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ADAS","msg":"downloading","err":0}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] download_completed ECU 1",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"ADAS","file_current":1264672,"file_total":1264672,"package_current":1264672,"package_total":2529856,"msg":"download_completed","err":0}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":1264672,"ecu":"ADAS","errorcode":0,"file_size":1264672,"file_total":1264672,"id":297,"installed":0,"status":"downloading","total_files":0,"total_size":2529856}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1264672,"file_total":1264672,"package_current":1264672,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ADAS","msg":"downloading","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1264672,"file_total":1264672,"package_current":1264672,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ADAS","msg":"downloading","err":0}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":1264672,"file_total":1264672,"package_current":1264672,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"ADAS","msg":"downloading","err":0}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] download_started ECU 2",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"EKS","file_current":0,"file_total":1265184,"package_current":1264672,"package_total":2529856,"msg":"download_started","err":0}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":1264672,"ecu":"EKS","errorcode":0,"file_size":0,"file_total":1265184,"id":297,"installed":0,"status":"downloading","total_files":0,"total_size":2529856}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":1265184,"package_current":1264672,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"downloading","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":1265184,"package_current":1264672,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"downloading","err":0}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":1265184,"package_current":1264672,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"downloading","err":0}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] downloading ECU 2",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"EKS","file_current":1048576,"file_total":1265184,"package_current":2313248,"package_total":2529856,"msg":"downloading","err":0}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":2313248,"ecu":"EKS","errorcode":0,"file_size":1048576,"file_total":1265184,"id":297,"installed":0,"status":"downloading","total_files":0,"total_size":2529856}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1048576,"file_total":1265184,"package_current":2313248,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"downloading","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1048576,"file_total":1265184,"package_current":2313248,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"downloading","err":0}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":1048576,"file_total":1265184,"package_current":2313248,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"downloading","err":0}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] download_completed ECU 2",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"EKS","file_current":1265184,"file_total":1265184,"package_current":2529856,"package_total":2529856,"msg":"download_completed","err":0}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":2529856,"ecu":"EKS","errorcode":0,"file_size":1265184,"file_total":1265184,"id":297,"installed":0,"status":"package_download_complete","total_files":0,"total_size":2529856}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1265184,"file_total":1265184,"package_current":2529856,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"package_download_complete","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":1265184,"file_total":1265184,"package_current":2529856,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"package_download_complete","err":0}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":1265184,"file_total":1265184,"package_current":2529856,"package_total":2529856,"installed":0,"total_files":0,"car_update_id":297,"ecu":"EKS","msg":"package_download_complete","err":0}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] package_download_complete",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"msg":"download_completed","err":-15,"extra_info":""}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":0,"ecu":"","errorcode":-15,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"package_download_complete","total_files":0,"total_size":0}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"package_download_complete","err":-15}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"package_download_complete","err":-15}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"package_download_complete","err":-15}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] download_failed",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"TEST","file_current":0,"file_total":100,"package_current":0,"package_total":1000,"msg":"download_failed","err":0}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":100,"id":297,"installed":0,"status":"download_failed","total_files":0,"total_size":1000}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":100,"package_current":0,"package_total":1000,"installed":0,"total_files":0,"car_update_id":297,"ecu":"TEST","msg":"download_failed","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":100,"package_current":0,"package_total":1000,"installed":0,"total_files":0,"car_update_id":297,"ecu":"TEST","msg":"download_failed","err":0}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":100,"package_current":0,"package_total":1000,"installed":0,"total_files":0,"car_update_id":297,"ecu":"TEST","msg":"download_failed","err":0}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] install_started",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":0,"total_files":10,"msg":"install_started","err":0}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"installing","total_files":10,"total_size":0}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"installing","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"installing","err":0}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"installing","err":0}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] installing",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":5,"total_files":10,"msg":"installing","err":0}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":5,"status":"installing","total_files":10,"total_size":0}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"installing","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"installing","err":0}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"installing","err":0}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] install_succeeded ECU",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":10,"total_files":10,"msg":"install_succeeded"}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":10,"status":"package_install_complete","total_files":10,"total_size":0}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"package_install_complete","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"package_install_complete","err":0}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"package_install_complete","err":0}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] package_install_complete",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"msg":"install_succeeded","err":0}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":0,"ecu":"","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":0,"status":"installing","total_files":0,"total_size":0}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"installing","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"installing","err":0}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":0,"total_files":0,"car_update_id":297,"ecu":"","msg":"installing","err":0}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] install_failed",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":5,"total_files":10,"msg":"install_failed","err":0}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":5,"status":"install_failed","total_files":10,"total_size":0}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_failed","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_failed","err":0}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_failed","err":0}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] requirements_failed",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":5,"total_files":10,"msg":"requirements_failed","err":0}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":5,"status":"requirements_failed","total_files":10,"total_size":0}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"requirements_failed","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"requirements_failed","err":0}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":5,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"requirements_failed","err":0}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] install_scheduled ECU",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":10,"total_files":10,"msg":"install_scheduled"}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":10,"status":"install_scheduled","total_files":10,"total_size":0}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_scheduled","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_scheduled","err":0}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"install_scheduled","err":0}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "[TREX] manifest_succeeded",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":297,"ecu":"TEST","installed":10,"total_files":10,"msg":"manifest_succeeded"}`,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
carupdateKey: {
|
||||
Value: `{"current_size":0,"ecu":"TEST","errorcode":0,"file_size":0,"file_total":0,"id":297,"installed":10,"status":"manifest_succeeded","total_files":10,"total_size":0}`,
|
||||
Expires: expectedExpire,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
mobile1Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"manifest_succeeded","err":0}}`,
|
||||
mobile2Key: `{"handler":"car_update_status","data":{"vin":"JH4KA7680RC01","file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"manifest_succeeded","err":0}}`,
|
||||
hmiKey: `{"handler":"car_update_status","data":{"file_current":0,"file_total":0,"package_current":0,"package_total":0,"installed":10,"total_files":10,"car_update_id":297,"ecu":"TEST","msg":"manifest_succeeded","err":0}}`,
|
||||
"1:JH4KA7680RC01": `{"handler":"read_ecu_versions","data":{"ecu_name":"*"}}`,
|
||||
},
|
||||
MockRedisGetSet: testGetSetResult,
|
||||
},
|
||||
SelectCarUpdate: &common.CarUpdate{
|
||||
UpdateManifest: &validUpdateManifest,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i := range tests {
|
||||
mockRedis.Reset()
|
||||
test := &tests[i]
|
||||
test.SetupRedis(mockRedis)
|
||||
test.SetupDB(mockCars, mockCarUpdates, test)
|
||||
|
||||
redisPool := tester.NewMockClientPool(mockRedis)
|
||||
handler := controllers.NewCarUpdateProgress(redisPool, mockKeepAwake, mockDB, test.Device)
|
||||
if handler == nil {
|
||||
t.Error(errors.New("NewCarUpdateProgress cannot handle device %v"))
|
||||
continue
|
||||
}
|
||||
err := handler.Process(test.DeviceKey, []byte(test.PayloadData))
|
||||
|
||||
test.CheckHandlerError(t, test.Name, err)
|
||||
test.Validate(t, test.Name, mockRedis)
|
||||
|
||||
for key, m := range test.RedisTestCase.ExpectedMessages {
|
||||
name := fmt.Sprintf("%s %s", test.Name, key)
|
||||
if strings.Contains(key, "1:") {
|
||||
schemaTesterTRex.ValidateSchemaObject(name, []byte(m))
|
||||
} else if strings.Contains(key, "2:") {
|
||||
schemaTesterHMI.ValidateSchemaObject(name, []byte(m))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type FoaServiceMock struct{}
|
||||
|
||||
func (f *FoaServiceMock) OtaUpdateStatus(vin string, carUpdate *common.CarUpdate, status *common.CarUpdateProgress) (*http.Response, error) {
|
||||
return &http.Response{StatusCode: 200}, nil
|
||||
}
|
||||
74
services/attendant/handlers/car_update_state.go
Normal file
74
services/attendant/handlers/car_update_state.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
fv "github.com/fiskerinc/cloud-services/pkg/flashpackversion"
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
"github.com/fiskerinc/cloud-services/pkg/validator"
|
||||
)
|
||||
|
||||
func UpdateCarState(db *services.DB, vin string, data []byte) error {
|
||||
logger.Debug().Msgf("UpdateCarState %s", vin)
|
||||
var update common.CarStateUpdate
|
||||
|
||||
err := json.Unmarshal(data, &update)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = validator.ValidateStruct(&update)
|
||||
if err != nil {
|
||||
logger.Err(err).Interface("CarStateUpdate", update).Str("CarStateUpdateByteValue as string", string(data)).Send()
|
||||
return err
|
||||
}
|
||||
|
||||
return processUpdateCarStateECUs(db, vin, update.ECUs)
|
||||
}
|
||||
|
||||
func processUpdateCarStateECUs(db *services.DB, vin string, ecus map[string]common.CarECU) error {
|
||||
cache := services.GetCarEcuCache()
|
||||
insert := []common.CarECU{}
|
||||
errs := []error{}
|
||||
|
||||
for name, ecu := range ecus {
|
||||
ecu.VIN = vin
|
||||
ecu.ECU = name
|
||||
err := validator.ValidateStruct(&ecu)
|
||||
if err != nil {
|
||||
logger.Error().Msgf("invalid CarECU %v", err)
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !cache.Exists(ecu.CacheKey(), ecu.HashValues()) {
|
||||
insert = append(insert, ecu)
|
||||
}
|
||||
}
|
||||
|
||||
if len(insert) == 0 {
|
||||
return combineErrors(errs)
|
||||
}
|
||||
|
||||
err := fv.InsertCarECUsAndUpdateFlashpackVersion(db.GetCars(), db.GetCarVersionsLog(), vin, insert)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
return combineErrors(errs)
|
||||
}
|
||||
|
||||
func combineErrors(errs []error) error {
|
||||
if len(errs) == 0 {
|
||||
return nil
|
||||
}
|
||||
errString := errs[0].Error()
|
||||
for i := 1; i < len(errs); i++ {
|
||||
errString += " " + errs[i].Error()
|
||||
}
|
||||
return errors.New(errString)
|
||||
}
|
||||
113
services/attendant/handlers/car_update_state_test.go
Normal file
113
services/attendant/handlers/car_update_state_test.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/handlers"
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/testhelper"
|
||||
vconfig "github.com/fiskerinc/cloud-services/pkg/vehicleconfig"
|
||||
)
|
||||
|
||||
func TestUpdateCarState(t *testing.T) {
|
||||
setupDBMock()
|
||||
setupRedisMock()
|
||||
|
||||
mockSap := vconfig.SAPServiceMock{}
|
||||
services.SetSapService(mockSap)
|
||||
|
||||
type testCase struct {
|
||||
Name string
|
||||
VIN string
|
||||
Payload string
|
||||
ExpectedErr string
|
||||
}
|
||||
|
||||
tests := []testCase{
|
||||
{
|
||||
Name: "Empty ECU",
|
||||
VIN: "JH4KA7680RC011845",
|
||||
Payload: `{"ecus": {}}`,
|
||||
ExpectedErr: "Key: 'CarStateUpdate.ECUs' Error:Field validation for 'ECUs' failed on the 'min' tag",
|
||||
},
|
||||
{
|
||||
Name: "Bad VIN and ECU",
|
||||
VIN: "JH4KA7680RC01",
|
||||
Payload: `{
|
||||
"ecus": {
|
||||
"ECU1": {
|
||||
"serial_number": "AAAAA",
|
||||
"hw_version": "2000",
|
||||
"boot_loader_version": "3000",
|
||||
"fingerprint": "0xffffffffffffffffff",
|
||||
"config": "0x024000941f9fffbfffe2dd9bff5860000007dfff091fff7f",
|
||||
"vendor": "A021E00029"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
ExpectedErr: "Key: 'CarECU.VIN' Error:Field validation for 'VIN' failed on the 'vin' tag",
|
||||
},
|
||||
{
|
||||
Name: "Good ECUs with/without software version",
|
||||
VIN: "JH4KA7680RC011845",
|
||||
Payload: `{
|
||||
"ecus": {
|
||||
"ECU1": {
|
||||
"sw_version": "1000",
|
||||
"serial_number": "AAAAA",
|
||||
"hw_version": "2000",
|
||||
"boot_loader_version": "3000",
|
||||
"fingerprint": "0xffffffffffffffffff",
|
||||
"config": "0x024000941f9fffbfffe2dd9bff5860000007dfff091fff7f",
|
||||
"vendor": "A021E00029"
|
||||
},
|
||||
"ECU2": {
|
||||
"serial_number": "BBBBBBB",
|
||||
"hw_version": "2001",
|
||||
"boot_loader_version": "3001",
|
||||
"fingerprint": "0xffffffffffffffffff",
|
||||
"config": "0x024000941f9fffbfffe2dd9bff5860000007dfff091fff7f",
|
||||
"vendor": "A021E00029"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
ExpectedErr: "",
|
||||
},
|
||||
{
|
||||
Name: "bad ECU followed by a Good ECU",
|
||||
VIN: "JH4KA7680RC011845",
|
||||
Payload: `{
|
||||
"ecus": {
|
||||
"ECU1": {
|
||||
"serial_number": "AAAAA",
|
||||
"hw_version": "2000",
|
||||
"boot_loader_version": "3000",
|
||||
"fingerprint": "0xffffffffffffffffff",
|
||||
"config": "0x024000941f9fffbfffe2dd9bff5860000007dfff091fff7f",
|
||||
"vendor": "A021E00029",
|
||||
"epoch_usec": "ABC"
|
||||
},
|
||||
"ECU2": {
|
||||
"serial_number": "BBBBBBB",
|
||||
"hw_version": "2001",
|
||||
"boot_loader_version": "3001",
|
||||
"fingerprint": "0xffffffffffffffffff",
|
||||
"config": "0x024000941f9fffbfffe2dd9bff5860000007dfff091fff7f",
|
||||
"vendor": "A021E00029"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
ExpectedErr: "json: cannot unmarshal string into Go struct field CarECU.ecus.epoch_usec of type int64",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
err := handlers.UpdateCarState(mockDB, test.VIN, []byte(test.Payload))
|
||||
if err != nil && test.ExpectedErr != err.Error() {
|
||||
t.Errorf(testhelper.TestErrorTemplate, test.Name, test.ExpectedErr, err.Error())
|
||||
} else if err == nil && test.ExpectedErr != "" {
|
||||
t.Errorf(testhelper.TestErrorTemplate, test.Name, test.ExpectedErr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
94
services/attendant/handlers/get_ecc_keys.go
Normal file
94
services/attendant/handlers/get_ecc_keys.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func GetAllEccKeys(db *services.DB, id string, data []byte) error {
|
||||
logger.Debug().Msgf("GetAllEccKeys %v %s", common.TRex, id)
|
||||
var err error
|
||||
var eccKeys []common.ECCKeys
|
||||
|
||||
req, err := parseGetAllEccKeysRequest(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if req.CarUpdateID == 0 {
|
||||
eccKeys, err = db.GetECCKeys().SelectAllPrivateKeysByVIN(id)
|
||||
} else {
|
||||
eccKeys, err = db.GetECCKeys().SelectAllPrivateKeysByCarUpdateID(req.CarUpdateID)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if eccKeys == nil {
|
||||
eccKeys = make([]common.ECCKeys, 0)
|
||||
}
|
||||
eccKeys = replaceECU(eccKeys)
|
||||
|
||||
client := services.RedisClientPool().GetFromPool()
|
||||
defer client.Close()
|
||||
|
||||
err = client.SafePublishMessage(common.TRex.Key(id), common.Message{
|
||||
Handler: "ecc_keys",
|
||||
Data: eccKeys,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Debug().Msgf("GetAllEccKeys sent %v %s", common.TRex, id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseGetAllEccKeysRequest(data []byte) (common.CarUpdateRequest, error) {
|
||||
var req common.CarUpdateRequest
|
||||
|
||||
if len(data) == 0 {
|
||||
return req, nil
|
||||
}
|
||||
|
||||
err := json.Unmarshal(data, &req)
|
||||
if err != nil {
|
||||
return req, errors.WithStack(err)
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func replaceECU(eccKeys []common.ECCKeys) []common.ECCKeys {
|
||||
|
||||
ecuReplacements := common.ECUReplacement()
|
||||
for i := 0; i < len(eccKeys); i++ {
|
||||
ecu := eccKeys[i].ECU
|
||||
if replacement, exist := ecuReplacements[ecu]; exist {
|
||||
eccKeys[i].ECU = replacement
|
||||
}
|
||||
}
|
||||
return eccKeys
|
||||
}
|
||||
|
||||
/*
|
||||
func notifyEccKeysGeneralError(client redis.Client, device common.Device, id string, err error) {
|
||||
e := client.PublishMessage(device.Key(id), common.Message{
|
||||
Handler: "ecc_keys",
|
||||
Data: []struct{ Error string }{
|
||||
{
|
||||
Error: err.Error(),
|
||||
},
|
||||
},
|
||||
})
|
||||
if e != nil {
|
||||
logger.Error().Err(errors.WithStack(e)).Send()
|
||||
}
|
||||
}
|
||||
*/
|
||||
111
services/attendant/handlers/get_ecc_keys_test.go
Normal file
111
services/attendant/handlers/get_ecc_keys_test.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/handlers"
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
"testing"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/db/queries/mocks"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis/tester"
|
||||
"github.com/fiskerinc/cloud-services/pkg/testhelper"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestGetAllEccKeys(t *testing.T) {
|
||||
testVIN := "JH4KA7680RC01"
|
||||
trexKey := "1:JH4KA7680RC01"
|
||||
|
||||
pk11 := common.NewBinaryHex([]byte("testprivkey11"))
|
||||
pk12 := common.NewBinaryHex([]byte("testprivkey12"))
|
||||
pk13 := common.NewBinaryHex([]byte("testprivkey13"))
|
||||
pk21 := common.NewBinaryHex([]byte("testprivkey21"))
|
||||
pk22 := common.NewBinaryHex([]byte("testprivkey22"))
|
||||
pk23 := common.NewBinaryHex([]byte("testprivkey23"))
|
||||
|
||||
testDBQuery := []common.ECCKeys{
|
||||
{
|
||||
ECU: "testecu1",
|
||||
PrivKey1: &pk11,
|
||||
PrivKey2: &pk12,
|
||||
PrivKey3: &pk13,
|
||||
},
|
||||
{
|
||||
ECU: "testecu2",
|
||||
PrivKey1: &pk21,
|
||||
PrivKey2: &pk22,
|
||||
PrivKey3: &pk23,
|
||||
},
|
||||
{
|
||||
ECU: "PDU",
|
||||
PrivKey1: &pk21,
|
||||
PrivKey2: &pk22,
|
||||
PrivKey3: &pk23,
|
||||
},
|
||||
}
|
||||
|
||||
mockRedis := tester.NewRedisMock()
|
||||
services.SetRedisClientPool(tester.NewMockClientPool(mockRedis))
|
||||
mockEccKeys := &mocks.MockEccKeys{}
|
||||
mockDB := &services.DB{}
|
||||
mockDB.SetECCKeys(mockEccKeys)
|
||||
|
||||
tests := []AttendentRouteTestCase{
|
||||
{
|
||||
Name: "[TREX] From DB, no car update id",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
ExpectedMessages: map[string]string{
|
||||
trexKey: `{"handler":"ecc_keys","data":[{"ecu":"testecu1","level_1":"74657374707269766b65793131","level_2":"74657374707269766b65793132","level_3":"74657374707269766b65793133"},{"ecu":"testecu2","level_1":"74657374707269766b65793231","level_2":"74657374707269766b65793232","level_3":"74657374707269766b65793233"},{"ecu":"OBC","level_1":"74657374707269766b65793231","level_2":"74657374707269766b65793232","level_3":"74657374707269766b65793233"}]}`,
|
||||
},
|
||||
},
|
||||
MockEccKeysSelect: testDBQuery,
|
||||
},
|
||||
{
|
||||
Name: "[TREX] From DB, with car update id",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
ExpectedMessages: map[string]string{
|
||||
trexKey: `{"handler":"ecc_keys","data":[{"ecu":"testecu1","level_1":"74657374707269766b65793131","level_2":"74657374707269766b65793132","level_3":"74657374707269766b65793133"},{"ecu":"testecu2","level_1":"74657374707269766b65793231","level_2":"74657374707269766b65793232","level_3":"74657374707269766b65793233"},{"ecu":"OBC","level_1":"74657374707269766b65793231","level_2":"74657374707269766b65793232","level_3":"74657374707269766b65793233"}]}`,
|
||||
},
|
||||
PayloadData: `{"car_update_id":10000}`,
|
||||
},
|
||||
MockEccKeysSelect: testDBQuery,
|
||||
},
|
||||
{
|
||||
Name: "Error",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
ExpectedError: "something went wrong",
|
||||
},
|
||||
MockEccKeysSelect: nil,
|
||||
},
|
||||
}
|
||||
|
||||
schemaTester := testhelper.NewSchemaTestHelper(t, schemaToTRex)
|
||||
for _, test := range tests {
|
||||
t.Run(test.Name, func(t *testing.T) {
|
||||
mockRedis.Reset()
|
||||
test.SetupRedis(mockRedis)
|
||||
mockEccKeys.MockListResponse = test.MockEccKeysSelect
|
||||
|
||||
if test.Name == "Error" {
|
||||
mockEccKeys.Error = errors.New("something went wrong")
|
||||
} else {
|
||||
mockEccKeys.Error = nil
|
||||
}
|
||||
|
||||
err := handlers.GetAllEccKeys(mockDB, test.DeviceKey, []byte(test.PayloadData))
|
||||
|
||||
test.CheckHandlerError(t, test.Name, err)
|
||||
test.Validate(t, test.Name, mockRedis)
|
||||
|
||||
for _, m := range test.ExpectedMessages {
|
||||
schemaTester.ValidateSchemaObject(test.Name, []byte(m))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
80
services/attendant/handlers/get_filekeys.go
Normal file
80
services/attendant/handlers/get_filekeys.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/cache"
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis"
|
||||
"github.com/fiskerinc/cloud-services/pkg/validator"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func GetFileKeys(db *services.DB, device common.Device, id string, data []byte) error {
|
||||
logger.Debug().Msgf("GetFileKeys %v %s", device, id)
|
||||
var err error
|
||||
var req *common.FileKeysRequest
|
||||
|
||||
client := services.RedisClientPool().GetFromPool()
|
||||
defer client.Close()
|
||||
|
||||
req, err = parseGetFileKeysRequest(data)
|
||||
if err != nil {
|
||||
notifyFileKeysGeneralError(client, device, id, err)
|
||||
return err
|
||||
}
|
||||
|
||||
keys, err := cache.RetrieveFileEncryptionParams(client, db.GetFileKeys(), req.FileIDs)
|
||||
if err != nil {
|
||||
notifyFileKeysGeneralError(client, device, id, err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = client.SafeQueueMessage(device.Key(id), common.Message{
|
||||
Handler: "filekeys",
|
||||
Data: keys,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Debug().Msgf("GetFileKeys sent %v %s", device, id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseGetFileKeysRequest(data []byte) (*common.FileKeysRequest, error) {
|
||||
var status common.FileKeysRequest
|
||||
|
||||
err := json.Unmarshal(data, &status)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
err = validator.ValidateStruct(status)
|
||||
if err != nil {
|
||||
return &status, errors.WithStack(err)
|
||||
}
|
||||
|
||||
return &status, nil
|
||||
}
|
||||
|
||||
func notifyFileKeysGeneralError(client redis.Client, device common.Device, id string, err error) {
|
||||
e := client.SafePublishMessage(device.Key(id), common.Message{
|
||||
Handler: "filekeys",
|
||||
Data: []common.FileKeyResponse{
|
||||
{
|
||||
FileID: "0",
|
||||
Error: err.Error(),
|
||||
},
|
||||
},
|
||||
})
|
||||
if e != nil {
|
||||
logger.Error().Err(errors.WithStack(e)).Send()
|
||||
}
|
||||
}
|
||||
124
services/attendant/handlers/get_filekeys_test.go
Normal file
124
services/attendant/handlers/get_filekeys_test.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/db/queries/mocks"
|
||||
"github.com/fiskerinc/cloud-services/pkg/testhelper"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/handlers"
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis/tester"
|
||||
)
|
||||
|
||||
func TestGetFileKey(t *testing.T) {
|
||||
testVIN := "JH4KA7680RC01"
|
||||
trexKey := "1:JH4KA7680RC01"
|
||||
hmiKey := "2:JH4KA7680RC01"
|
||||
fileCache1 := "fileid:b7d94be8c94062cf"
|
||||
fileCache2 := "fileid:83165a80c940e8b3"
|
||||
testPayload := `{"file_ids": ["b7d94be8c94062cf","83165a80c940e8b3"]}`
|
||||
testDBQuery := []common.FileKey{
|
||||
{
|
||||
FileID: "b7d94be8c94062cf",
|
||||
Auth: []byte("AuthValue"),
|
||||
Key: []byte("KeyValue"),
|
||||
Nonce: []byte("NonceValue"),
|
||||
},
|
||||
{
|
||||
FileID: "83165a80c940e8b3",
|
||||
Auth: []byte("AuthValue2"),
|
||||
Key: []byte("KeyValue2"),
|
||||
Nonce: []byte("NonceValue2"),
|
||||
},
|
||||
}
|
||||
|
||||
mockRedis := tester.NewRedisMock()
|
||||
services.SetRedisClientPool(tester.NewMockClientPool(mockRedis))
|
||||
mockFileKeys := &mocks.MockFileKeys{}
|
||||
mockDB := &services.DB{}
|
||||
mockDB.SetFileKeys(mockFileKeys)
|
||||
|
||||
tests := []AttendentRouteTestCase{
|
||||
{
|
||||
Name: "[TREX] From DB",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.TRex,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: testPayload,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
fileCache1: {
|
||||
Value: `{"file_id":"b7d94be8c94062cf","key":"S2V5VmFsdWU=","auth":"QXV0aFZhbHVl","nonce":"Tm9uY2VWYWx1ZQ=="}`,
|
||||
Expires: 86400,
|
||||
},
|
||||
fileCache2: {
|
||||
Value: `{"file_id":"83165a80c940e8b3","key":"S2V5VmFsdWUy","auth":"QXV0aFZhbHVlMg==","nonce":"Tm9uY2VWYWx1ZTI="}`,
|
||||
Expires: 86400,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
trexKey: `{"handler":"filekeys","data":[{"file_id":"b7d94be8c94062cf","key":"S2V5VmFsdWU=","auth":"QXV0aFZhbHVl","nonce":"Tm9uY2VWYWx1ZQ=="},{"file_id":"83165a80c940e8b3","key":"S2V5VmFsdWUy","auth":"QXV0aFZhbHVlMg==","nonce":"Tm9uY2VWYWx1ZTI="}]}`,
|
||||
},
|
||||
},
|
||||
MockFileKeysSelect: testDBQuery,
|
||||
MockFileKeysError: nil,
|
||||
},
|
||||
{
|
||||
Name: "[HMI] From DB",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.HMI,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: testPayload,
|
||||
ExpectedCaches: map[string]tester.ExpiringCacheResult{
|
||||
fileCache1: {
|
||||
Value: `{"file_id":"b7d94be8c94062cf","key":"S2V5VmFsdWU=","auth":"QXV0aFZhbHVl","nonce":"Tm9uY2VWYWx1ZQ=="}`,
|
||||
Expires: 86400,
|
||||
},
|
||||
fileCache2: {
|
||||
Value: `{"file_id":"83165a80c940e8b3","key":"S2V5VmFsdWUy","auth":"QXV0aFZhbHVlMg==","nonce":"Tm9uY2VWYWx1ZTI="}`,
|
||||
Expires: 86400,
|
||||
},
|
||||
},
|
||||
ExpectedMessages: map[string]string{
|
||||
hmiKey: `{"handler":"filekeys","data":[{"file_id":"b7d94be8c94062cf","key":"S2V5VmFsdWU=","auth":"QXV0aFZhbHVl","nonce":"Tm9uY2VWYWx1ZQ=="},{"file_id":"83165a80c940e8b3","key":"S2V5VmFsdWUy","auth":"QXV0aFZhbHVlMg==","nonce":"Tm9uY2VWYWx1ZTI="}]}`,
|
||||
},
|
||||
},
|
||||
MockFileKeysSelect: testDBQuery,
|
||||
MockFileKeysError: nil,
|
||||
},
|
||||
}
|
||||
|
||||
schemaTester := testhelper.NewSchemaTestHelper(t, schemaToTRex)
|
||||
for _, test := range tests {
|
||||
t.Run(test.Name, func(t *testing.T) {
|
||||
mockRedis.Reset()
|
||||
test.SetupRedis(mockRedis)
|
||||
mockFileKeys.GetMultiResponse = test.MockFileKeysSelect
|
||||
mockFileKeys.Error = test.MockFileKeysError
|
||||
|
||||
err := handlers.GetFileKeys(mockDB, test.Device, test.DeviceKey, []byte(test.PayloadData))
|
||||
|
||||
test.CheckHandlerError(t, test.Name, err)
|
||||
test.Validate(t, test.Name, mockRedis)
|
||||
|
||||
for _, m := range test.ExpectedMessages {
|
||||
schemaTester.ValidateSchemaObject(test.Name, []byte(m))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGetFileKey(b *testing.B) {
|
||||
db := services.GetDB()
|
||||
vin := "1F15K3R45N1234567"
|
||||
id := []byte(`{"file_ids": ["b7d94be8c94062cf","83165a80c940e8b3"]}`)
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
err := handlers.GetFileKeys(db, common.TRex, vin, id)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
113
services/attendant/handlers/mock_test.go
Normal file
113
services/attendant/handlers/mock_test.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/db/queries/mocks"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis/tester"
|
||||
"github.com/go-pg/pg/v10/orm"
|
||||
)
|
||||
|
||||
var mockRedis *redis.Connection
|
||||
var mockDB *services.DB
|
||||
var testDateTime time.Time = time.Date(2022, 1, 2, 3, 4, 5, 6, time.UTC)
|
||||
|
||||
func setupRedisMock() {
|
||||
redis.MockRedisConnection()
|
||||
mockRedis = &redis.Connection{}
|
||||
}
|
||||
|
||||
func setupDBMock() {
|
||||
db := services.DB{}
|
||||
db.SetCarUpdates(&mocks.MockCarUpdates{
|
||||
SelectCarUpdateResponse: &common.CarUpdate{
|
||||
ID: 1,
|
||||
VIN: "FISKER123",
|
||||
UpdateManifestID: 2,
|
||||
UpdateManifest: &common.UpdateManifest{
|
||||
ID: 2,
|
||||
Name: "TEST_PACKAGE",
|
||||
Version: "1.0.0",
|
||||
ReleaseNotes: "http://releasenotes.com",
|
||||
Country: "US",
|
||||
PowerTrain: "MD23",
|
||||
Restraint: "None",
|
||||
Model: "Ocean",
|
||||
Trim: "Sport",
|
||||
Year: 2022,
|
||||
BodyType: "truck",
|
||||
},
|
||||
},
|
||||
})
|
||||
db.SetECU(&mocks.MockEcuDtc{})
|
||||
db.SetCars(&mocks.MockCars{
|
||||
SelectResponse: &common.Car{},
|
||||
})
|
||||
carVersionLogMock := mocks.MockCarVersionsLog{MockLogVersionChange: func(log *common.CarVersionLogs) (orm.Result, error) {
|
||||
return nil, nil
|
||||
}}
|
||||
db.SetCarVersionsLog(&carVersionLogMock)
|
||||
mockDB = &db
|
||||
}
|
||||
|
||||
type mockRedisCache struct {
|
||||
redis.Connection
|
||||
}
|
||||
|
||||
func (c *mockRedisCache) GetSet(id string, data interface{}) error {
|
||||
driverIDs := []string{"valid-cognito-id-1", "valid-cognito-id-2"}
|
||||
|
||||
dataBytes, err := json.Marshal(driverIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(dataBytes, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewRedisMock() *tester.MockRedis {
|
||||
redis.MockRedisConnection()
|
||||
return &tester.MockRedis{}
|
||||
}
|
||||
|
||||
type AttendentRouteTestCase struct {
|
||||
Name string
|
||||
SelectCarUpdate *common.CarUpdate
|
||||
SelectCarUpdates []common.CarUpdate
|
||||
CarUpdateError error
|
||||
SelectCarToDrivers []common.CarToDriver
|
||||
CarToDriversError error
|
||||
MockLoadManifest *common.UpdateManifest
|
||||
MockFileKeysSelect []common.FileKey
|
||||
MockFileKeysError error
|
||||
MockEccKeysSelect []common.ECCKeys
|
||||
tester.RedisTestCase
|
||||
}
|
||||
|
||||
func (at *AttendentRouteTestCase) SetupDB(mockCars *mocks.MockCars, mockCarUpdates *mocks.MockCarUpdates, test *AttendentRouteTestCase) {
|
||||
if test == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if mockCars != nil {
|
||||
mockCars.SelectCarsForDrivers = test.SelectCarToDrivers
|
||||
mockCars.Error = test.CarToDriversError
|
||||
}
|
||||
|
||||
if mockCarUpdates != nil {
|
||||
mockCarUpdates.SelectCarUpdateResponse = test.SelectCarUpdate
|
||||
mockCarUpdates.SelectCarUpdatesResponse = test.SelectCarUpdates
|
||||
mockCarUpdates.LoadManifest = test.MockLoadManifest
|
||||
mockCarUpdates.Error = test.CarUpdateError
|
||||
}
|
||||
}
|
||||
160
services/attendant/handlers/order_updated.go
Normal file
160
services/attendant/handlers/order_updated.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/grpc/sms"
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
"github.com/fiskerinc/cloud-services/pkg/manifestsender"
|
||||
"github.com/fiskerinc/cloud-services/pkg/tmobile"
|
||||
"github.com/fiskerinc/cloud-services/pkg/utils/envtool"
|
||||
)
|
||||
|
||||
var ENABLE_ORDERUPDATE_SENDS = envtool.GetEnvBool("ENABLE_ORDERUPDATE_SENDS", false)
|
||||
|
||||
// Take the feature codes from VehicleOrder message to generate the VOD and CDSs
|
||||
// Create a new common.UpdateManifest with the VOD and CDS and save it as a common.ConfigUpdateType
|
||||
// Create a new common.CarUpdate for the VIN and the manifest in step 2 and save it to the database
|
||||
// Copy the car update id into the UpdateManifest
|
||||
// Send the UpdateManifest to both trex and hmi
|
||||
func OrderUpdated(db *services.DB, smsClient sms.SMSServiceClient, vin string, data []byte) error {
|
||||
logger.Debug().Msgf("Order updated %s", vin)
|
||||
|
||||
var order common.VehicleOrder
|
||||
err := json.Unmarshal(data, &order)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = setCarSettings(db, vin, order)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = changeRatePlan(db, smsClient, vin, order.VehicleSpecification.DestinationCountry)
|
||||
if err != nil {
|
||||
logger.Error().Msgf("Failed to change rate plan for %s, %s", vin, err)
|
||||
}
|
||||
|
||||
if !ENABLE_ORDERUPDATE_SENDS {
|
||||
return nil
|
||||
}
|
||||
|
||||
cs := services.GetVehicleConfig()
|
||||
r := services.RedisClientPool().GetFromPool()
|
||||
defer r.Close()
|
||||
|
||||
trex := manifestsender.NewTBOXManifestSender(r, cs, services.GetDB(), nil, nil)
|
||||
defer trex.Close()
|
||||
|
||||
// I don't think this has ever been called on production, or dev !
|
||||
input := manifestsender.ProcessConfigUpdateStruct{
|
||||
VIN: vin,
|
||||
Name: "SAP order change update",
|
||||
Username: "unidentified attendant sap user",
|
||||
SendToCar: true,
|
||||
DontCreateDatabaseEntry: false,
|
||||
Forced: false,
|
||||
}
|
||||
_, err = trex.ProcessConfigUpdate(input, services.GetDB().GetCarConfigData())
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func setCarSettings(db *services.DB, vin string, order common.VehicleOrder) (err error) {
|
||||
// If the sequence number is missing, go will fill it in as 0, which is the case where the car has no sequence number
|
||||
if order.VehicleSpecification.SequenceNumber != "" {
|
||||
_, err = db.GetCars().SetSetting(&common.CarSetting{
|
||||
VIN: vin,
|
||||
Name: common.SEQUENCE_NUMBER,
|
||||
Value: fmt.Sprint(order.VehicleSpecification.SequenceNumber),
|
||||
Type: "string",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = db.GetCars().SetSetting(&common.CarSetting{
|
||||
VIN: vin,
|
||||
Name: common.BODY_COLOR,
|
||||
Value: common.FeatureCodeToBodyColor(order.VehicleSpecification.VehicleFeatures),
|
||||
Type: "string",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Incase SAP hasn't sent this value yet
|
||||
if order.VehicleSpecification.DestinationCountry != "" {
|
||||
_, err = db.GetCars().SetSetting(&common.CarSetting{
|
||||
VIN: vin,
|
||||
Name: common.DELIVERY_DESTINATION,
|
||||
Value: order.VehicleSpecification.DestinationCountry,
|
||||
Type: "string",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func changeRatePlan(db *services.DB, smsClient sms.SMSServiceClient, vin, destinationCountry string) error {
|
||||
car, err := services.GetDB().GetCars().SelectByVIN(vin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(car.ICCID) == 0 {
|
||||
return fmt.Errorf("no iccid found for vehicle %s", vin)
|
||||
}
|
||||
iccid := strings.TrimSuffix(strings.ToLower(car.ICCID), "f")
|
||||
|
||||
customAtributeReq := sms.CustomAtributesRequest{
|
||||
ICCID: iccid,
|
||||
AccountCustom1: destinationCountry,
|
||||
}
|
||||
_, err = smsClient.HandleCustomAttributes(context.Background(), &customAtributeReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ratePlan, err := db.GetRatePlan().Select(destinationCountry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
changeRatePlanRequest := sms.ChangeRatePlanRequest{
|
||||
ICCID: iccid,
|
||||
ProductId: ratePlan.ProductID,
|
||||
AccountId: tmobile.FISKER_TMOBILE_ACCOUNT_ID,
|
||||
}
|
||||
_, err = smsClient.HandleChangeRatePlan(context.Background(), &changeRatePlanRequest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go verifyRatePlan(smsClient, iccid, destinationCountry)
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifyRatePlan(smsClient sms.SMSServiceClient, iccid, destinationCountry string) error {
|
||||
deviceDetailsRequest := sms.DeviceDetailsRequest{
|
||||
ICCID: iccid,
|
||||
}
|
||||
|
||||
details, err := smsClient.HandleDeviceDetails(context.Background(), &deviceDetailsRequest)
|
||||
if err != nil {
|
||||
logger.Error().Msgf("failed to check device details for iccid %s", iccid)
|
||||
}
|
||||
|
||||
logger.Info().Msgf("device details for iccid %s: %+v", iccid, details)
|
||||
return nil
|
||||
}
|
||||
224
services/attendant/handlers/order_updated_test.go
Normal file
224
services/attendant/handlers/order_updated_test.go
Normal file
@@ -0,0 +1,224 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/handlers"
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
q "github.com/fiskerinc/cloud-services/pkg/db/queries"
|
||||
"github.com/fiskerinc/cloud-services/pkg/db/queries/mocks"
|
||||
"github.com/fiskerinc/cloud-services/pkg/grpc/sms"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis/tester"
|
||||
vconfig "github.com/fiskerinc/cloud-services/pkg/vehicleconfig"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
someErr = errors.New("some error")
|
||||
vinMock = "FISKER123"
|
||||
vodMock = "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
|
||||
confMock = "000000000000000000000000000000000000000"
|
||||
validOrder = common.VehicleOrder{
|
||||
SpecID: 800010200,
|
||||
OrderNumber: 8000102,
|
||||
MessageIdentifier: "VEHICLEORDERSUBMISSION",
|
||||
VehicleSpecification: common.VehicleSpecification{
|
||||
OrderIndicator: "S",
|
||||
FleetOrderIndicator: "N",
|
||||
ProductionPhaseIndicator: "01",
|
||||
VehicleIndicator: "000",
|
||||
ManufacturingPlant: "G",
|
||||
ExpectedReferenceDate: common.ExpectedReferenceDate{
|
||||
Time: time.Date(2022, 5, 26, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
ModelType: "FM29",
|
||||
ModelYearIndicator: 2023,
|
||||
VehicleModel: "F29",
|
||||
VinPrefix: "VCF1ZBU2_PG",
|
||||
VehicleFeatures: []common.FeatureCodes{
|
||||
{
|
||||
FamilyCode: "2801",
|
||||
FeatureCode: "280102",
|
||||
},
|
||||
{
|
||||
FamilyCode: "2804",
|
||||
FeatureCode: "280401",
|
||||
},
|
||||
{
|
||||
FamilyCode: "2805",
|
||||
FeatureCode: "280501",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
validUpdateManifest = common.UpdateManifest{
|
||||
ID: 1,
|
||||
CarUpdateID: 1,
|
||||
Version: fmt.Sprint(validOrder.OrderNumber),
|
||||
Description: fmt.Sprintf("configuration %s %s", vinMock, validOrder.MessageIdentifier),
|
||||
ManifestType: common.ConfigUpdateType,
|
||||
VOD: "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
|
||||
}
|
||||
validRespECUs = []*common.UpdateManifestECU{
|
||||
{
|
||||
UpdateManifestID: 1,
|
||||
ECU: "ICC",
|
||||
Configuration: confMock,
|
||||
},
|
||||
}
|
||||
smsMock = sms.NewSMSMockSuccess()
|
||||
mockCars = mocks.MockCars{}
|
||||
)
|
||||
|
||||
func TestOrderUpdated(t *testing.T) {
|
||||
handlers.ENABLE_ORDERUPDATE_SENDS = true
|
||||
validUpdateManifestResp := validUpdateManifest
|
||||
validUpdateManifestResp.ID = 1
|
||||
validUpdateManifestResp.ECUs = validRespECUs
|
||||
|
||||
scrubbedValidUpdateManifest := validUpdateManifestResp.ToUpdateConfigManifest()
|
||||
scrubbedValidUpdateManifest.Type = "standard"
|
||||
|
||||
successPayload, _ := json.Marshal(validOrder)
|
||||
redisMock := tester.NewRedisMock()
|
||||
services.SetRedisClientPool(tester.NewMockClientPool(redisMock))
|
||||
mockSap := vconfig.SAPServiceMock{GetConfigurationMock: func(vin string) (common.SAPResponse, error) {
|
||||
return common.SAPResponse{
|
||||
ModelYear: 2023,
|
||||
ModelType: "Ocean",
|
||||
VersionDuringModelYear: "1",
|
||||
Features: []common.SAPFeature{
|
||||
{
|
||||
FamilyCode: "FamilyCode1",
|
||||
FeatureCode: "FeatureCode1",
|
||||
},
|
||||
{
|
||||
FamilyCode: "FamilyCode2",
|
||||
FeatureCode: "FeatureCode2",
|
||||
},
|
||||
{
|
||||
FamilyCode: "VOD",
|
||||
FeatureCode: vodMock,
|
||||
},
|
||||
}}, nil
|
||||
}}
|
||||
services.SetSapService(mockSap)
|
||||
mockCars.SetLoadResp(&common.Car{
|
||||
VIN: vinMock,
|
||||
ICCID: "1234567890",
|
||||
SoldStatus: common.CarSoldStatusRetailed,
|
||||
})
|
||||
|
||||
tests := map[string]struct {
|
||||
updateManifest q.UpdateManifestsInterface
|
||||
cars q.CarsInterface
|
||||
carsUpdate q.CarUpdatesInterface
|
||||
ratePlan q.RatePlanInterface
|
||||
vConfig vconfig.ConfigServiceInterface
|
||||
payload []byte
|
||||
expRedisMsgs map[string]interface{}
|
||||
expErr error
|
||||
}{
|
||||
"success": {
|
||||
updateManifest: &mocks.MockUpdateManifests{SelectResponse: []common.UpdateManifest{{ID: 1234}}},
|
||||
cars: &mockCars,
|
||||
carsUpdate: &mocks.MockCarUpdates{},
|
||||
ratePlan: &mocks.MockRatePlan{},
|
||||
vConfig: vconfig.ConfigMock{GetVODCDSCodingDataMock: SuccessGetCDSMock},
|
||||
payload: successPayload,
|
||||
expRedisMsgs: map[string]interface{}{
|
||||
"2:" + vinMock: common.Message{
|
||||
Handler: "car_update",
|
||||
Data: common.CarUpdate{
|
||||
ID: 1,
|
||||
VIN: vinMock,
|
||||
UpdateManifestID: 1,
|
||||
UpdateManifest: &validUpdateManifestResp,
|
||||
},
|
||||
},
|
||||
"1:" + vinMock: common.Message{
|
||||
Handler: "config_update",
|
||||
Data: scrubbedValidUpdateManifest,
|
||||
},
|
||||
},
|
||||
expErr: nil,
|
||||
},
|
||||
"json_parse_err": {
|
||||
payload: []byte(`12`),
|
||||
expErr: errors.New("json: cannot unmarshal number into Go value of type common.VehicleOrder"),
|
||||
},
|
||||
"failed_cars_db": {
|
||||
updateManifest: &mocks.MockUpdateManifests{SelectResponse: []common.UpdateManifest{{ID: 1234}}},
|
||||
cars: &mocks.MockCars{
|
||||
DBMockHelper: mocks.DBMockHelper{
|
||||
Error: someErr,
|
||||
},
|
||||
},
|
||||
carsUpdate: &mocks.MockCarUpdates{},
|
||||
ratePlan: &mocks.MockRatePlan{},
|
||||
vConfig: vconfig.ConfigMock{GetVODCDSCodingDataMock: SuccessGetCDSMock},
|
||||
payload: successPayload,
|
||||
expErr: someErr,
|
||||
},
|
||||
"failed_cds": {
|
||||
updateManifest: &mocks.MockUpdateManifests{SelectResponse: []common.UpdateManifest{{ID: 1234}}},
|
||||
carsUpdate: &mocks.MockCarUpdates{},
|
||||
cars: &mockCars,
|
||||
ratePlan: &mocks.MockRatePlan{},
|
||||
vConfig: vconfig.ConfigMock{GetVODCDSCodingDataMock: FailedGetCDSMock},
|
||||
payload: successPayload,
|
||||
expErr: someErr,
|
||||
},
|
||||
"failed_db": {
|
||||
updateManifest: &mocks.MockUpdateManifests{
|
||||
DBMockHelper: mocks.DBMockHelper{
|
||||
Error: someErr,
|
||||
},
|
||||
},
|
||||
cars: &mockCars,
|
||||
carsUpdate: &mocks.MockCarUpdates{},
|
||||
ratePlan: &mocks.MockRatePlan{},
|
||||
vConfig: vconfig.ConfigMock{GetVODCDSCodingDataMock: SuccessGetCDSMock},
|
||||
payload: successPayload,
|
||||
expErr: someErr,
|
||||
},
|
||||
}
|
||||
|
||||
for tname, tt := range tests {
|
||||
t.Run(tname, func(t *testing.T) {
|
||||
redisMock.Reset()
|
||||
db := services.GetDB()
|
||||
db.SetManifests(tt.updateManifest)
|
||||
db.SetCars(tt.cars)
|
||||
db.SetCarUpdates(tt.carsUpdate)
|
||||
db.SetRatePlan(tt.ratePlan)
|
||||
services.SetVehicleConfig(tt.vConfig)
|
||||
err := handlers.OrderUpdated(db, &smsMock, vinMock, tt.payload)
|
||||
if err != nil && tt.expErr != nil {
|
||||
assert.Equal(t, tt.expErr.Error(), err.Error())
|
||||
return
|
||||
}
|
||||
assert.Equal(t, tt.expErr, err)
|
||||
// assert.Equal(t, tt.expRedisMsgs, redisMock.PublishedMessages)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func SuccessGetCDSMock(request common.VODCDSRequest) (map[string]string, error) {
|
||||
ecus := map[string]string{
|
||||
"VOD": vodMock,
|
||||
"ICC": confMock,
|
||||
}
|
||||
|
||||
return ecus, nil
|
||||
}
|
||||
func FailedGetCDSMock(request common.VODCDSRequest) (map[string]string, error) {
|
||||
return nil, someErr
|
||||
}
|
||||
24
services/attendant/handlers/send_manifest.go
Normal file
24
services/attendant/handlers/send_manifest.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/controllers"
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
)
|
||||
|
||||
var PrivateSeed int64 // Used only for testing. Do not change otherwise
|
||||
|
||||
func SendManifest(d *services.DB, ka *services.KeepAwake, device common.Device, id string, data []byte) error {
|
||||
logger.Debug().Msgf("SendManifest %v %s", device, id)
|
||||
|
||||
clientPool := services.RedisClientPool()
|
||||
|
||||
configService := services.GetVehicleConfig()
|
||||
|
||||
generator := controllers.NewManifestSender(clientPool, d, configService, device, ka, PrivateSeed)
|
||||
defer generator.Release()
|
||||
|
||||
return generator.Process(id, data)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
)
|
||||
|
||||
// If the update is not finished installing on the car, we send out an sms to wake the car up.
|
||||
// If this message is failed to deliver, we need to cancel the car update and set its status as failed
|
||||
func CarSendManifestSMSWakeUpCallback(d *services.DB, ka *services.KeepAwake, device common.Device, id string, data []byte) (err error) {
|
||||
logger.Info().Msgf("SMS delivered but not sending TBox manifest %v %s", device, id)
|
||||
return nil
|
||||
/*
|
||||
clientPool := services.RedisClientPool()
|
||||
|
||||
sap := services.GetSapService()
|
||||
configService := services.GetVehicleConfig()
|
||||
|
||||
generator := controllers.NewManifestSender(clientPool, d, sap, configService, device, ka, PrivateSeed)
|
||||
defer generator.Release()
|
||||
|
||||
return generator.ContinueTBOXSend(id, data) */
|
||||
}
|
||||
962
services/attendant/handlers/send_manifest_test.go
Normal file
962
services/attendant/handlers/send_manifest_test.go
Normal file
@@ -0,0 +1,962 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/handlers"
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"os"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/common/dbbasemodel"
|
||||
"github.com/fiskerinc/cloud-services/pkg/common/manifestfingerprintparams"
|
||||
dbm "github.com/fiskerinc/cloud-services/pkg/db/queries/mocks"
|
||||
"github.com/fiskerinc/cloud-services/pkg/grpc/sms"
|
||||
"github.com/fiskerinc/cloud-services/pkg/kafka"
|
||||
kafkaMock "github.com/fiskerinc/cloud-services/pkg/kafka/mock"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis"
|
||||
rm "github.com/fiskerinc/cloud-services/pkg/redis/tester"
|
||||
th "github.com/fiskerinc/cloud-services/pkg/testhelper"
|
||||
"github.com/fiskerinc/cloud-services/pkg/testrunner"
|
||||
"github.com/fiskerinc/cloud-services/pkg/utils/elptr"
|
||||
vconfig "github.com/fiskerinc/cloud-services/pkg/vehicleconfig"
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
|
||||
func TestSendManifest(t *testing.T) {
|
||||
os.Setenv("APP_SERVICE_NAME", "ATTENDANT")
|
||||
handlers.PrivateSeed = 123456789
|
||||
|
||||
ka := services.NewKeepAwakeService()
|
||||
ka.SetService(&services.MockKeepAwakeImplementation{})
|
||||
|
||||
now := time.Now()
|
||||
testVIN := "JH4KA7680RC01"
|
||||
tboxKey := common.TRex.Key(testVIN)
|
||||
hmiKey := common.HMI.Key(testVIN)
|
||||
|
||||
smsKey := "manifest_tbox_send_cache:100"
|
||||
|
||||
var bhex common.BinaryHex = []byte("test")
|
||||
redis.MockRedisConnection()
|
||||
falsePtrValue := elptr.ElPtr(false)
|
||||
truePtrValue := elptr.ElPtr(true)
|
||||
ecuaRollback := []*common.UpdateManifestECU{
|
||||
{
|
||||
ID: 100,
|
||||
UpdateManifestID: 200,
|
||||
ECU: "ECUA",
|
||||
Version: "VERSIONOLD",
|
||||
Mode: "A",
|
||||
DBModelBase: th.Timestamp,
|
||||
Files: []*common.UpdateManifestFile{
|
||||
{
|
||||
FileID: "FILEIDOLD",
|
||||
UpdateManifestECUID: 1001,
|
||||
Filename: "FILENAMEOLD",
|
||||
URL: "URLOLD",
|
||||
FileType: common.Software,
|
||||
WriteRegionID: 700,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 701,
|
||||
Length: 702,
|
||||
},
|
||||
FileSize: 240,
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
ecus := []*common.UpdateManifestECU{
|
||||
{
|
||||
ECU: "ICC",
|
||||
Version: "SWVERSION",
|
||||
HWVersions: []string{"HWVERSION"},
|
||||
Mode: "D",
|
||||
SelfDownload: true,
|
||||
InstallPriority: 13,
|
||||
Files: []*common.UpdateManifestFile{
|
||||
{
|
||||
FileID: "AAAAAAA",
|
||||
URL: "http://download.com/file1.bin",
|
||||
FileSize: 1000,
|
||||
Checksum: "AAAAAAA",
|
||||
WriteRegionID: 100,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 101,
|
||||
Length: 102,
|
||||
},
|
||||
FileType: common.Calibration,
|
||||
EraseRegionID: 200,
|
||||
EraseRegion: &common.MemoryRegion{
|
||||
Offset: 201,
|
||||
Length: 202,
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
{
|
||||
FileID: "SHOULD_NOT_BE_IN_UPDATE",
|
||||
URL: "http://download.com/SHOULD_NOT_BE_IN_UPDATE.bin",
|
||||
FileSize: 1000,
|
||||
Checksum: "AAAAAAA",
|
||||
WriteRegionID: 100,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 101,
|
||||
Length: 102,
|
||||
},
|
||||
FileType: common.Calibration,
|
||||
EraseRegionID: 200,
|
||||
EraseRegion: &common.MemoryRegion{
|
||||
Offset: 201,
|
||||
Length: 202,
|
||||
},
|
||||
Parsed: falsePtrValue,
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
{
|
||||
FileID: "MUST_BE_IN_UPDATE",
|
||||
URL: "http://download.com/MUST_BE_IN_UPDATE.bin",
|
||||
FileSize: 1000,
|
||||
Checksum: "AAAAAAA",
|
||||
WriteRegionID: 100,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 101,
|
||||
Length: 102,
|
||||
},
|
||||
FileType: common.Calibration,
|
||||
EraseRegionID: 200,
|
||||
EraseRegion: &common.MemoryRegion{
|
||||
Offset: 201,
|
||||
Length: 202,
|
||||
},
|
||||
Parsed: truePtrValue,
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ECU: "ECUD",
|
||||
Version: "SWVERSION",
|
||||
HWVersions: []string{"HWVERSION"},
|
||||
Mode: "D",
|
||||
InstallPriority: 4,
|
||||
Files: []*common.UpdateManifestFile{
|
||||
{
|
||||
FileID: "SHOULD_NOT_BE_IN_UPDATE",
|
||||
URL: "http://download.com/SHOULD_NOT_BE_IN_UPDATE.bin",
|
||||
FileSize: 1000,
|
||||
Checksum: "AAAAAAA",
|
||||
WriteRegionID: 100,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 101,
|
||||
Length: 102,
|
||||
},
|
||||
FileType: common.Calibration,
|
||||
EraseRegionID: 200,
|
||||
EraseRegion: &common.MemoryRegion{
|
||||
Offset: 201,
|
||||
Length: 202,
|
||||
},
|
||||
Parsed: falsePtrValue,
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
{
|
||||
FileID: "MUST_BE_IN_UPDATE",
|
||||
URL: "http://download.com/MUST_BE_IN_UPDATE.bin",
|
||||
FileSize: 1000,
|
||||
Checksum: "AAAAAAA",
|
||||
WriteRegionID: 100,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 101,
|
||||
Length: 102,
|
||||
},
|
||||
FileType: common.Calibration,
|
||||
EraseRegionID: 200,
|
||||
EraseRegion: &common.MemoryRegion{
|
||||
Offset: 201,
|
||||
Length: 202,
|
||||
},
|
||||
Parsed: truePtrValue,
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
{
|
||||
FileID: "BBBBBBB",
|
||||
URL: "http://download.com/file2.bin",
|
||||
FileSize: 2000,
|
||||
Checksum: "BBBBBBB",
|
||||
FileType: common.Calibration,
|
||||
WriteRegionID: 300,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 301,
|
||||
Length: 302,
|
||||
},
|
||||
EraseRegionID: 400,
|
||||
EraseRegion: &common.MemoryRegion{
|
||||
Offset: 401,
|
||||
Length: 402,
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
{
|
||||
ID: 100,
|
||||
UpdateManifestID: 200,
|
||||
ECU: "PDU",
|
||||
Version: "PDU-VERS",
|
||||
HWVersions: []string{"PDU-VERS"},
|
||||
Mode: "PDU",
|
||||
ConfigurationMask: "AAAAAAAA",
|
||||
InstallPriority: 7,
|
||||
Files: []*common.UpdateManifestFile{
|
||||
{
|
||||
FileID: "NOT_BE_IN_UPDATE",
|
||||
URL: "http://download.com/NOT_BE_IN_UPDATE.bin",
|
||||
FileSize: 1000,
|
||||
Checksum: "AAAAAAA",
|
||||
WriteRegionID: 100,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 101,
|
||||
Length: 102,
|
||||
},
|
||||
FileType: common.Calibration,
|
||||
EraseRegionID: 200,
|
||||
EraseRegion: &common.MemoryRegion{
|
||||
Offset: 201,
|
||||
Length: 202,
|
||||
},
|
||||
Parsed: falsePtrValue,
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
{
|
||||
FileID: "MUST_BE_IN_UPDATE",
|
||||
URL: "http://download.com/MUST_BE_IN_UPDATE.bin",
|
||||
FileSize: 1000,
|
||||
Checksum: "AAAAAAA",
|
||||
WriteRegionID: 100,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 101,
|
||||
Length: 102,
|
||||
},
|
||||
FileType: common.Calibration,
|
||||
EraseRegionID: 200,
|
||||
EraseRegion: &common.MemoryRegion{
|
||||
Offset: 201,
|
||||
Length: 202,
|
||||
},
|
||||
Parsed: truePtrValue,
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
{
|
||||
FileID: "AAAAAAAA",
|
||||
URL: "http://download.com/filea.bin",
|
||||
FileSize: 2000,
|
||||
Checksum: "AAAAAAAA",
|
||||
WriteRegionID: 500,
|
||||
FileType: common.Calibration,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 501,
|
||||
Length: 502,
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
{
|
||||
ID: 100,
|
||||
UpdateManifestID: 200,
|
||||
ECU: "ECUA",
|
||||
Version: "A-VERS",
|
||||
HWVersions: []string{"A-VERS"},
|
||||
Mode: "A",
|
||||
ConfigurationMask: "AAAAAAAA",
|
||||
InstallPriority: 1,
|
||||
Files: []*common.UpdateManifestFile{
|
||||
{
|
||||
FileID: "FILEID",
|
||||
UpdateManifestECUID: 100,
|
||||
Filename: "FILENAME",
|
||||
URL: "URL",
|
||||
FileType: common.Calibration,
|
||||
WriteRegionID: 600,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 601,
|
||||
Length: 602,
|
||||
},
|
||||
FileSize: 240,
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
}
|
||||
|
||||
fingerprint := getTodaysFingerprint()
|
||||
|
||||
standardManifest := common.UpdateManifest{
|
||||
ID: 100,
|
||||
CarUpdateID: 297,
|
||||
Name: "TEST",
|
||||
Version: "MANIFEST_VERSION",
|
||||
SUMS: "2023.10.01.00",
|
||||
Description: "TESTDESC",
|
||||
ReleaseNotes: "http://fiskerinc.com/release_notes",
|
||||
Type: common.ManifestTypeForced,
|
||||
Active: truePtrValue,
|
||||
Country: "US",
|
||||
PowerTrain: "MD23",
|
||||
Restraint: "None",
|
||||
Model: "Ocean",
|
||||
Trim: "Sport",
|
||||
Year: 2022,
|
||||
BodyType: "truck",
|
||||
RollbackEnabled: true,
|
||||
ECUs: ecus,
|
||||
UpdateDuration: 30,
|
||||
}
|
||||
|
||||
rollbackDisabledManifest := common.UpdateManifest{
|
||||
ID: 100,
|
||||
CarUpdateID: 297,
|
||||
Name: "TEST",
|
||||
Version: "MANIFEST_VERSION",
|
||||
SUMS: "2023.10.01.00.E",
|
||||
Description: "TESTDESC",
|
||||
ReleaseNotes: "http://fiskerinc.com/release_notes",
|
||||
Type: "standard",
|
||||
Active: truePtrValue,
|
||||
Country: "US",
|
||||
PowerTrain: "MD23",
|
||||
Restraint: "None",
|
||||
Model: "Ocean",
|
||||
Trim: "Sport",
|
||||
Year: 2022,
|
||||
BodyType: "truck",
|
||||
ECUs: ecus,
|
||||
UpdateDuration: 30,
|
||||
}
|
||||
standardManifestNoICC := common.UpdateManifest{
|
||||
ID: 100,
|
||||
CarUpdateID: 297,
|
||||
Name: "TEST",
|
||||
Version: "MANIFEST_VERSION",
|
||||
SUMS: "2023.10.01.00.E",
|
||||
Description: "TESTDESC",
|
||||
ReleaseNotes: "http://fiskerinc.com/release_notes",
|
||||
Type: "standard",
|
||||
Country: "US",
|
||||
PowerTrain: "MD23",
|
||||
Restraint: "None",
|
||||
Model: "Ocean",
|
||||
Trim: "Sport",
|
||||
Year: 2022,
|
||||
RollbackEnabled: true,
|
||||
BodyType: "truck",
|
||||
ECUs: []*common.UpdateManifestECU{
|
||||
{
|
||||
ECU: "ECUD",
|
||||
HWVersions: []string{"HWVERSION"},
|
||||
Version: "SWVERSION",
|
||||
Mode: "D",
|
||||
InstallPriority: 7,
|
||||
Files: []*common.UpdateManifestFile{
|
||||
{
|
||||
FileID: "BBBBBBB",
|
||||
URL: "http://download.com/file2.bin",
|
||||
FileSize: 2000,
|
||||
Checksum: "BBBBBBB",
|
||||
FileType: common.Calibration,
|
||||
WriteRegionID: 700,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 701,
|
||||
Length: 702,
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
{
|
||||
ID: 100,
|
||||
UpdateManifestID: 200,
|
||||
ECU: "PDU",
|
||||
Version: "PDU-VERS",
|
||||
HWVersions: []string{"PDU-VERS"},
|
||||
Mode: "PDU",
|
||||
ConfigurationMask: "AAAAAAAA",
|
||||
InstallPriority: 10,
|
||||
Files: []*common.UpdateManifestFile{
|
||||
{
|
||||
FileID: "AAAAAAAA",
|
||||
URL: "http://download.com/filea.bin",
|
||||
FileSize: 2000,
|
||||
FileType: common.Calibration,
|
||||
Checksum: "AAAAAAAA",
|
||||
WriteRegionID: 800,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 801,
|
||||
Length: 802,
|
||||
},
|
||||
EraseRegionID: 900,
|
||||
EraseRegion: &common.MemoryRegion{
|
||||
Offset: 901,
|
||||
Length: 902,
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
{
|
||||
ID: 100,
|
||||
UpdateManifestID: 200,
|
||||
ECU: "ECUA",
|
||||
Version: "A-VERS",
|
||||
HWVersions: []string{"A-VERS"},
|
||||
Mode: "A",
|
||||
ConfigurationMask: "AAAAAAAA",
|
||||
InstallPriority: 4,
|
||||
Files: []*common.UpdateManifestFile{
|
||||
{
|
||||
FileID: "FILEID",
|
||||
UpdateManifestECUID: 100,
|
||||
Filename: "FILENAME",
|
||||
URL: "URL",
|
||||
FileType: common.Calibration,
|
||||
WriteRegionID: 600,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 601,
|
||||
Length: 602,
|
||||
},
|
||||
FileSize: 240,
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
},
|
||||
UpdateDuration: 30,
|
||||
}
|
||||
mockCarUpdate := &common.CarUpdate{
|
||||
ID: 297,
|
||||
VIN: testVIN,
|
||||
UpdateManifestID: 100,
|
||||
}
|
||||
mockCarECUs := []common.CarECU{
|
||||
{ECU: "ECUD", HWVersion: "HWVERSION"},
|
||||
{ECU: "ECUA", HWVersion: "A-VERS", Version: "TEST122"},
|
||||
{ECU: "OBC", HWVersion: "PDU-VERS", Version: "TEST121"},
|
||||
{ECU: "BCM", HWVersion: ";#A;#"},
|
||||
{ECU: "ICC", HWVersion: "HWVERSION", Version: "TEST123"},
|
||||
}
|
||||
mockRedis := rm.MockRedis{}
|
||||
mockCUDB := dbm.MockCarUpdates{}
|
||||
mockManDB := dbm.MockUpdateManifests{}
|
||||
mockKeys := dbm.MockEccKeys{
|
||||
MockListResponse: []common.ECCKeys{
|
||||
{
|
||||
ECU: "PDU",
|
||||
PrivKey1: &bhex,
|
||||
PrivKey2: &bhex,
|
||||
PrivKey3: &bhex,
|
||||
PubKey1: &bhex,
|
||||
PubKey2: &bhex,
|
||||
PubKey3: &bhex,
|
||||
Env: "current",
|
||||
DBModelBase: dbbasemodel.DBModelBase{
|
||||
CreatedAt: &now,
|
||||
UpdatedAt: &now,
|
||||
},
|
||||
},
|
||||
{
|
||||
ECU: "ECUA",
|
||||
PrivKey1: &bhex,
|
||||
PrivKey2: &bhex,
|
||||
PrivKey3: &bhex,
|
||||
PubKey1: &bhex,
|
||||
PubKey2: &bhex,
|
||||
PubKey3: &bhex,
|
||||
Env: "current",
|
||||
DBModelBase: dbbasemodel.DBModelBase{
|
||||
CreatedAt: &now,
|
||||
UpdatedAt: &now,
|
||||
},
|
||||
},
|
||||
{
|
||||
ECU: "ECUD",
|
||||
PrivKey1: &bhex,
|
||||
PrivKey2: &bhex,
|
||||
PrivKey3: &bhex,
|
||||
PubKey1: &bhex,
|
||||
PubKey2: &bhex,
|
||||
PubKey3: &bhex,
|
||||
Env: "current",
|
||||
DBModelBase: dbbasemodel.DBModelBase{
|
||||
CreatedAt: &now,
|
||||
UpdatedAt: &now,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
services.GetDB().SetCarUpdates(&mockCUDB)
|
||||
services.GetDB().SetCars(&dbm.MockCars{SelectCarECUs: mockCarECUs, SelectResponse: &common.Car{ICCID: "8000000000000000000"}})
|
||||
services.GetDB().SetManifests(&mockManDB)
|
||||
services.GetDB().SetECCKeys(&mockKeys)
|
||||
services.SetRedisClientPool(rm.NewMockClientPool(&mockRedis))
|
||||
mockSap := vconfig.SAPServiceMock{GetConfigurationMock: func(vin string) (common.SAPResponse, error) {
|
||||
return common.SAPResponse{
|
||||
ModelYear: 2023,
|
||||
ModelType: "Ocean",
|
||||
VersionDuringModelYear: "1",
|
||||
Features: []common.SAPFeature{
|
||||
{
|
||||
FamilyCode: "FamilyCode1",
|
||||
FeatureCode: "FeatureCode1",
|
||||
},
|
||||
{
|
||||
FamilyCode: "FamilyCode2",
|
||||
FeatureCode: "FeatureCode2",
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}}
|
||||
mockConf := vconfig.ConfigMock{GetVODCDSCodingDataMock: func(request common.VODCDSRequest) (map[string]string, error) {
|
||||
return map[string]string{
|
||||
"EPS": "000147303031313632011D",
|
||||
"ESP": "000F47303031313632000001012301027600000101000002B0",
|
||||
"ECUA": "config",
|
||||
"VOD": "",
|
||||
"ADAS": "000147303031313632011D",
|
||||
}, nil
|
||||
}}
|
||||
mockSMS := &sms.SMSMock{}
|
||||
mockSMS.SetHandleSMSQueueResponse(&sms.SMSQueueResponse{
|
||||
SmsMsgID: "100",
|
||||
SentSuccessful: true,
|
||||
}, nil)
|
||||
|
||||
services.SetSapService(mockSap)
|
||||
services.SetVehicleConfig(mockConf)
|
||||
services.SetSmsClient(mockSMS)
|
||||
|
||||
mockKafkaProducer := kafkaMock.GetKafkaMock(nil)
|
||||
services.SetKafkaProducer(mockKafkaProducer)
|
||||
|
||||
clonedStandardManifest := common.UpdateManifest{}
|
||||
clonedStandardManifestNoICC := common.UpdateManifest{}
|
||||
err := copier.CopyWithOption(&clonedStandardManifest, &standardManifest, copier.Option{DeepCopy: true})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = copier.CopyWithOption(&clonedStandardManifestNoICC, &standardManifestNoICC, copier.Option{DeepCopy: true})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tests := []testrunner.TestCase{
|
||||
{
|
||||
Name: "Send manifest w Self Download",
|
||||
DBTestCase: &dbm.DBTestCase{
|
||||
MockLoadResponse: mockCarUpdate,
|
||||
SetupMockResponse: func() {
|
||||
mockCUDB.LoadManifest = &clonedStandardManifest
|
||||
mockManDB.ECUUpdatesMock = func(man *common.UpdateManifestECU, vin string) ([]*common.UpdateManifestECU, error) {
|
||||
if man.ECU == "ECUA" {
|
||||
return ecuaRollback, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
},
|
||||
},
|
||||
RedisTestCase: &rm.RedisTestCase{
|
||||
Device: common.Service,
|
||||
DeviceKey: kafka.OTAUpdateService,
|
||||
PayloadData: `{"car_update_id":297}`,
|
||||
ExpectedMessages: map[string]string{
|
||||
hmiKey: `{"handler":"update_manifest","data":{"name":"TEST","version":"MANIFEST_VERSION","description":"TESTDESC","release_notes":"http://fiskerinc.com/release_notes","ecu_updates":[{"name":"ECUA","version":"A-VERS","current_version":"TEST122","hw_version":"A-VERS","configuration_mask":"AAAAAAAA","files":[{"file_id":"FILEID","url":"URL","file_size":240,"type":"calibration","write_region":{"offset":601,"length":602}}]},{"name":"ECUD","version":"SWVERSION","hw_version":"HWVERSION","files":[{"file_id":"MUST_BE_IN_UPDATE","url":"http://download.com/MUST_BE_IN_UPDATE.bin","file_size":1000,"checksum":"AAAAAAA","type":"calibration","write_region":{"offset":101,"length":102},"erase_region":{"offset":201,"length":202}},{"file_id":"BBBBBBB","url":"http://download.com/file2.bin","file_size":2000,"checksum":"BBBBBBB","type":"calibration","write_region":{"offset":301,"length":302},"erase_region":{"offset":401,"length":402}}]},{"name":"OBC","version":"PDU-VERS","current_version":"TEST121","hw_version":"PDU-VERS","configuration_mask":"AAAAAAAA","files":[{"file_id":"MUST_BE_IN_UPDATE","url":"http://download.com/MUST_BE_IN_UPDATE.bin","file_size":1000,"checksum":"AAAAAAA","type":"calibration","write_region":{"offset":101,"length":102},"erase_region":{"offset":201,"length":202}},{"file_id":"AAAAAAAA","url":"http://download.com/filea.bin","file_size":2000,"checksum":"AAAAAAAA","type":"calibration","write_region":{"offset":501,"length":502}}]},{"name":"ICC","version":"SWVERSION","current_version":"TEST123","hw_version":"HWVERSION","self_download":true,"files":[{"file_id":"AAAAAAA","url":"http://download.com/file1.bin","file_size":1000,"checksum":"AAAAAAA","type":"calibration","write_region":{"offset":101,"length":102},"erase_region":{"offset":201,"length":202}},{"file_id":"MUST_BE_IN_UPDATE","url":"http://download.com/MUST_BE_IN_UPDATE.bin","file_size":1000,"checksum":"AAAAAAA","type":"calibration","write_region":{"offset":101,"length":102},"erase_region":{"offset":201,"length":202}}]}],"fingerprint":"` + fingerprint + `","car_update_id":297,"rollback":true,"type":"forced","vod":"01011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110100202310010011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001e","update_duration":30}}`,
|
||||
},
|
||||
ExpectedCaches: map[string]rm.ExpiringCacheResult{
|
||||
// carupdateKey: {
|
||||
// Value: `{"current_size":0,"ecu":"","errorcode":0,"file_size":0,"file_total":0,"id":297,"info":"ICC","installed":0,"status":"sent","total_files":0,"total_size":0}`,
|
||||
// Expires: expectedExpire,
|
||||
// },
|
||||
smsKey: {
|
||||
Value: `{"VIN":"JH4KA7680RC01","ManifestID":100,"Destination":"ICC"}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Send manifest w Self Download rollback disabled",
|
||||
DBTestCase: &dbm.DBTestCase{
|
||||
MockLoadResponse: mockCarUpdate,
|
||||
SetupMockResponse: func() {
|
||||
mockCUDB.LoadManifest = &rollbackDisabledManifest
|
||||
mockManDB.ECUUpdatesMock = func(man *common.UpdateManifestECU, vin string) ([]*common.UpdateManifestECU, error) {
|
||||
if man.ECU == "ECUA" {
|
||||
return ecuaRollback, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
},
|
||||
},
|
||||
RedisTestCase: &rm.RedisTestCase{
|
||||
Device: common.Service,
|
||||
DeviceKey: kafka.OTAUpdateService,
|
||||
PayloadData: `{"car_update_id":297}`,
|
||||
ExpectedMessages: map[string]string{
|
||||
hmiKey: `{"handler":"update_manifest","data":{"name":"TEST","version":"MANIFEST_VERSION","description":"TESTDESC","release_notes":"http://fiskerinc.com/release_notes","ecu_updates":[{"name":"ECUA","version":"A-VERS","current_version":"TEST122","hw_version":"A-VERS","configuration_mask":"AAAAAAAA","files":[{"file_id":"FILEID","url":"URL","file_size":240,"type":"calibration","write_region":{"offset":601,"length":602}}]},{"name":"ECUD","version":"SWVERSION","hw_version":"HWVERSION","files":[{"file_id":"MUST_BE_IN_UPDATE","url":"http://download.com/MUST_BE_IN_UPDATE.bin","file_size":1000,"checksum":"AAAAAAA","type":"calibration","write_region":{"offset":101,"length":102},"erase_region":{"offset":201,"length":202}},{"file_id":"BBBBBBB","url":"http://download.com/file2.bin","file_size":2000,"checksum":"BBBBBBB","type":"calibration","write_region":{"offset":301,"length":302},"erase_region":{"offset":401,"length":402}}]},{"name":"OBC","version":"PDU-VERS","current_version":"TEST121","hw_version":"PDU-VERS","configuration_mask":"AAAAAAAA","files":[{"file_id":"MUST_BE_IN_UPDATE","url":"http://download.com/MUST_BE_IN_UPDATE.bin","file_size":1000,"checksum":"AAAAAAA","type":"calibration","write_region":{"offset":101,"length":102},"erase_region":{"offset":201,"length":202}},{"file_id":"AAAAAAAA","url":"http://download.com/filea.bin","file_size":2000,"checksum":"AAAAAAAA","type":"calibration","write_region":{"offset":501,"length":502}}]},{"name":"ICC","version":"SWVERSION","current_version":"TEST123","hw_version":"HWVERSION","self_download":true,"files":[{"file_id":"AAAAAAA","url":"http://download.com/file1.bin","file_size":1000,"checksum":"AAAAAAA","type":"calibration","write_region":{"offset":101,"length":102},"erase_region":{"offset":201,"length":202}},{"file_id":"MUST_BE_IN_UPDATE","url":"http://download.com/MUST_BE_IN_UPDATE.bin","file_size":1000,"checksum":"AAAAAAA","type":"calibration","write_region":{"offset":101,"length":102},"erase_region":{"offset":201,"length":202}}]}],"fingerprint":"` + fingerprint + `","car_update_id":297,"rollback":false,"type":"standard","vod":"0101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111010020231001000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000ba","update_duration":30}}`,
|
||||
},
|
||||
ExpectedCaches: map[string]rm.ExpiringCacheResult{
|
||||
smsKey: {
|
||||
Value: `{"VIN":"JH4KA7680RC01","ManifestID":100,"Destination":"ICC"}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Bad message",
|
||||
RedisTestCase: &rm.RedisTestCase{
|
||||
Device: common.HMI,
|
||||
DeviceKey: testVIN,
|
||||
PayloadData: `{"car_update_id":`,
|
||||
ExpectedError: "unexpected end of JSON input",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Send manifest w No Self Download",
|
||||
DBTestCase: &dbm.DBTestCase{
|
||||
MockLoadResponse: mockCarUpdate,
|
||||
SetupMockResponse: func() {
|
||||
mockCUDB.LoadManifest = &clonedStandardManifestNoICC
|
||||
},
|
||||
},
|
||||
RedisTestCase: &rm.RedisTestCase{
|
||||
Device: common.Service,
|
||||
DeviceKey: kafka.OTAUpdateService,
|
||||
PayloadData: `{"car_update_id":297}`,
|
||||
ExpectedMessages: map[string]string{
|
||||
hmiKey: `{"handler":"update_manifest","data":{"name":"TEST","version":"MANIFEST_VERSION","description":"TESTDESC","release_notes":"http://fiskerinc.com/release_notes","ecu_updates":[{"name":"ECUA","version":"A-VERS","current_version":"TEST122","hw_version":"A-VERS","configuration_mask":"AAAAAAAA","files":[{"file_id":"FILEID","url":"URL","file_size":240,"type":"calibration","write_region":{"offset":601,"length":602}}]},{"name":"ECUD","version":"SWVERSION","hw_version":"HWVERSION","files":[{"file_id":"BBBBBBB","url":"http://download.com/file2.bin","file_size":2000,"checksum":"BBBBBBB","type":"calibration","write_region":{"offset":701,"length":702}}]},{"name":"OBC","version":"PDU-VERS","current_version":"TEST121","hw_version":"PDU-VERS","configuration_mask":"AAAAAAAA","files":[{"file_id":"AAAAAAAA","url":"http://download.com/filea.bin","file_size":2000,"checksum":"AAAAAAAA","type":"calibration","write_region":{"offset":801,"length":802},"erase_region":{"offset":901,"length":902}}]}],"fingerprint":"` + fingerprint + `","car_update_id":297,"rollback":true,"type":"standard","vod":"0101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111010020231001000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000ba","update_duration":30}}`,
|
||||
tboxKey: `{"handler":"update_manifest","data":{"ecu_updates":[{"name":"ECUA","version":"A-VERS","current_version":"TEST122","hw_version":"A-VERS","configuration_mask":"AAAAAAAA","configuration":"config","files":[{"file_id":"FILEID","url":"URL","file_size":240,"type":"calibration","write_region":{"offset":601,"length":602}}],"rollback":[{"version":"VERSIONOLD","files":[{"file_id":"FILEIDOLD","url":"URLOLD","file_size":240,"type":"software","write_region":{"offset":701,"length":702}}]}],"ecc_keys":{"level_1":"74657374","level_2":"74657374","level_3":"74657374"}},{"name":"ECUD","version":"SWVERSION","hw_version":"HWVERSION","files":[{"file_id":"BBBBBBB","url":"http://download.com/file2.bin","file_size":2000,"checksum":"BBBBBBB","type":"calibration","write_region":{"offset":701,"length":702}}],"ecc_keys":{"level_1":"74657374","level_2":"74657374","level_3":"74657374"}},{"name":"OBC","version":"PDU-VERS","current_version":"TEST121","hw_version":"PDU-VERS","configuration_mask":"AAAAAAAA","files":[{"file_id":"AAAAAAAA","url":"http://download.com/filea.bin","file_size":2000,"checksum":"AAAAAAAA","type":"calibration","write_region":{"offset":801,"length":802},"erase_region":{"offset":901,"length":902}}],"ecc_keys":{"level_1":"74657374","level_2":"74657374","level_3":"74657374"}}],"fingerprint":"` + fingerprint + `","car_update_id":297,"rollback":true,"type":"standard","vod":"0101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111010020231001000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000ba","update_duration":30}}`,
|
||||
},
|
||||
ExpectedCaches: map[string]rm.ExpiringCacheResult{
|
||||
"manifest_tbox_send_cache:UQIDEPFQUH": {
|
||||
Value: `{"VIN":"JH4KA7680RC01","ManifestID":0,"Destination":"ICC/TBOX"}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schemaTesterHMI := th.NewSchemaTestHelper(t, schemaToHMI)
|
||||
schemaTesterTRex := th.NewSchemaTestHelper(t, schemaToTRex)
|
||||
|
||||
for _, test := range tests {
|
||||
mockRedis.Reset()
|
||||
for _, ecu := range ecus {
|
||||
ecu.Rollback = nil
|
||||
}
|
||||
|
||||
if test.DBTestCase != nil {
|
||||
test.DBTestCase.SetupDB(&mockCUDB)
|
||||
}
|
||||
if test.RedisTestCase != nil {
|
||||
test.RedisTestCase.SetupRedis(&mockRedis)
|
||||
|
||||
err := handlers.SendManifest(services.GetDB(), ka, test.RedisTestCase.Device, test.RedisTestCase.DeviceKey, []byte(test.RedisTestCase.PayloadData))
|
||||
|
||||
test.RedisTestCase.CheckHandlerError(t, test.Name, err)
|
||||
test.RedisTestCase.Validate(t, test.Name, &mockRedis)
|
||||
}
|
||||
|
||||
if test.DBTestCase != nil {
|
||||
test.DBTestCase.Validate(t, test.Name, &mockCUDB)
|
||||
}
|
||||
|
||||
for key, m := range test.RedisTestCase.ExpectedMessages {
|
||||
name := fmt.Sprintf("%s %s", test.Name, key)
|
||||
if strings.Contains(key, "2:") {
|
||||
schemaTesterHMI.ValidateSchemaObject(name, []byte(m))
|
||||
continue
|
||||
}
|
||||
|
||||
schemaTesterTRex.ValidateSchemaObject(name, []byte(m))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendManifestMultiFile(t *testing.T) {
|
||||
os.Setenv("APP_SERVICE_NAME", "ATTENDANT")
|
||||
testVIN := "JH4KA7680RC01"
|
||||
now := time.Now()
|
||||
hmiKey := common.HMI.Key(testVIN)
|
||||
falsePtrValue := elptr.ElPtr(false)
|
||||
truePtrValue := elptr.ElPtr(true)
|
||||
var bhex common.BinaryHex = []byte("test")
|
||||
redis.MockRedisConnection()
|
||||
ka := services.NewKeepAwakeService()
|
||||
ka.SetService(&services.MockKeepAwakeImplementation{})
|
||||
|
||||
ecus := []*common.UpdateManifestECU{
|
||||
{
|
||||
ECU: "BCM",
|
||||
Version: "DB22121A",
|
||||
HWVersions: []string{";#A;#"},
|
||||
Mode: "D",
|
||||
SelfDownload: true,
|
||||
Files: []*common.UpdateManifestFile{
|
||||
{
|
||||
FileID: "ShouldNotSee",
|
||||
Filename: "notparsed.s19",
|
||||
URL: "fakeurl.com",
|
||||
Checksum: "shouldnotsee",
|
||||
Parsed: falsePtrValue,
|
||||
},
|
||||
{
|
||||
FileID: "3ee5fd6bc9402d67",
|
||||
Filename: "MAGNA_BCM_FBL_driver.s19_0.bin",
|
||||
URL: "https://upload-dev.fiskerdps.com/4466d78a-50e1-4f1d-a4b8-5f78076758ed/MAGNA_BCM_FBL_driver.s19_0.bin",
|
||||
FileSize: 1000,
|
||||
Checksum: "shouldsee",
|
||||
WriteRegionID: 100,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 101,
|
||||
Length: 102,
|
||||
},
|
||||
FileType: common.Bootloader,
|
||||
EraseRegionID: 200,
|
||||
EraseRegion: &common.MemoryRegion{
|
||||
Offset: 201,
|
||||
Length: 202,
|
||||
},
|
||||
DBModelBase: th.Timestamp,
|
||||
Parsed: truePtrValue,
|
||||
},
|
||||
{
|
||||
FileID: "7878ede9c9407779",
|
||||
Filename: "FM29_Application_FR40_220111.s19_0.bin",
|
||||
URL: "ttps://upload-dev.fiskerdps.com/b5c3c8c8-86cd-422e-aa11-a248697edfa3/FM29_Application_FR40_220111.s19_0.bin",
|
||||
FileSize: 1000,
|
||||
Checksum: "SHOULD NOT SEE",
|
||||
WriteRegionID: 100,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 101,
|
||||
Length: 102,
|
||||
},
|
||||
FileType: common.Software,
|
||||
EraseRegionID: 200,
|
||||
EraseRegion: &common.MemoryRegion{
|
||||
Offset: 201,
|
||||
Length: 202,
|
||||
},
|
||||
Parsed: truePtrValue,
|
||||
Signature: "ShouldNOtSee",
|
||||
DBModelBase: th.Timestamp,
|
||||
},
|
||||
{
|
||||
FileID: "7bb5083dc9407ae9",
|
||||
Filename: "FM29_Application_FR40_220111.s19_1.bin",
|
||||
URL: "https://upload-dev.fiskerdps.com/2cdeb566-cb00-42cd-93a8-69769b19269a/FM29_Application_FR40_220111.s19_1.bin",
|
||||
FileSize: 1000,
|
||||
Checksum: "shantsee",
|
||||
WriteRegionID: 100,
|
||||
WriteRegion: common.MemoryRegion{
|
||||
Offset: 101,
|
||||
Length: 102,
|
||||
},
|
||||
FileType: common.Software,
|
||||
EraseRegionID: 200,
|
||||
EraseRegion: &common.MemoryRegion{
|
||||
Offset: 201,
|
||||
Length: 202,
|
||||
},
|
||||
Parsed: truePtrValue,
|
||||
DBModelBase: th.Timestamp,
|
||||
Signature: "SHOULD NOT SEE",
|
||||
},
|
||||
{
|
||||
FileID: "7ebb4fadc9409b91",
|
||||
Filename: "FM29_Application_FR40_220111.s19_2.bin",
|
||||
URL: "https://upload-dev.fiskerdps.com/ec9f8a84-61fb-4a9b-9735-ac6f91b07a83/FM29_Application_FR40_220111.s19_2.bin",
|
||||
FileType: common.Software,
|
||||
Parsed: truePtrValue,
|
||||
Signature: "SomeSignatureYouShouldSee",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
fingerprint := getTodaysFingerprint()
|
||||
|
||||
standardManifest := common.UpdateManifest{
|
||||
ID: 100,
|
||||
CarUpdateID: 297,
|
||||
Name: "TEST",
|
||||
Version: "MANIFEST_VERSION",
|
||||
SUMS: "2023.10.01.00",
|
||||
Description: "TESTDESC",
|
||||
ReleaseNotes: "http://fiskerinc.com/release_notes",
|
||||
Type: "standard",
|
||||
Active: truePtrValue,
|
||||
Country: "US",
|
||||
PowerTrain: "MD23",
|
||||
Restraint: "None",
|
||||
Model: "Ocean",
|
||||
Trim: "Sport",
|
||||
Year: 2022,
|
||||
BodyType: "truck",
|
||||
RollbackEnabled: false,
|
||||
ECUs: ecus,
|
||||
UpdateDuration: 30,
|
||||
}
|
||||
|
||||
mockCarUpdate := &common.CarUpdate{
|
||||
ID: 297,
|
||||
VIN: testVIN,
|
||||
UpdateManifestID: 100,
|
||||
}
|
||||
mockCarECUs := []common.CarECU{
|
||||
{ECU: "ECUD", HWVersion: "HWVERSION"},
|
||||
{ECU: "ECUA", HWVersion: "A-VERS"},
|
||||
{ECU: "OBC", HWVersion: "PDU-VERS"},
|
||||
{ECU: "BCM", HWVersion: ";#A;#"},
|
||||
{ECU: "ICC", HWVersion: "HWVERSION"},
|
||||
}
|
||||
mockRedis := rm.MockRedis{}
|
||||
mockCUDB := dbm.MockCarUpdates{}
|
||||
mockManDB := dbm.MockUpdateManifests{}
|
||||
mockKeys := dbm.MockEccKeys{
|
||||
MockListResponse: []common.ECCKeys{
|
||||
{
|
||||
ECU: "BCM",
|
||||
PrivKey1: &bhex,
|
||||
PrivKey2: &bhex,
|
||||
PrivKey3: &bhex,
|
||||
PubKey1: &bhex,
|
||||
PubKey2: &bhex,
|
||||
PubKey3: &bhex,
|
||||
Env: "current",
|
||||
DBModelBase: dbbasemodel.DBModelBase{
|
||||
CreatedAt: &now,
|
||||
UpdatedAt: &now,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
services.GetDB().SetCarUpdates(&mockCUDB)
|
||||
services.GetDB().SetCars(&dbm.MockCars{SelectCarECUs: mockCarECUs, SelectResponse: &common.Car{ICCID: ""}})
|
||||
services.GetDB().SetManifests(&mockManDB)
|
||||
services.GetDB().SetECCKeys(&mockKeys)
|
||||
services.SetRedisClientPool(rm.NewMockClientPool(&mockRedis))
|
||||
|
||||
mockSap := vconfig.SAPServiceMock{GetConfigurationMock: func(vin string) (common.SAPResponse, error) {
|
||||
return common.SAPResponse{
|
||||
ModelYear: 2023,
|
||||
ModelType: "Ocean",
|
||||
VersionDuringModelYear: "1",
|
||||
Features: []common.SAPFeature{
|
||||
{
|
||||
FamilyCode: "FamilyCode1",
|
||||
FeatureCode: "FeatureCode1",
|
||||
},
|
||||
{
|
||||
FamilyCode: "FamilyCode2",
|
||||
FeatureCode: "FeatureCode2",
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}}
|
||||
mockConf := vconfig.ConfigMock{GetVODCDSCodingDataMock: func(request common.VODCDSRequest) (map[string]string, error) {
|
||||
return map[string]string{
|
||||
"ECUA": "config",
|
||||
"VOD": "",
|
||||
}, nil
|
||||
}}
|
||||
mockSMS := &sms.SMSMock{}
|
||||
mockSMS.SetHandleSMSQueueResponse(&sms.SMSQueueResponse{
|
||||
SmsMsgID: "100",
|
||||
SentSuccessful: true,
|
||||
}, nil)
|
||||
services.SetSmsClient(mockSMS)
|
||||
services.SetSapService(mockSap)
|
||||
services.SetVehicleConfig(mockConf)
|
||||
smsKey := "manifest_tbox_send_cache:100"
|
||||
tests := []testrunner.TestCase{
|
||||
{
|
||||
Name: "MultiFile right order",
|
||||
DBTestCase: &dbm.DBTestCase{
|
||||
MockLoadResponse: mockCarUpdate,
|
||||
SetupMockResponse: func() {
|
||||
mockCUDB.LoadManifest = &standardManifest
|
||||
mockManDB.ECUUpdatesMock = func(man *common.UpdateManifestECU, vin string) ([]*common.UpdateManifestECU, error) {
|
||||
if man.ECU == "ECUA" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
},
|
||||
},
|
||||
RedisTestCase: &rm.RedisTestCase{
|
||||
Device: common.Service,
|
||||
DeviceKey: kafka.OTAUpdateService,
|
||||
PayloadData: `{"car_update_id":297}`,
|
||||
ExpectedMessages: map[string]string{
|
||||
hmiKey: `{"handler":"update_manifest","data":{"name":"TEST","version":"MANIFEST_VERSION","description":"TESTDESC","release_notes":"http://fiskerinc.com/release_notes","ecu_updates":[{"name":"BCM","version":"DB22121A","hw_version":";#A;#","self_download":true,"files":[{"file_id":"3ee5fd6bc9402d67","url":"https://upload-dev.fiskerdps.com/4466d78a-50e1-4f1d-a4b8-5f78076758ed/MAGNA_BCM_FBL_driver.s19_0.bin","file_size":1000,"checksum":"shouldsee","type":"bootloader","write_region":{"offset":101,"length":102},"erase_region":{"offset":201,"length":202}},{"file_id":"7878ede9c9407779","url":"ttps://upload-dev.fiskerdps.com/b5c3c8c8-86cd-422e-aa11-a248697edfa3/FM29_Application_FR40_220111.s19_0.bin","file_size":1000,"type":"software","write_region":{"offset":101,"length":102},"erase_region":{"offset":201,"length":202}},{"file_id":"7bb5083dc9407ae9","url":"https://upload-dev.fiskerdps.com/2cdeb566-cb00-42cd-93a8-69769b19269a/FM29_Application_FR40_220111.s19_1.bin","file_size":1000,"type":"software","write_region":{"offset":101,"length":102},"erase_region":{"offset":201,"length":202}},{"file_id":"7ebb4fadc9409b91","url":"https://upload-dev.fiskerdps.com/ec9f8a84-61fb-4a9b-9735-ac6f91b07a83/FM29_Application_FR40_220111.s19_2.bin","type":"software","write_region":{"offset":0,"length":0},"signature":"SomeSignatureYouShouldSee"}]}],"fingerprint":"` + fingerprint + `","car_update_id":297,"rollback":false,"type":"standard","vod":"01011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110100202310010011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100001e","update_duration":30}}`,
|
||||
},
|
||||
ExpectedCaches: map[string]rm.ExpiringCacheResult{smsKey: {
|
||||
Value: `{"VIN":"JH4KA7680RC01","ManifestID":100,"Destination":"ICC"}`,
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
mockRedis.Reset()
|
||||
for _, ecu := range ecus {
|
||||
ecu.Rollback = nil
|
||||
}
|
||||
|
||||
if test.DBTestCase != nil {
|
||||
test.DBTestCase.SetupDB(&mockCUDB)
|
||||
}
|
||||
if test.RedisTestCase != nil {
|
||||
test.RedisTestCase.SetupRedis(&mockRedis)
|
||||
|
||||
err := handlers.SendManifest(services.GetDB(), ka, test.RedisTestCase.Device, test.RedisTestCase.DeviceKey, []byte(test.RedisTestCase.PayloadData))
|
||||
|
||||
test.RedisTestCase.CheckHandlerError(t, test.Name, err)
|
||||
test.RedisTestCase.Validate(t, test.Name, &mockRedis)
|
||||
}
|
||||
|
||||
if test.DBTestCase != nil {
|
||||
test.DBTestCase.Validate(t, test.Name, &mockCUDB)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendManifestIntegration(t *testing.T) {
|
||||
os.Setenv("APP_SERVICE_NAME", "ATTENDANT")
|
||||
ka := services.NewKeepAwakeService()
|
||||
ka.SetService(&services.MockKeepAwakeImplementation{})
|
||||
err := handlers.SendManifest(services.GetDB(), ka, common.Service, "", []byte(`{"car_update_id":297}`))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func getTodaysFingerprint() string {
|
||||
// generate today's fingerprint
|
||||
fpparams := manifestfingerprintparams.GetFPParams()
|
||||
var fm = common.UpdateManifest{}
|
||||
fm.GenerateFingerprint(fpparams.CurTime(), fpparams.ManifestSerial())
|
||||
return fm.Fingerprint
|
||||
}
|
||||
55
services/attendant/handlers/update_approve.go
Normal file
55
services/attendant/handlers/update_approve.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// UpdateData extracts update ID from byte slice
|
||||
type UpdateData struct {
|
||||
ID int `json:"id"`
|
||||
}
|
||||
|
||||
// ApproveUpdate updates DB update field and
|
||||
//
|
||||
// sends redis message to vehicle to initialize download
|
||||
func ApproveUpdate(db *services.DB, id string, data []byte) error {
|
||||
logger.Debug().Msgf("ApproveUpdate %s", id)
|
||||
|
||||
client := services.RedisClientPool().GetFromPool()
|
||||
defer client.Close()
|
||||
|
||||
// TODO: NEEDS VALIDATION THAT INCOMING ID CAN APPROVE
|
||||
// CAN COME FROM MOBILE OR HMI - NEEDS TO HANDLE BOTH CASES
|
||||
|
||||
var u UpdateData
|
||||
err := json.Unmarshal(data, &u)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
update, err := db.ModifyUpdateStatus(u.ID, "approved")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Debug().Msgf("Sending redis queue- %s, key- %s, hander- %s, data- %v", "attendant", update.VIN, "update_download", u)
|
||||
|
||||
err = client.SafeQueueMessage(
|
||||
common.TRex.Key(update.VIN),
|
||||
common.Message{
|
||||
Handler: "update_download",
|
||||
Data: u,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
28
services/attendant/handlers/update_approve_test.go
Normal file
28
services/attendant/handlers/update_approve_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/handlers"
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis/tester"
|
||||
"github.com/fiskerinc/cloud-services/pkg/testhelper"
|
||||
)
|
||||
|
||||
func TestApproveUpdate(t *testing.T) {
|
||||
mockRedis := &tester.MockRedis{}
|
||||
services.SetRedisClientPool(tester.NewMockClientPool(mockRedis))
|
||||
|
||||
data := []byte(`{"id": 1}`)
|
||||
|
||||
err := handlers.ApproveUpdate(mockDB, "FISKER123", data)
|
||||
if err != nil {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "ApproveUpdate", "no error", err)
|
||||
}
|
||||
|
||||
err = handlers.ApproveUpdate(mockDB, "FISKER123", nil)
|
||||
if err == nil {
|
||||
t.Errorf(testhelper.TestErrorTemplate, "ApproveUpdate", "error", err)
|
||||
}
|
||||
}
|
||||
70
services/attendant/handlers/updates_get.go
Normal file
70
services/attendant/handlers/updates_get.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/cache"
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
s "github.com/fiskerinc/cloud-services/pkg/common/carupdatestatus"
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
"github.com/fiskerinc/cloud-services/pkg/validator"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// VehicleData extracts VIN from byte slice
|
||||
type VehicleData struct {
|
||||
VIN string `json:"vin" validate:"required,vin"`
|
||||
}
|
||||
|
||||
// GetUpdates queries DB for updates based off VIN and
|
||||
//
|
||||
// sends redis message back to requester
|
||||
func GetUpdates(db *services.DB, id string, data []byte) error {
|
||||
clientPool := services.RedisClientPool()
|
||||
|
||||
var v VehicleData
|
||||
err := json.Unmarshal(data, &v)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
err = validator.ValidateStruct(&v)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
ok, err := cache.VerifyCarToDriver(clientPool, db.GetCars(), v.VIN, id)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !ok {
|
||||
return cache.ErrInvalidCarToDriverAssociation(v.VIN, id)
|
||||
}
|
||||
|
||||
cu := common.CarUpdate{
|
||||
VIN: v.VIN,
|
||||
Status: s.InstallApprovalAwait,
|
||||
}
|
||||
updates, err := db.GetCarUpdates().Select(&cu, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result := make([]common.ApprovalUpdate, len(updates))
|
||||
for i := range updates {
|
||||
result[i] = common.NewApprovalUpdates(&updates[i])
|
||||
}
|
||||
|
||||
client := clientPool.GetFromPool()
|
||||
defer client.Close()
|
||||
logger.Debug().Msgf("Sending redis queue- %s, key- %s, hander- %s, data- %v", "attendant", id, "updates", result)
|
||||
return client.SafeQueueMessage(
|
||||
common.Mobile.Key(id),
|
||||
common.Message{
|
||||
Handler: "updates",
|
||||
Data: result,
|
||||
},
|
||||
)
|
||||
}
|
||||
148
services/attendant/handlers/updates_get_test.go
Normal file
148
services/attendant/handlers/updates_get_test.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/handlers"
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/common"
|
||||
s "github.com/fiskerinc/cloud-services/pkg/common/carupdatestatus"
|
||||
"github.com/fiskerinc/cloud-services/pkg/common/dbbasemodel"
|
||||
"github.com/fiskerinc/cloud-services/pkg/db/queries/mocks"
|
||||
"github.com/fiskerinc/cloud-services/pkg/redis/tester"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestUpdatesGet(t *testing.T) {
|
||||
mockRedis := &tester.MockRedis{}
|
||||
services.SetRedisClientPool(tester.NewMockClientPool(mockRedis))
|
||||
mockCars := &mocks.MockCars{}
|
||||
mockCarUpdates := &mocks.MockCarUpdates{}
|
||||
mockDB = &services.DB{}
|
||||
mockDB.SetCars(mockCars)
|
||||
mockDB.SetCarUpdates(mockCarUpdates)
|
||||
|
||||
cognitoID := "valid-cognito-id-1"
|
||||
mobileKey := common.Mobile.Key(cognitoID)
|
||||
vin := "JM1BG2241R0797923"
|
||||
data := fmt.Sprintf(`{"vin":"%s"}`, vin)
|
||||
now := time.Now()
|
||||
selectList := []common.CarUpdate{
|
||||
{
|
||||
ID: 1234,
|
||||
VIN: vin,
|
||||
UpdateManifestID: 4321,
|
||||
Status: s.InstallApprovalAwait,
|
||||
UpdateManifest: &common.UpdateManifest{
|
||||
Name: "TEST",
|
||||
Description: "TEST",
|
||||
ReleaseNotes: "http://releasenotes.com",
|
||||
Country: "US",
|
||||
PowerTrain: "MD23",
|
||||
Restraint: "None",
|
||||
Model: "Ocean",
|
||||
Trim: "Sport",
|
||||
Year: 2022,
|
||||
BodyType: "truck",
|
||||
ECUs: []*common.UpdateManifestECU{
|
||||
{
|
||||
ECU: "ADAS",
|
||||
Version: "VERSION",
|
||||
Mode: "A",
|
||||
},
|
||||
},
|
||||
DBModelBase: dbbasemodel.DBModelBase{
|
||||
CreatedAt: &now,
|
||||
UpdatedAt: &now,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
carToDrivers := []common.CarToDriver{
|
||||
{
|
||||
ID: 2000,
|
||||
VIN: vin,
|
||||
DriverID: cognitoID,
|
||||
},
|
||||
}
|
||||
|
||||
tests := []AttendentRouteTestCase{
|
||||
{
|
||||
Name: "No data",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.Mobile,
|
||||
DeviceKey: cognitoID,
|
||||
PayloadData: "",
|
||||
ExpectedError: "unexpected end of JSON input",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Bad request",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.Mobile,
|
||||
DeviceKey: cognitoID,
|
||||
PayloadData: "{}",
|
||||
ExpectedError: "Key: 'VehicleData.VIN' Error:Field validation for 'VIN' failed on the 'required' tag",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Bad association",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.Mobile,
|
||||
DeviceKey: cognitoID,
|
||||
PayloadData: data,
|
||||
ExpectedError: "no relationship found between vin JM1BG2241R0797923 and driver valid-cognito-id-1",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Cache error",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.Mobile,
|
||||
DeviceKey: cognitoID,
|
||||
PayloadData: data,
|
||||
ExpectedError: "cache error",
|
||||
},
|
||||
CarToDriversError: errors.New("cache error"),
|
||||
},
|
||||
{
|
||||
Name: "Good request",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.Mobile,
|
||||
DeviceKey: cognitoID,
|
||||
PayloadData: data,
|
||||
ExpectedMessages: map[string]string{
|
||||
mobileKey: `{"handler":"updates","data":[{"id":1234,"vin":"JM1BG2241R0797923","name":"TEST","description":"TEST","release_notes":"http://releasenotes.com"}]}`,
|
||||
},
|
||||
},
|
||||
SelectCarToDrivers: carToDrivers,
|
||||
SelectCarUpdates: selectList,
|
||||
},
|
||||
{
|
||||
Name: "DB error",
|
||||
RedisTestCase: tester.RedisTestCase{
|
||||
Device: common.Mobile,
|
||||
DeviceKey: cognitoID,
|
||||
PayloadData: data,
|
||||
ExpectedError: "database error",
|
||||
},
|
||||
SelectCarToDrivers: carToDrivers,
|
||||
SelectCarUpdates: nil,
|
||||
CarUpdateError: errors.New("database error"),
|
||||
},
|
||||
}
|
||||
|
||||
for i := range tests {
|
||||
mockRedis.Reset()
|
||||
test := &tests[i]
|
||||
test.SetupRedis(mockRedis)
|
||||
test.SetupDB(mockCars, mockCarUpdates, test)
|
||||
|
||||
err := handlers.GetUpdates(mockDB, test.DeviceKey, []byte(test.PayloadData))
|
||||
|
||||
test.CheckHandlerError(t, test.Name, err)
|
||||
test.Validate(t, test.Name, mockRedis)
|
||||
}
|
||||
}
|
||||
45
services/attendant/handlers/upload_dtc.go
Normal file
45
services/attendant/handlers/upload_dtc.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/controllers"
|
||||
"github.com/fiskerinc/cloud-services/services/attendant/services"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/logger"
|
||||
"github.com/fiskerinc/cloud-services/pkg/mongo"
|
||||
"github.com/fiskerinc/cloud-services/pkg/validator"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func UploadDtc(id string, data []byte) error {
|
||||
// ID is a vin in this case
|
||||
logger.Debug().Msgf("Upload DTC for %s", id)
|
||||
var DTCEntry controllers.DTCEntry
|
||||
DTCEntry.VIN = id
|
||||
|
||||
err := json.Unmarshal(data, &DTCEntry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = validator.GetValidator().Struct(&DTCEntry); err != nil {
|
||||
return errors.WithMessage(err, "failed structure validation")
|
||||
}
|
||||
|
||||
err = DTCEntry.ParseSnapshot()
|
||||
if err != nil {
|
||||
logger.Warn().Msg(err.Error())
|
||||
return err
|
||||
}
|
||||
client, err := services.GetMongoClient()
|
||||
if err != nil {
|
||||
logger.Warn().Str("id", id).Err(err).Send()
|
||||
return err
|
||||
}
|
||||
dtcs := mongo.NewCollection(client.Collection("dtcs"))
|
||||
DTCEntry.CreatedAt = time.Now()
|
||||
_, err = dtcs.InsertOne(DTCEntry)
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user