mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 08:36:13 +00:00
Refreshes docs/images/ui-{settings,devices,sync,migration}.png by
driving the web UI in chromedp against a synthetic speaker, so
documentation can be regenerated without real hardware and without
leaking personal data from the local network.
Three independent pieces:
- pkg/service/testing/fakespeaker — embeddable library serving the
HTTP and telnet surface the migration wizard probes (/info,
/presets, /recents and a getpdo CurrentSystemConfiguration reply
that places the device on the unmigrated happy path).
- cmd/dummy-speaker — thin CLI wrapping the library; self-registers
with a running service via POST /setup/devices.
- scripts/screenshots — chromedp runner driven by a JSON manifest;
decoupled from speaker/service setup so it can target any backend
URL. run.sh orchestrates a one-shot end-to-end capture and seeds
settings.json with a generic hostname plus discovery disabled to
keep real-network state out of the captures.
Captures are at DPR=2 for retina-sharp text.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
65 lines
1.2 KiB
Go
65 lines
1.2 KiB
Go
package fakespeaker
|
|
|
|
import (
|
|
"context"
|
|
"encoding/xml"
|
|
"io"
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestFakeSpeakerServesFixtures(t *testing.T) {
|
|
s, err := Start(Config{})
|
|
if err != nil {
|
|
t.Fatalf("start: %v", err)
|
|
}
|
|
|
|
t.Cleanup(func() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
defer cancel()
|
|
|
|
_ = s.Stop(ctx)
|
|
})
|
|
|
|
cases := []struct {
|
|
path string
|
|
root string
|
|
}{
|
|
{"/info", "info"},
|
|
{"/presets", "presets"},
|
|
{"/recents", "recents"},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.path, func(t *testing.T) {
|
|
resp, err := http.Get("http://" + s.HTTPAddr() + tc.path) //nolint:noctx
|
|
if err != nil {
|
|
t.Fatalf("get %s: %v", tc.path, err)
|
|
}
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("status = %d, want 200", resp.StatusCode)
|
|
}
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
t.Fatalf("read body: %v", err)
|
|
}
|
|
|
|
var root struct {
|
|
XMLName xml.Name
|
|
}
|
|
|
|
if err := xml.Unmarshal(body, &root); err != nil {
|
|
t.Fatalf("parse XML: %v\n%s", err, body)
|
|
}
|
|
|
|
if root.XMLName.Local != tc.root {
|
|
t.Fatalf("root element = %q, want %q", root.XMLName.Local, tc.root)
|
|
}
|
|
})
|
|
}
|
|
}
|