Add bench UART ports and cold-start reset to goTool autotest.
Bench configs define command and console serial paths; scenarios can reset nodes via esptool before tests. Smoke resets all nodes then waits for ESP-NOW join. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
d24b0cb5c3
commit
0299ba44fd
@ -31,15 +31,16 @@ go run . -port /dev/ttyUSB0 clients
|
|||||||
|
|
||||||
### Automated tests
|
### Automated tests
|
||||||
|
|
||||||
Bench **configs** (`testdata/configs/`) list master/slave MACs. **Scenarios** (`testdata/scenarios/`) run a sequence of the same UART commands with `input` / `expect` checks.
|
Bench **configs** (`testdata/configs/`) list network, MACs, and serial ports (`uart.master` for commands, `*_console` for esptool reset). **Scenarios** run UART commands plus optional `reset` steps.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go run . -port /dev/ttyUSB0 test -list-configs
|
go run . test -list-configs
|
||||||
go run . -port /dev/ttyUSB0 test -list-scenarios
|
go run . test -config example-lab -scenario smoke
|
||||||
go run . -port /dev/ttyUSB0 test -config example-lab -scenario smoke
|
go run . test -config my-lab -scenario smoke -port /dev/ttyUSB1 -v
|
||||||
go run . -port /dev/ttyUSB0 test -config testdata/configs/my-lab.json -scenario smoke -v
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
With a complete bench config, `-port` is optional for `test` (uses `uart.master` from JSON).
|
||||||
|
|
||||||
See [`testdata/README.md`](testdata/README.md) for the JSON schema.
|
See [`testdata/README.md`](testdata/README.md) for the JSON schema.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@ -7,12 +7,23 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// UARTConfig holds serial paths for gotool commands and per-node reset (USB console).
|
||||||
|
type UARTConfig struct {
|
||||||
|
// Baud for uart.master (default 921600).
|
||||||
|
Baud uint `json:"baud,omitempty"`
|
||||||
|
// Master command UART (external adapter on GPIO2/3), e.g. /dev/ttyUSB0.
|
||||||
|
Master string `json:"master"`
|
||||||
|
// Master USB console / JTAG serial for esptool reset, e.g. /dev/ttyACM0.
|
||||||
|
MasterConsole string `json:"master_console,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Config describes the bench: ESP-NOW network, master MAC, and known slaves.
|
// Config describes the bench: ESP-NOW network, master MAC, and known slaves.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Description string `json:"description,omitempty"`
|
Description string `json:"description,omitempty"`
|
||||||
Network uint `json:"network"`
|
Network uint `json:"network"`
|
||||||
MasterMAC string `json:"master_mac"`
|
MasterMAC string `json:"master_mac"`
|
||||||
|
UART UARTConfig `json:"uart"`
|
||||||
Slaves []SlaveNode `json:"slaves"`
|
Slaves []SlaveNode `json:"slaves"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,6 +31,8 @@ type SlaveNode struct {
|
|||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
MAC string `json:"mac"`
|
MAC string `json:"mac"`
|
||||||
ClientID *uint `json:"client_id,omitempty"`
|
ClientID *uint `json:"client_id,omitempty"`
|
||||||
|
// USB console port for esptool reset (optional), e.g. /dev/ttyACM1.
|
||||||
|
Console string `json:"console,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Bench struct {
|
type Bench struct {
|
||||||
@ -50,6 +63,12 @@ func NewBench(cfg Config) (*Bench, error) {
|
|||||||
if cfg.Network < 1 || cfg.Network > 8 {
|
if cfg.Network < 1 || cfg.Network > 8 {
|
||||||
return nil, fmt.Errorf("config %q: network must be 1–8 (DIP / IO expander)", cfg.ID)
|
return nil, fmt.Errorf("config %q: network must be 1–8 (DIP / IO expander)", cfg.ID)
|
||||||
}
|
}
|
||||||
|
if cfg.UART.Master == "" {
|
||||||
|
return nil, fmt.Errorf("config %q: uart.master is required (gotool command port)", cfg.ID)
|
||||||
|
}
|
||||||
|
if cfg.UART.Baud == 0 {
|
||||||
|
cfg.UART.Baud = 921600
|
||||||
|
}
|
||||||
|
|
||||||
b := &Bench{Config: cfg, slaveByID: make(map[string]*SlaveNode)}
|
b := &Bench{Config: cfg, slaveByID: make(map[string]*SlaveNode)}
|
||||||
for i := range cfg.Slaves {
|
for i := range cfg.Slaves {
|
||||||
|
|||||||
@ -7,6 +7,9 @@ func TestNewBenchClientIDFromMAC(t *testing.T) {
|
|||||||
ID: "t",
|
ID: "t",
|
||||||
Network: 1,
|
Network: 1,
|
||||||
MasterMAC: "aa:bb:cc:dd:ee:ff",
|
MasterMAC: "aa:bb:cc:dd:ee:ff",
|
||||||
|
UART: UARTConfig{
|
||||||
|
Master: "/dev/ttyUSB0",
|
||||||
|
},
|
||||||
Slaves: []SlaveNode{{
|
Slaves: []SlaveNode{{
|
||||||
ID: "pod",
|
ID: "pod",
|
||||||
MAC: "50:78:7d:18:01:10",
|
MAC: "50:78:7d:18:01:10",
|
||||||
|
|||||||
103
goTool/autotest/reset.go
Normal file
103
goTool/autotest/reset.go
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package autotest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultResetWaitMS = 2000
|
||||||
|
|
||||||
|
// ResetESP32 toggles EN via esptool (USB-JTAG / ttyACM console port).
|
||||||
|
func ResetESP32(port string) error {
|
||||||
|
if port == "" {
|
||||||
|
return fmt.Errorf("empty console port")
|
||||||
|
}
|
||||||
|
|
||||||
|
tries := [][]string{
|
||||||
|
{"python", "-m", "esptool", "--chip", "esp32s3", "-p", port,
|
||||||
|
"--before", "default_reset", "--after", "hard_reset", "chip_id"},
|
||||||
|
{"esptool.py", "--chip", "esp32s3", "-p", port,
|
||||||
|
"--before", "default_reset", "--after", "hard_reset", "chip_id"},
|
||||||
|
{"esptool", "--chip", "esp32s3", "-p", port,
|
||||||
|
"--before", "default_reset", "--after", "hard_reset", "chip_id"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastErr error
|
||||||
|
for _, argv := range tries {
|
||||||
|
if _, err := exec.LookPath(argv[0]); err != nil {
|
||||||
|
lastErr = err
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cmd := exec.Command(argv[0], argv[1:]...)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
lastErr = err
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if lastErr != nil {
|
||||||
|
return fmt.Errorf("esptool reset on %s: %w (install ESP-IDF esptool or python -m esptool)", port, lastErr)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("esptool not found; cannot reset %s", port)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bench) resetNode(target string) (string, error) {
|
||||||
|
switch target {
|
||||||
|
case "master", "":
|
||||||
|
if b.UART.MasterConsole == "" {
|
||||||
|
return "", fmt.Errorf("uart.master_console not set in config %q", b.ID)
|
||||||
|
}
|
||||||
|
return b.UART.MasterConsole, nil
|
||||||
|
default:
|
||||||
|
s, err := b.Slave(target)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if s.Console == "" {
|
||||||
|
return "", fmt.Errorf("slave %q has no console port in config", target)
|
||||||
|
}
|
||||||
|
return s.Console, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bench) ResetTargets(targets []string, waitMS int) error {
|
||||||
|
if waitMS <= 0 {
|
||||||
|
waitMS = defaultResetWaitMS
|
||||||
|
}
|
||||||
|
if len(targets) == 0 {
|
||||||
|
targets = []string{"master"}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, t := range targets {
|
||||||
|
port, err := b.resetNode(t)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := ResetESP32(port); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
time.Sleep(time.Duration(waitMS) * time.Millisecond)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bench) ResetAll(waitMS int) error {
|
||||||
|
// Slaves first, master last — master discover runs after slaves are booting.
|
||||||
|
var targets []string
|
||||||
|
for i := range b.Slaves {
|
||||||
|
if b.Slaves[i].Console != "" {
|
||||||
|
targets = append(targets, b.Slaves[i].ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if b.UART.MasterConsole != "" {
|
||||||
|
targets = append(targets, "master")
|
||||||
|
}
|
||||||
|
if len(targets) == 0 {
|
||||||
|
return fmt.Errorf("config %q: no console ports defined for reset", b.ID)
|
||||||
|
}
|
||||||
|
return b.ResetTargets(targets, waitMS)
|
||||||
|
}
|
||||||
@ -92,11 +92,42 @@ func runStep(bench *Bench, step Step, client MasterClient) error {
|
|||||||
return checkDeadzone(bench, step, client)
|
return checkDeadzone(bench, step, client)
|
||||||
case "unicast_test", "unicast":
|
case "unicast_test", "unicast":
|
||||||
return checkUnicastTest(bench, step, client)
|
return checkUnicastTest(bench, step, client)
|
||||||
|
case "reset", "reboot":
|
||||||
|
return checkReset(bench, step)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unknown command %q", step.Command)
|
return fmt.Errorf("unknown command %q", step.Command)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type resetInput struct {
|
||||||
|
Target string `json:"target"`
|
||||||
|
Slave string `json:"slave"`
|
||||||
|
All bool `json:"all"`
|
||||||
|
WaitMS int `json:"wait_ms"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkReset(bench *Bench, step Step) error {
|
||||||
|
var in resetInput
|
||||||
|
if len(step.Input) > 0 {
|
||||||
|
if err := json.Unmarshal(step.Input, &in); err != nil {
|
||||||
|
return fmt.Errorf("input: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if in.All {
|
||||||
|
return bench.ResetAll(in.WaitMS)
|
||||||
|
}
|
||||||
|
|
||||||
|
target := in.Target
|
||||||
|
if in.Slave != "" {
|
||||||
|
target = in.Slave
|
||||||
|
}
|
||||||
|
if target == "" {
|
||||||
|
target = "master"
|
||||||
|
}
|
||||||
|
return bench.ResetTargets([]string{target}, in.WaitMS)
|
||||||
|
}
|
||||||
|
|
||||||
func checkVersion(step Step, client MasterClient) error {
|
func checkVersion(step Step, client MasterClient) error {
|
||||||
ver, err := client.GetVersion()
|
ver, err := client.GetVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import (
|
|||||||
"powerpod/gotool/autotest"
|
"powerpod/gotool/autotest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func runTest(sp *serialPort, args []string) error {
|
func runTest(portOverride string, baudOverride int, args []string) error {
|
||||||
fs := flag.NewFlagSet("test", flag.ExitOnError)
|
fs := flag.NewFlagSet("test", flag.ExitOnError)
|
||||||
configName := fs.String("config", "", "bench config id or path (testdata/configs/)")
|
configName := fs.String("config", "", "bench config id or path (testdata/configs/)")
|
||||||
scenarioName := fs.String("scenario", "", "scenario id or path (testdata/scenarios/)")
|
scenarioName := fs.String("scenario", "", "scenario id or path (testdata/scenarios/)")
|
||||||
@ -49,14 +49,37 @@ func runTest(sp *serialPort, args []string) error {
|
|||||||
return fmt.Errorf("load scenario: %w", err)
|
return fmt.Errorf("load scenario: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
port := portOverride
|
||||||
|
if port == "" {
|
||||||
|
port = bench.UART.Master
|
||||||
|
}
|
||||||
|
baud := baudOverride
|
||||||
|
if baud <= 0 {
|
||||||
|
baud = int(bench.UART.Baud)
|
||||||
|
}
|
||||||
|
|
||||||
|
sp, err := openSerial(port, baud)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("open %s: %w", port, err)
|
||||||
|
}
|
||||||
|
defer sp.Close()
|
||||||
|
|
||||||
if !*verbose {
|
if !*verbose {
|
||||||
log.SetOutput(io.Discard)
|
log.SetOutput(io.Discard)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("bench config %q (network %d, master %s)\n",
|
fmt.Printf("bench config %q (network %d, master %s)\n",
|
||||||
bench.ID, bench.Network, bench.MasterMAC)
|
bench.ID, bench.Network, bench.MasterMAC)
|
||||||
|
fmt.Printf(" uart.master %s (baud %d)\n", bench.UART.Master, bench.UART.Baud)
|
||||||
|
if bench.UART.MasterConsole != "" {
|
||||||
|
fmt.Printf(" uart.master_console %s\n", bench.UART.MasterConsole)
|
||||||
|
}
|
||||||
for _, s := range bench.Slaves {
|
for _, s := range bench.Slaves {
|
||||||
fmt.Printf(" slave %q mac=%s client_id=%d\n", s.ID, s.MAC, *s.ClientID)
|
line := fmt.Sprintf(" slave %q mac=%s client_id=%d", s.ID, s.MAC, *s.ClientID)
|
||||||
|
if s.Console != "" {
|
||||||
|
line += fmt.Sprintf(" console=%s", s.Console)
|
||||||
|
}
|
||||||
|
fmt.Println(line)
|
||||||
}
|
}
|
||||||
fmt.Printf("scenario %q (%d steps)\n\n", sc.ID, len(sc.Steps))
|
fmt.Printf("scenario %q (%d steps)\n\n", sc.ID, len(sc.Steps))
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,8 @@ import (
|
|||||||
const defaultBaud = 921600
|
const defaultBaud = 921600
|
||||||
|
|
||||||
func usage() {
|
func usage() {
|
||||||
fmt.Fprintf(os.Stderr, "usage: gotool -port /dev/ttyUSB0 <command>\n\n")
|
fmt.Fprintf(os.Stderr, "usage: gotool [-port /dev/ttyUSB0] <command>\n")
|
||||||
|
fmt.Fprintf(os.Stderr, " test uses uart.master from bench config when -port is omitted\n\n")
|
||||||
fmt.Fprintf(os.Stderr, "commands:\n")
|
fmt.Fprintf(os.Stderr, "commands:\n")
|
||||||
fmt.Fprintf(os.Stderr, " version firmware version and git hash\n")
|
fmt.Fprintf(os.Stderr, " version firmware version and git hash\n")
|
||||||
fmt.Fprintf(os.Stderr, " clients registered ESP-NOW slaves on the master\n")
|
fmt.Fprintf(os.Stderr, " clients registered ESP-NOW slaves on the master\n")
|
||||||
@ -25,20 +26,28 @@ func main() {
|
|||||||
baud := flag.Int("baud", defaultBaud, "UART baud rate")
|
baud := flag.Int("baud", defaultBaud, "UART baud rate")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if *portName == "" || flag.NArg() < 1 {
|
if flag.NArg() < 1 {
|
||||||
usage()
|
usage()
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := flag.Arg(0)
|
cmd := flag.Arg(0)
|
||||||
|
|
||||||
|
var runErr error
|
||||||
|
switch cmd {
|
||||||
|
case "test", "autotest":
|
||||||
|
runErr = runTest(*portName, *baud, flag.Args()[1:])
|
||||||
|
case "version", "clients", "client-info", "deadzone", "accel-deadzone", "unicast-test", "unicast_test":
|
||||||
|
if *portName == "" {
|
||||||
|
fmt.Fprintf(os.Stderr, "command %q requires -port\n\n", cmd)
|
||||||
|
usage()
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
sp, err := openSerial(*portName, *baud)
|
sp, err := openSerial(*portName, *baud)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("open serial: %v", err)
|
log.Fatalf("open serial: %v", err)
|
||||||
}
|
}
|
||||||
defer sp.Close()
|
defer sp.Close()
|
||||||
|
|
||||||
var runErr error
|
|
||||||
switch cmd {
|
switch cmd {
|
||||||
case "version":
|
case "version":
|
||||||
runErr = runVersion(sp)
|
runErr = runVersion(sp)
|
||||||
@ -48,8 +57,7 @@ func main() {
|
|||||||
runErr = runDeadzone(sp, flag.Args()[1:])
|
runErr = runDeadzone(sp, flag.Args()[1:])
|
||||||
case "unicast-test", "unicast_test":
|
case "unicast-test", "unicast_test":
|
||||||
runErr = runUnicastTest(sp, flag.Args()[1:])
|
runErr = runUnicastTest(sp, flag.Args()[1:])
|
||||||
case "test", "autotest":
|
}
|
||||||
runErr = runTest(sp, flag.Args()[1:])
|
|
||||||
default:
|
default:
|
||||||
fmt.Fprintf(os.Stderr, "unknown command %q\n\n", cmd)
|
fmt.Fprintf(os.Stderr, "unknown command %q\n\n", cmd)
|
||||||
usage()
|
usage()
|
||||||
|
|||||||
45
goTool/testdata/README.md
vendored
45
goTool/testdata/README.md
vendored
@ -2,29 +2,35 @@
|
|||||||
|
|
||||||
## Bench config (`configs/*.json`)
|
## Bench config (`configs/*.json`)
|
||||||
|
|
||||||
Describes your hardware bench (for documentation and slave lookup in tests).
|
Describes your hardware bench: network, MACs, and serial ports.
|
||||||
|
|
||||||
| Field | Meaning |
|
| Field | Meaning |
|
||||||
|-------|---------|
|
|-------|---------|
|
||||||
| `id` | Config name; referenced by scenarios |
|
| `id` | Config name; referenced by scenarios |
|
||||||
| `network` | ESP-NOW network **1–8** (must match DIP/IO expander on all nodes) |
|
| `network` | ESP-NOW network **1–8** (DIP / IO expander on all nodes) |
|
||||||
| `master_mac` | Expected WiFi MAC of the master ESP (reference) |
|
| `master_mac` | Master WiFi STA MAC (reference) |
|
||||||
| `slaves[].id` | Short name used in scenario `input.slave` / `expect.slave` |
|
| `uart.baud` | Command UART baud (default **921600**) |
|
||||||
| `slaves[].mac` | Full slave STA MAC (must match `gotool clients`) |
|
| `uart.master` | **gotool** port — external UART adapter on master GPIO2/3 (e.g. `/dev/ttyUSB0`) |
|
||||||
|
| `uart.master_console` | Master USB-JTAG/console for **reset** via esptool (e.g. `/dev/ttyACM0`) |
|
||||||
|
| `slaves[].id` | Short name for scenarios (`input.slave`, `expect.slave`) |
|
||||||
|
| `slaves[].mac` | Slave STA MAC (must match `gotool clients`) |
|
||||||
| `slaves[].client_id` | Optional; default = last MAC byte |
|
| `slaves[].client_id` | Optional; default = last MAC byte |
|
||||||
|
| `slaves[].console` | Slave USB console for **reset** (optional, e.g. `/dev/ttyACM1`) |
|
||||||
|
|
||||||
Copy `example-lab.json` to e.g. `my-lab.json` and set real MACs.
|
Copy `example-lab.json` → `my-lab.json` and set real paths (`ls /dev/ttyUSB* /dev/ttyACM*`).
|
||||||
|
|
||||||
|
`gotool test` uses `uart.master` when `-port` is omitted. Override with `-port /dev/…`.
|
||||||
|
|
||||||
## Scenario (`scenarios/*.json`)
|
## Scenario (`scenarios/*.json`)
|
||||||
|
|
||||||
Ordered steps: UART commands with `input` and `expect`.
|
Ordered steps: UART commands, delays, or esptool reset.
|
||||||
|
|
||||||
| Step field | Meaning |
|
| Step field | Meaning |
|
||||||
|------------|---------|
|
|------------|---------|
|
||||||
| `delay_ms` | Sleep only (no command) |
|
| `delay_ms` | Sleep only (no command) |
|
||||||
| `command` | `version`, `clients`, `deadzone`, `unicast_test` |
|
| `command` | See below |
|
||||||
| `input` | Command arguments (see below) |
|
| `input` | Command arguments |
|
||||||
| `expect` | Assertions on the response |
|
| `expect` | Assertions (UART commands only) |
|
||||||
|
|
||||||
### Commands
|
### Commands
|
||||||
|
|
||||||
@ -38,10 +44,25 @@ Ordered steps: UART commands with `input` and `expect`.
|
|||||||
**unicast_test** — `input`: `slave` or `client_id`, `seq`
|
**unicast_test** — `input`: `slave` or `client_id`, `seq`
|
||||||
`expect`: `success`, `seq`
|
`expect`: `success`, `seq`
|
||||||
|
|
||||||
|
**reset** — esptool hard-reset via console port from bench config (no `expect`).
|
||||||
|
`input`: `target` (`master`) or `slave` (`pod-1`), or `all: true`; optional `wait_ms` after each reset (default 2000).
|
||||||
|
|
||||||
|
Example reset steps:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "name": "reset master", "command": "reset", "input": { "target": "master", "wait_ms": 3000 } },
|
||||||
|
{ "name": "reset all", "command": "reset", "input": { "all": true, "wait_ms": 2500 } }
|
||||||
|
```
|
||||||
|
|
||||||
|
Requires `python -m esptool` or `esptool.py` on PATH (ESP-IDF).
|
||||||
|
|
||||||
|
The `smoke` scenario resets every node with a configured `console` port, waits **10 s** for boot and ESP-NOW join, then runs the UART checks.
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd goTool
|
cd goTool
|
||||||
go run . -port /dev/ttyUSB0 test -config my-lab -scenario smoke
|
go run . test -config example-lab -scenario smoke
|
||||||
go run . -port /dev/ttyUSB0 test -list-configs
|
go run . test -config my-lab -scenario smoke -port /dev/ttyUSB1
|
||||||
|
go run . test -list-configs
|
||||||
```
|
```
|
||||||
|
|||||||
10
goTool/testdata/configs/example-lab.json
vendored
10
goTool/testdata/configs/example-lab.json
vendored
@ -1,13 +1,19 @@
|
|||||||
{
|
{
|
||||||
"id": "example-lab",
|
"id": "example-lab",
|
||||||
"description": "Example bench — replace MACs and network with your hardware",
|
"description": "Example bench — replace MACs, network, and serial paths",
|
||||||
"network": 1,
|
"network": 1,
|
||||||
"master_mac": "50:78:7d:18:00:10",
|
"master_mac": "50:78:7d:18:00:10",
|
||||||
|
"uart": {
|
||||||
|
"baud": 921600,
|
||||||
|
"master": "/dev/ttyUSB0",
|
||||||
|
"master_console": "/dev/ttyACM0"
|
||||||
|
},
|
||||||
"slaves": [
|
"slaves": [
|
||||||
{
|
{
|
||||||
"id": "pod-1",
|
"id": "pod-1",
|
||||||
"mac": "50:78:7d:18:01:10",
|
"mac": "50:78:7d:18:01:10",
|
||||||
"client_id": 16
|
"client_id": 16,
|
||||||
|
"console": "/dev/ttyACM1"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
22
goTool/testdata/scenarios/smoke.json
vendored
22
goTool/testdata/scenarios/smoke.json
vendored
@ -1,21 +1,29 @@
|
|||||||
{
|
{
|
||||||
"id": "smoke",
|
"id": "smoke",
|
||||||
"description": "Basic master UART checks (no slaves required for version)",
|
"description": "Cold-start smoke: reset all nodes, wait for join, then UART checks",
|
||||||
"config": "example-lab",
|
"config": "example-lab",
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"name": "firmware version",
|
"name": "reset all nodes",
|
||||||
|
"command": "reset",
|
||||||
|
"input": {
|
||||||
|
"all": true,
|
||||||
|
"wait_ms": 2500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "boot and ESP-NOW join",
|
||||||
|
"delay_ms": 10000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "master UART up",
|
||||||
"command": "version",
|
"command": "version",
|
||||||
"expect": {
|
"expect": {
|
||||||
"version_min": 1
|
"version_min": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "wait for ESP-NOW join",
|
"name": "slave registered",
|
||||||
"delay_ms": 5000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "slave visible",
|
|
||||||
"command": "clients",
|
"command": "clients",
|
||||||
"expect": {
|
"expect": {
|
||||||
"min_clients": 1,
|
"min_clients": 1,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user