mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-19 00:56:16 +00:00
Adds XMLMigrated, HostsMigrated, ResolvMigrated, TelnetMigrated, and IsPaired as explicit fields on the summary so the UI can render partial-state cells (URLs flipped via telnet but the on-disk XML hasn't caught up; DNS interception in place but no CA installed; etc.) and surface pairing as its own precondition. IsMigrated remains backward-compatible — it is now the OR of the four migration axes. checkIsMigrated stops short-circuiting and writes each axis verdict unconditionally so a "partial" state on any axis is always visible to the UI even when another axis already reports the device migrated. populateDeviceInfo now derives IsPaired from the live :8090/info margeAccountUUID (clobbering any stale datastore copy), so a factory-reset speaker is correctly flagged as unpaired. Tests cover the per-axis verdicts independently and the IsPaired derivation in both the populated and empty live-info cases. This is the data layer for the upcoming three-axis "state view" panel on the migration tab. No frontend or behavior changes here. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
157 lines
4.8 KiB
Go
157 lines
4.8 KiB
Go
package setup
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
)
|
|
|
|
func TestIsTelnetMigrated_TargetHostnamePresent(t *testing.T) {
|
|
m := &Manager{ServerURL: "http://example:8000"}
|
|
|
|
summary := &MigrationSummary{
|
|
TelnetVerifiedConfig: "margeServerUrl=http://example:8000\nbmxRegistryUrl=http://example:8000/bmx/registry/v1/services\n",
|
|
}
|
|
|
|
if !m.isTelnetMigrated(summary) {
|
|
t.Error("isTelnetMigrated = false, want true when getpdo response contains our hostname")
|
|
}
|
|
}
|
|
|
|
func TestIsTelnetMigrated_DifferentHostname(t *testing.T) {
|
|
m := &Manager{ServerURL: "http://example:8000"}
|
|
|
|
summary := &MigrationSummary{
|
|
TelnetVerifiedConfig: "margeServerUrl=https://streaming.bose.com\n",
|
|
}
|
|
|
|
if m.isTelnetMigrated(summary) {
|
|
t.Error("isTelnetMigrated = true, want false when getpdo response points at the original cloud")
|
|
}
|
|
}
|
|
|
|
func TestIsTelnetMigrated_EmptyVerifiedConfig(t *testing.T) {
|
|
m := &Manager{ServerURL: "http://example:8000"}
|
|
|
|
summary := &MigrationSummary{} // TelnetVerifiedConfig empty
|
|
|
|
if m.isTelnetMigrated(summary) {
|
|
t.Error("isTelnetMigrated = true, want false when TelnetVerifiedConfig is empty")
|
|
}
|
|
}
|
|
|
|
// TestCheckIsMigrated_TelnetOnlyMigratedDevice covers the gap that motivated
|
|
// this iteration: SSH is unreachable, but the speaker has been pointed at
|
|
// our service via telnet (e.g. a firmware that refuses USB unlock). The
|
|
// migration UI must still report IsMigrated: true.
|
|
func TestCheckIsMigrated_TelnetOnlyMigratedDevice(t *testing.T) {
|
|
m := &Manager{ServerURL: "http://example:8000"}
|
|
|
|
summary := &MigrationSummary{
|
|
SSHSuccess: false,
|
|
TelnetVerifiedConfig: "margeServerUrl=http://example:8000\n",
|
|
}
|
|
|
|
m.checkIsMigrated(summary, "192.0.2.1")
|
|
|
|
if !summary.IsMigrated {
|
|
t.Error("IsMigrated = false, want true on a telnet-only migrated device with no SSH")
|
|
}
|
|
}
|
|
|
|
// TestCheckIsMigrated_NoTelnetNoSSH ensures we don't false-positive when
|
|
// neither transport sees the redirect.
|
|
func TestCheckIsMigrated_NoTelnetNoSSH(t *testing.T) {
|
|
m := &Manager{ServerURL: "http://example:8000"}
|
|
|
|
summary := &MigrationSummary{
|
|
SSHSuccess: false,
|
|
TelnetVerifiedConfig: "", // probe failed
|
|
}
|
|
|
|
m.checkIsMigrated(summary, "192.0.2.1")
|
|
|
|
if summary.IsMigrated {
|
|
t.Error("IsMigrated = true, want false when neither SSH nor telnet sees the redirect")
|
|
}
|
|
}
|
|
|
|
// TestCheckIsMigrated_PerAxisBooleansArePopulated locks in that each
|
|
// axis is reported individually so the UI can show partial-state cells.
|
|
// The mock SSH client claims /etc/hosts has Bose redirects; XML is
|
|
// unmigrated; resolv has no marker; telnet sees the redirected URL.
|
|
// All four axis flags must reflect their independent verdicts and
|
|
// IsMigrated must be the OR.
|
|
func TestCheckIsMigrated_PerAxisBooleansArePopulated(t *testing.T) {
|
|
m := &Manager{
|
|
ServerURL: "http://example:8000",
|
|
NewSSH: func(string) SSHClient {
|
|
return &mockSSH{
|
|
runFunc: func(cmd string) (string, error) {
|
|
if cmd == "cat /etc/hosts" {
|
|
return "192.0.2.1\tstreaming.bose.com\n", nil
|
|
}
|
|
return "", errors.New("not implemented in this mock")
|
|
},
|
|
}
|
|
},
|
|
}
|
|
|
|
summary := &MigrationSummary{
|
|
SSHSuccess: true,
|
|
CACertTrusted: true, // hosts migration requires CA trust
|
|
ParsedCurrentConfig: &PrivateCfg{
|
|
MargeServerUrl: "https://streaming.bose.com",
|
|
},
|
|
TelnetVerifiedConfig: "margeServerUrl=http://example:8000\n",
|
|
CurrentResolvConf: "nameserver 8.8.8.8\n",
|
|
}
|
|
|
|
m.checkIsMigrated(summary, "192.0.2.1")
|
|
|
|
if !summary.TelnetMigrated {
|
|
t.Error("TelnetMigrated = false, want true (verified config points at example)")
|
|
}
|
|
|
|
if summary.XMLMigrated {
|
|
t.Error("XMLMigrated = true, want false (parsed XML still points at streaming.bose.com)")
|
|
}
|
|
|
|
if !summary.HostsMigrated {
|
|
t.Error("HostsMigrated = false, want true (mock hosts content has Bose redirect + CA trusted)")
|
|
}
|
|
|
|
if summary.ResolvMigrated {
|
|
t.Error("ResolvMigrated = true, want false (no marker, no example hostname)")
|
|
}
|
|
|
|
if !summary.IsMigrated {
|
|
t.Error("IsMigrated = false, want true (TelnetMigrated || HostsMigrated)")
|
|
}
|
|
}
|
|
|
|
// TestCheckIsMigrated_TelnetSeesOriginalSSHSeesOriginal ensures we don't
|
|
// false-positive when both transports report unmigrated state.
|
|
func TestCheckIsMigrated_TelnetSeesOriginalSSHSeesOriginal(t *testing.T) {
|
|
m := &Manager{
|
|
ServerURL: "http://example:8000",
|
|
NewSSH: func(string) SSHClient {
|
|
return &mockSSH{runFunc: func(string) (string, error) { return "", errors.New("file not found") }}
|
|
},
|
|
}
|
|
|
|
summary := &MigrationSummary{
|
|
SSHSuccess: true,
|
|
TelnetVerifiedConfig: "margeServerUrl=https://streaming.bose.com\n",
|
|
ParsedCurrentConfig: &PrivateCfg{
|
|
MargeServerUrl: "https://streaming.bose.com",
|
|
},
|
|
CurrentResolvConf: "nameserver 8.8.8.8\n",
|
|
}
|
|
|
|
m.checkIsMigrated(summary, "192.0.2.1")
|
|
|
|
if summary.IsMigrated {
|
|
t.Error("IsMigrated = true, want false when both SSH and telnet see the original cloud URLs")
|
|
}
|
|
}
|