package onboarding import ( "data-terminal-cloud/internal/device" "github.com/google/uuid" "strings" "sync" "testing" ) func TestControlInputValidation(t *testing.T) { valid := DeviceControlReport{Firmware: "1.7.0", Revision: 1, Speaker: 70, RSSI: -55} if err := validateControlReport(valid); err != nil { t.Fatal(err) } for _, mutate := range []func(*DeviceControlReport){ func(v *DeviceControlReport) { v.Speaker = -1 }, func(v *DeviceControlReport) { v.Speaker = 101 }, func(v *DeviceControlReport) { v.Revision = -1 }, func(v *DeviceControlReport) { v.Firmware = "" }, func(v *DeviceControlReport) { v.RSSI = -128 }, func(v *DeviceControlReport) { s := "名称\n"; v.DisplayName = &s }, func(v *DeviceControlReport) { v.Power = &DevicePowerReport{Mode: "standby", MicrophonePaused: false} }, func(v *DeviceControlReport) { v.Power = &DevicePowerReport{Mode: "standby", MicrophonePaused: true, BacklightPercent: 80} }, func(v *DeviceControlReport) { v.Power = &DevicePowerReport{Mode: "off"} }, func(v *DeviceControlReport) { v.Power = &DevicePowerReport{Mode: "active", BacklightPercent: 101} }, } { invalid := valid mutate(&invalid) if validateControlReport(invalid) == nil { t.Fatalf("accepted %+v", invalid) } } ack := DeviceControlAck{ID: uuid.NewString(), Status: "SUCCEEDED"} if err := validateControlAck(ack); err != nil { t.Fatal(err) } ack.Status = "QUEUED" if validateControlAck(ack) == nil { t.Fatal("accepted state regression") } ack.Status = "FAILED" ack.Result = map[string]any{"body": strings.Repeat("x", 4097)} if validateControlAck(ack) == nil { t.Fatal("accepted oversized result") } } func TestScreenWakeValidation(t *testing.T) { in := DeviceControlReport{Firmware: "1.7.0-controls.32", Revision: 4, Speaker: 60, RSSI: -50, Power: &DevicePowerReport{Mode: "active", BacklightPercent: 80}, ScreenWake: &DeviceScreenWake{ID: uuid.NewString(), Revision: 4}} must(t, validateControlReport(in)) for _, mutation := range []func(*DeviceControlReport){ func(r *DeviceControlReport) { r.ScreenWake = &DeviceScreenWake{ID: "bad", Revision: 4} }, func(r *DeviceControlReport) { r.ScreenWake = &DeviceScreenWake{ID: uuid.NewString()} }, func(r *DeviceControlReport) { r.Power = nil }, func(r *DeviceControlReport) { r.Power = &DevicePowerReport{Mode: "standby", MicrophonePaused: true} }, } { invalid := in mutation(&invalid) if validateControlReport(invalid) == nil { t.Fatal("invalid screen wake accepted") } } } func TestScreenWakeReconcilesAndFencesNewerConfiguration(t *testing.T) { f := newFixture(t) _, err := f.s.pool.Exec(f.ctx, `UPDATE device_twin SET desired_revision=4,reported_revision=4, desired_config='{"volume":{"speaker":31},"identity":{"display_name":"保留名称"},"power":{"mode":"standby"}}', reported_config='{}' WHERE device_id=$1`, f.d.ID) must(t, err) in := DeviceControlReport{Firmware: "1.7.0-controls.32", Revision: 4, Speaker: 31, RSSI: -50, Power: &DevicePowerReport{Mode: "active", BacklightPercent: 80}, ScreenWake: &DeviceScreenWake{ID: uuid.NewString(), Revision: 4}} check := func(wantRevision int64, wantMode, wantResult string) { t.Helper() out, err := f.s.DeviceControlSync(f.ctx, f.d, in) must(t, err) if receipt := out["screen_wake"].(*DeviceScreenWakeReceipt); receipt.ID != in.ScreenWake.ID || receipt.Result != wantResult { t.Fatal(receipt) } var revision, reported int64 var mode, name string var speaker int must(t, f.s.pool.QueryRow(f.ctx, `SELECT desired_revision,reported_revision,desired_config->'power'->>'mode', desired_config->'identity'->>'display_name',(desired_config->'volume'->>'speaker')::int FROM device_twin WHERE device_id=$1`, f.d.ID).Scan(&revision, &reported, &mode, &name, &speaker)) if revision != wantRevision || reported != in.Revision || mode != wantMode || name != "保留名称" || speaker != 31 { t.Fatalf("revision=%d reported=%d mode=%s name=%s speaker=%d", revision, reported, mode, name, speaker) } } check(5, "active", "applied") check(5, "active", "applied") // Retry after a lost reply must not add a revision. _, err = f.s.pool.Exec(f.ctx, `UPDATE device_twin SET desired_revision=6, desired_config=jsonb_set(desired_config,'{power}','{"mode":"standby"}') WHERE device_id=$1`, f.d.ID) must(t, err) check(6, "standby", "applied") // The old successful event cannot undo a later standby. in.ScreenWake = &DeviceScreenWake{ID: uuid.NewString(), Revision: 4} check(6, "standby", "superseded") // An offline stale tap respects the newer config. in.ScreenWake = &DeviceScreenWake{ID: uuid.NewString(), Revision: 6} in.Revision = 6 var wg sync.WaitGroup errs := make(chan error, 2) for i := 0; i < 2; i++ { wg.Add(1) go func() { defer wg.Done(); _, err := f.s.DeviceControlSync(f.ctx, f.d, in); errs <- err }() } wg.Wait() close(errs) for err := range errs { must(t, err) } check(7, "active", "applied") in.ScreenWake = &DeviceScreenWake{ID: in.ScreenWake.ID, Revision: 7} if _, err := f.s.DeviceControlSync(f.ctx, f.d, in); err == nil { t.Fatal("receipt ID reused with a changed revision") } foreign := f.d foreign.ID = uuid.NewString() if _, err := f.s.DeviceControlSync(f.ctx, foreign, in); err == nil { t.Fatal("foreign device altered power") } } func TestControlNameReportsAreActualReadings(t *testing.T) { f := newFixture(t) _, err := f.s.pool.Exec(f.ctx, `UPDATE device_twin SET desired_revision=2,desired_config='{"identity":{"display_name":"云端名称"}}',reported_config='{}',reported_revision=NULL WHERE device_id=$1`, f.d.ID) must(t, err) in := DeviceControlReport{Firmware: "1.7.0", Speaker: 60, RSSI: -50} _, err = f.s.DeviceControlSync(f.ctx, f.d, in) must(t, err) var name *string must(t, f.s.pool.QueryRow(f.ctx, `SELECT reported_config->'identity'->>'display_name' FROM device_twin WHERE device_id=$1`, f.d.ID).Scan(&name)) if name != nil { t.Fatal("old firmware falsely reported desired name") } actual := "设备实际名称" in.DisplayName = &actual _, err = f.s.DeviceControlSync(f.ctx, f.d, in) must(t, err) must(t, f.s.pool.QueryRow(f.ctx, `SELECT reported_config->'identity'->>'display_name' FROM device_twin WHERE device_id=$1`, f.d.ID).Scan(&name)) if name == nil || *name != actual { t.Fatal("actual name lost or replaced by desired") } actual = "" _, err = f.s.DeviceControlSync(f.ctx, f.d, in) must(t, err) must(t, f.s.pool.QueryRow(f.ctx, `SELECT reported_config->'identity'->>'display_name' FROM device_twin WHERE device_id=$1`, f.d.ID).Scan(&name)) if name == nil || *name != "" { t.Fatal("explicit default name not reported") } } func TestControlPowerActualReadings(t *testing.T) { f := newFixture(t) _, err := f.s.pool.Exec(f.ctx, `UPDATE device_twin SET desired_config=desired_config || '{"power":{"mode":"standby"}}'::jsonb WHERE device_id=$1`, f.d.ID) must(t, err) in := DeviceControlReport{Firmware: "1.7.0", Speaker: 60, RSSI: -50} _, err = f.s.DeviceControlSync(f.ctx, f.d, in) must(t, err) var mode *string must(t, f.s.pool.QueryRow(f.ctx, `SELECT reported_config->'power'->>'mode' FROM device_twin WHERE device_id=$1`, f.d.ID).Scan(&mode)) if mode != nil { t.Fatal("old firmware falsely claimed standby") } for _, p := range []DevicePowerReport{{Mode: "active", BacklightPercent: 80, MicrophoneReads: 12}, {Mode: "standby", MicrophonePaused: true, BacklightPercent: 0, MicrophoneReads: 12}} { in.Power = &p _, err = f.s.DeviceControlSync(f.ctx, f.d, in) must(t, err) must(t, f.s.pool.QueryRow(f.ctx, `SELECT reported_config->'power'->>'mode' FROM device_twin WHERE device_id=$1`, f.d.ID).Scan(&mode)) if mode == nil || *mode != p.Mode { t.Fatal("power report substituted by desired mode") } } } func TestDeviceControlReportsAndCommandIsolation(t *testing.T) { f := newFixture(t) _, err := f.s.pool.Exec(f.ctx, `UPDATE device_twin SET desired_revision=2,desired_config='{"volume":{"speaker":40}}',reported_revision=NULL WHERE device_id=$1`, f.d.ID) must(t, err) commandID := uuid.NewString() _, err = f.s.pool.Exec(f.ctx, `INSERT INTO device_command(public_id,tenant_id,device_id,command_type,requested_by,idempotency_key,request_digest,expires_at) VALUES($1,$2,$3,'diagnostics',$4,$5,repeat('d',64),now()+interval '5 minutes')`, commandID, f.tenant, f.d.ID, f.operatorID, uuid.NewString()) must(t, err) in := DeviceControlReport{Firmware: "1.7.0", Speaker: 70, RSSI: -50, Busy: true} out, err := f.s.DeviceControlSync(f.ctx, f.d, in) must(t, err) if len(out["commands"].([]device.Command)) != 0 { t.Fatal("delivered during a call") } var actual int var revision *int64 must(t, f.s.pool.QueryRow(f.ctx, `SELECT (reported_config->'volume'->>'speaker')::int,reported_revision FROM device_twin WHERE device_id=$1`, f.d.ID).Scan(&actual, &revision)) if actual != 70 || revision != nil { t.Fatal("cloud desired value falsely reported as applied") } in.Speaker = 40 in.Revision = 2 in.Busy = false out, err = f.s.DeviceControlSync(f.ctx, f.d, in) must(t, err) items := out["commands"].([]device.Command) if len(items) != 1 || items[0].ID != commandID || items[0].Status != "DELIVERED" { t.Fatal(items) } in.Revision = 3 if _, err = f.s.DeviceControlSync(f.ctx, f.d, in); err == nil { t.Fatal("accepted future revision") } in.Revision = 1 if _, err = f.s.DeviceControlSync(f.ctx, f.d, in); err == nil { t.Fatal("accepted stale revision") } ack := DeviceControlAck{ID: commandID, Status: "ACKNOWLEDGED"} foreign := f.d foreign.ID = uuid.NewString() if _, err = f.s.DeviceControlAcknowledge(f.ctx, foreign, ack); err == nil { t.Fatal("foreign device acknowledged command") } _, err = f.s.DeviceControlAcknowledge(f.ctx, f.d, ack) must(t, err) ack.Status = "SUCCEEDED" ack.Result = map[string]any{"speaker": 40} _, err = f.s.DeviceControlAcknowledge(f.ctx, f.d, ack) must(t, err) _, err = f.s.DeviceControlAcknowledge(f.ctx, f.d, ack) must(t, err) ack.Status = "FAILED" if _, err = f.s.DeviceControlAcknowledge(f.ctx, f.d, ack); err == nil { t.Fatal("changed terminal result") } blocked := f.d blocked.Status = "revoked" if _, err = f.s.DeviceControlSync(f.ctx, blocked, in); err == nil { t.Fatal("revoked device synced") } }