109 lines
4.2 KiB
Go
109 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/DATA-DOG/go-sqlmock"
|
|
)
|
|
|
|
func expectSnapshot(mock sqlmock.Sqlmock, notified bool) {
|
|
mock.ExpectBegin()
|
|
mock.ExpectQuery(`SELECT \* FROM vehicle_alert_event`).WillReturnRows(sqlmock.NewRows([]string{"id", "rule_name", "status"}).AddRow("false-event", "车辆原生告警", "unprocessed").AddRow("real-event", "车辆原生告警", "processing"))
|
|
payload := func(flag string) string {
|
|
data := map[string]any{"gb32960.alarm.max_alarm_level": "0", "gb32960.alarm.general_alarm_flag": flag}
|
|
for _, key := range []string{"battery_faults", "motor_faults", "engine_faults", "other_faults"} {
|
|
data["gb32960.alarm."+key] = []string{}
|
|
}
|
|
b, _ := json.Marshal(data)
|
|
return string(b)
|
|
}
|
|
mock.ExpectQuery(`SELECT n.\* FROM vehicle_native_alarm_evidence`).WillReturnRows(sqlmock.NewRows([]string{"event_id", "fields_json"}).AddRow("false-event", payload("0x00300000")).AddRow("real-event", payload("0x00380800")))
|
|
mock.ExpectQuery(`SELECT a.\* FROM vehicle_alert_event_action`).WillReturnRows(sqlmock.NewRows([]string{"event_id", "action"}).AddRow("false-event", "trigger"))
|
|
mock.ExpectQuery(`SELECT s.\* FROM vehicle_native_alarm_state`).WillReturnRows(sqlmock.NewRows([]string{"vin", "active_event_id"}).AddRow("VIN1", "false-event"))
|
|
notifications := sqlmock.NewRows([]string{"id", "event_id"})
|
|
if notified {
|
|
notifications.AddRow(1, "false-event")
|
|
}
|
|
mock.ExpectQuery(`SELECT n.id,n.event_id`).WillReturnRows(notifications)
|
|
}
|
|
|
|
func TestRepairDryRunNeverWrites(t *testing.T) {
|
|
db, mock, _ := sqlmock.New()
|
|
defer db.Close()
|
|
expectSnapshot(mock, false)
|
|
mock.ExpectRollback()
|
|
if err := run(t.Context(), db, false, ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := mock.ExpectationsWereMet(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
func TestRepairBacksUpAndCorrectsOnlyNativeEvents(t *testing.T) {
|
|
db, mock, _ := sqlmock.New()
|
|
defer db.Close()
|
|
expectSnapshot(mock, false)
|
|
mock.ExpectExec(`UPDATE vehicle_native_alarm_state`).WithArgs("false-event").WillReturnResult(sqlmock.NewResult(0, 1))
|
|
mock.ExpectExec(`DELETE FROM vehicle_alert_event_action`).WithArgs("false-event").WillReturnResult(sqlmock.NewResult(0, 1))
|
|
mock.ExpectExec(`DELETE FROM vehicle_native_alarm_evidence`).WithArgs("false-event").WillReturnResult(sqlmock.NewResult(0, 1))
|
|
mock.ExpectExec(`DELETE FROM vehicle_alert_event WHERE id=\? AND rule_id='native-gb32960-alarm'`).WithArgs("false-event").WillReturnResult(sqlmock.NewResult(0, 1))
|
|
mock.ExpectExec(`UPDATE vehicle_alert_event SET rule_name=\?,version=version\+1 WHERE id=\? AND rule_id='native-gb32960-alarm'`).WithArgs("绝缘报警", "real-event").WillReturnResult(sqlmock.NewResult(0, 1))
|
|
mock.ExpectExec(`INSERT INTO vehicle_alert_event_action`).WithArgs("real-event", "processing", "processing").WillReturnResult(sqlmock.NewResult(1, 1))
|
|
mock.ExpectCommit()
|
|
path := filepath.Join(t.TempDir(), "backup.json")
|
|
if err := run(t.Context(), db, true, path); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var archive map[string]json.RawMessage
|
|
if err = json.Unmarshal(data, &archive); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, key := range []string{"events", "evidence", "actions", "state"} {
|
|
if len(archive[key]) == 0 {
|
|
t.Fatalf("missing backup %s", key)
|
|
}
|
|
}
|
|
info, _ := os.Stat(path)
|
|
if info.Mode().Perm() != 0600 {
|
|
t.Fatal("backup permissions")
|
|
}
|
|
if err := mock.ExpectationsWereMet(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
func TestRepairRefusesToOverwriteBackup(t *testing.T) {
|
|
db, mock, _ := sqlmock.New()
|
|
defer db.Close()
|
|
expectSnapshot(mock, false)
|
|
mock.ExpectRollback()
|
|
path := filepath.Join(t.TempDir(), "backup.json")
|
|
if err := os.WriteFile(path, []byte("previous backup"), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := run(t.Context(), db, true, path); err == nil {
|
|
t.Fatal("overwrote backup")
|
|
}
|
|
if err := mock.ExpectationsWereMet(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
func TestRepairRefusesToOrphanNotifications(t *testing.T) {
|
|
db, mock, _ := sqlmock.New()
|
|
defer db.Close()
|
|
expectSnapshot(mock, true)
|
|
mock.ExpectRollback()
|
|
if err := run(t.Context(), db, true, filepath.Join(t.TempDir(), "backup.json")); err == nil {
|
|
t.Fatal("deleted notified event")
|
|
}
|
|
if err := mock.ExpectationsWereMet(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|