package setup import ( "errors" "io" "net/http" "strings" "testing" ) // inspectFakes wires canned XML bodies into Manager.HTTPGet keyed by URL // path. A missing path returns 404; an empty-string body returns the // supplied err. type inspectFakes struct { responses map[string]string errs map[string]error } func (f *inspectFakes) get(url string) (*http.Response, error) { for path, body := range f.responses { if strings.HasSuffix(url, path) { if e := f.errs[path]; e != nil { return nil, e } return &http.Response{ StatusCode: 200, Body: io.NopCloser(strings.NewReader(body)), Header: http.Header{}, }, nil } } return &http.Response{ StatusCode: 404, Body: io.NopCloser(strings.NewReader("not found")), Header: http.Header{}, }, nil } func TestInspect_HappyPath(t *testing.T) { f := &inspectFakes{ responses: map[string]string{ "/info": ` Bose SoundTouch DE4803 SoundTouch 10 1234567 http://aftertouch.local:8000 SCM 27.0.6 F23456789012 `, "/networkInfo": ` `, "/sources": ``, "/presets": `1LIVE`, }, } m := &Manager{HTTPGet: f.get} r := m.Inspect("192.0.2.42", InspectOptions{}) if r.InfoErr != nil { t.Errorf("InfoErr = %v, want nil", r.InfoErr) } if r.Info == nil || r.Info.DeviceID != "506583DE4803" { t.Errorf("Info.DeviceID = %v, want 506583DE4803", r.Info) } if r.Info.MargeAccountUUID != "1234567" { t.Errorf("MargeAccountUUID = %q, want 1234567", r.Info.MargeAccountUUID) } if r.Network == nil || len(r.Network.Interfaces.Interfaces) == 0 { t.Fatalf("Network parse failed: %v / %v", r.Network, r.NetworkErr) } wifi := r.Network.Interfaces.Interfaces[0] if wifi.SSID != "MyHomeNetwork" { t.Errorf("SSID = %q, want MyHomeNetwork", wifi.SSID) } if r.Sources == nil || len(r.Sources.SourceItem) != 2 { t.Errorf("Sources = %v, want 2 entries", r.Sources) } if r.Presets == nil || len(r.Presets.Presets) != 1 { t.Errorf("Presets = %v, want 1 preset", r.Presets) } if r.Presets.Presets[0].ContentItem.ItemName != "1LIVE" { t.Errorf("preset name = %q, want 1LIVE", r.Presets.Presets[0].ContentItem.ItemName) } } func TestInspect_PartialFailureRecordsPerSectionErrors(t *testing.T) { // /info ok, /presets returns network error — the rest of the report // must still populate. f := &inspectFakes{ responses: map[string]string{ "/info": `n`, "/networkInfo": ``, "/sources": ``, "/presets": "", // body unused — errs map below triggers error }, errs: map[string]error{ "/presets": errors.New("connection reset"), }, } m := &Manager{HTTPGet: f.get} r := m.Inspect("192.0.2.42", InspectOptions{}) if r.InfoErr != nil { t.Errorf("InfoErr = %v, want nil", r.InfoErr) } if r.PresetsErr == nil { t.Error("expected PresetsErr to be populated") } if r.Sources == nil { t.Error("Sources should still populate despite PresetsErr") } } func TestInspect_TelnetRuntimeURLs(t *testing.T) { f := &inspectFakes{ responses: map[string]string{ "/info": `n`, }, } tn := &fakeTelnet{ responses: map[string]string{ "getpdo CurrentSystemConfiguration": "margeServerUrl: http://aftertouch.local:8000\nstatsServerUrl: http://aftertouch.local:8000\n", }, } m := &Manager{ HTTPGet: f.get, NewTelnet: func(string) TelnetClient { return tn }, } r := m.Inspect("192.0.2.42", InspectOptions{IncludeTelnet: true}) if r.RuntimeErr != nil { t.Errorf("RuntimeErr = %v, want nil", r.RuntimeErr) } if !strings.Contains(r.RuntimeURLs, "margeServerUrl") { t.Errorf("RuntimeURLs missing expected content: %q", r.RuntimeURLs) } } func TestInspect_TelnetSkippedWhenOptionDisabled(t *testing.T) { f := &inspectFakes{ responses: map[string]string{ "/info": `n`, }, } m := &Manager{HTTPGet: f.get} r := m.Inspect("192.0.2.42", InspectOptions{IncludeTelnet: false}) if r.RuntimeURLs != "" || r.RuntimeErr != nil { t.Errorf("telnet runtime fields should be zero when IncludeTelnet=false, got %q / %v", r.RuntimeURLs, r.RuntimeErr) } }