Extend autotest to cover all UART commands except OTA upload.

Add led_ring, find_me, restart, and ota_progress steps plus uart_cmds scenario.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-19 22:41:23 +02:00
co-authored by Cursor
parent a9e08107b4
commit 95d5a9747a
7 changed files with 390 additions and 1 deletions
+212
View File
@@ -15,6 +15,10 @@ type MasterClient interface {
ListClients() ([]*pb.ClientInfo, error)
AccelDeadzone(req *pb.AccelDeadzoneRequest) (*pb.AccelDeadzoneResponse, error)
EspnowUnicastTest(clientID, seq uint32) (*pb.EspNowUnicastTestResponse, error)
LedRing(req *pb.LedRingProgressRequest) (*pb.LedRingProgressResponse, error)
FindMe(clientID uint32) (*pb.EspNowFindMeResponse, error)
Restart(clientID uint32) (*pb.RestartResponse, error)
OtaSlaveProgress(clientID uint32) (*pb.OtaSlaveProgressResponse, error)
}
type StepResult struct {
@@ -92,6 +96,14 @@ func runStep(bench *Bench, step Step, client MasterClient) error {
return checkDeadzone(bench, step, client)
case "unicast_test", "unicast":
return checkUnicastTest(bench, step, client)
case "led_ring", "ledring":
return checkLedRing(step, client)
case "find_me", "findme":
return checkFindMe(bench, step, client)
case "restart":
return checkRestartCmd(bench, step, client)
case "ota_progress", "ota_slave_progress":
return checkOtaProgress(step, client)
case "reset", "reboot":
return checkReset(bench, step)
default:
@@ -310,3 +322,203 @@ func checkUnicastTest(bench *Bench, step Step, client MasterClient) error {
}
return nil
}
type ledRingInput struct {
Mode string `json:"mode"`
Progress uint `json:"progress"`
Digit uint `json:"digit"`
R uint `json:"r"`
G uint `json:"g"`
B uint `json:"b"`
Intensity uint `json:"intensity"`
BlinkMs uint `json:"blink_ms"`
BlinkCount uint `json:"blink_count"`
}
func ledRingModeValue(mode string) (uint32, error) {
switch strings.ToLower(strings.ReplaceAll(mode, "-", "_")) {
case "clear", "":
return 0, nil
case "progress":
return 1, nil
case "digit":
return 2, nil
case "blink":
return 3, nil
case "find_me", "findme":
return 4, nil
default:
return 0, fmt.Errorf("unknown led_ring mode %q", mode)
}
}
func checkLedRing(step Step, client MasterClient) error {
var in ledRingInput
if len(step.Input) > 0 {
if err := json.Unmarshal(step.Input, &in); err != nil {
return fmt.Errorf("input: %w", err)
}
}
mode, err := ledRingModeValue(in.Mode)
if err != nil {
return err
}
if in.Mode == "" && step.Expect.Mode != nil {
mode = *step.Expect.Mode
}
req := &pb.LedRingProgressRequest{
Mode: mode,
Progress: uint32(in.Progress),
Digit: uint32(in.Digit),
R: uint32(in.R),
G: uint32(in.G),
B: uint32(in.B),
Intensity: uint32(in.Intensity),
BlinkMs: uint32(in.BlinkMs),
BlinkCount: uint32(in.BlinkCount),
}
if mode == 1 && req.GetG() == 0 && req.GetR() == 0 && req.GetB() == 0 {
req.G = 255
}
resp, err := client.LedRing(req)
if err != nil {
return err
}
e := step.Expect
if e.Success != nil && resp.GetSuccess() != *e.Success {
return fmt.Errorf("success=%v want %v", resp.GetSuccess(), *e.Success)
}
if e.Mode != nil && resp.GetMode() != *e.Mode {
return fmt.Errorf("mode=%d want %d", resp.GetMode(), *e.Mode)
}
if e.Progress != nil && resp.GetProgress() != *e.Progress {
return fmt.Errorf("progress=%d want %d", resp.GetProgress(), *e.Progress)
}
if e.Digit != nil && resp.GetDigit() != *e.Digit {
return fmt.Errorf("digit=%d want %d", resp.GetDigit(), *e.Digit)
}
return nil
}
type findMeInput struct {
ClientID *uint `json:"client_id"`
Client uint `json:"client"`
Slave string `json:"slave"`
}
func checkFindMe(bench *Bench, step Step, client MasterClient) error {
var in findMeInput
if len(step.Input) > 0 {
if err := json.Unmarshal(step.Input, &in); err != nil {
return fmt.Errorf("input: %w", err)
}
}
clientID, err := resolveClientID(bench, in.Slave, in.ClientID, in.Client)
if err != nil {
return err
}
resp, err := client.FindMe(clientID)
if err != nil {
return err
}
e := step.Expect
if e.Success != nil && resp.GetSuccess() != *e.Success {
return fmt.Errorf("success=%v want %v", resp.GetSuccess(), *e.Success)
}
if e.Slave != "" || in.Slave != "" {
wantSlave := e.Slave
if wantSlave == "" {
wantSlave = in.Slave
}
wantID, err := bench.ResolveClientID(wantSlave)
if err != nil {
return err
}
if resp.GetClientId() != wantID {
return fmt.Errorf("client_id=%d want %d", resp.GetClientId(), wantID)
}
}
return nil
}
type restartCmdInput struct {
ClientID *uint `json:"client_id"`
Client uint `json:"client"`
Slave string `json:"slave"`
}
func checkRestartCmd(bench *Bench, step Step, client MasterClient) error {
var in restartCmdInput
if len(step.Input) > 0 {
if err := json.Unmarshal(step.Input, &in); err != nil {
return fmt.Errorf("input: %w", err)
}
}
clientID, err := resolveClientID(bench, in.Slave, in.ClientID, in.Client)
if err != nil {
return err
}
resp, err := client.Restart(clientID)
if err != nil {
return err
}
e := step.Expect
if e.Success != nil && resp.GetSuccess() != *e.Success {
return fmt.Errorf("success=%v want %v", resp.GetSuccess(), *e.Success)
}
if resp.GetClientId() != clientID {
return fmt.Errorf("client_id=%d want %d", resp.GetClientId(), clientID)
}
return nil
}
type otaProgressInput struct {
ClientID *uint `json:"client_id"`
Client uint `json:"client"`
Slave string `json:"slave"`
}
func checkOtaProgress(step Step, client MasterClient) error {
var in otaProgressInput
if len(step.Input) > 0 {
if err := json.Unmarshal(step.Input, &in); err != nil {
return fmt.Errorf("input: %w", err)
}
}
clientID := uint32(in.Client)
if in.ClientID != nil {
clientID = uint32(*in.ClientID)
}
resp, err := client.OtaSlaveProgress(clientID)
if err != nil {
return err
}
e := step.Expect
if e.Active != nil && resp.GetActive() != *e.Active {
return fmt.Errorf("active=%v want %v", resp.GetActive(), *e.Active)
}
return nil
}
func resolveClientID(bench *Bench, slave string, clientID *uint, client uint) (uint32, error) {
switch {
case slave != "":
return bench.ResolveClientID(slave)
case clientID != nil:
return uint32(*clientID), nil
default:
return uint32(client), nil
}
}
+25
View File
@@ -0,0 +1,25 @@
package autotest
import "testing"
func TestLedRingModeValue(t *testing.T) {
tests := []struct {
mode string
want uint32
}{
{"clear", 0},
{"progress", 1},
{"digit", 2},
{"blink", 3},
{"find-me", 4},
}
for _, tc := range tests {
got, err := ledRingModeValue(tc.mode)
if err != nil {
t.Fatalf("mode %q: %v", tc.mode, err)
}
if got != tc.want {
t.Fatalf("mode %q = %d want %d", tc.mode, got, tc.want)
}
}
}
+8
View File
@@ -45,6 +45,14 @@ type Expect struct {
// unicast_test
Seq *uint32 `json:"seq,omitempty"`
// led_ring
Mode *uint32 `json:"mode,omitempty"`
Progress *uint32 `json:"progress,omitempty"`
Digit *uint32 `json:"digit,omitempty"`
// ota_slave_progress
Active *bool `json:"active,omitempty"`
}
func LoadScenario(path string) (*Scenario, error) {