diff --git a/controller/internal/web/r1060_plex_by_address_test.go b/controller/internal/web/r1060_plex_by_address_test.go new file mode 100644 index 0000000..ac46bf5 --- /dev/null +++ b/controller/internal/web/r1060_plex_by_address_test.go @@ -0,0 +1,67 @@ +package web + +import ( + "context" + "net" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "gitea.dooplex.hu/admin/felhom-controller/internal/mediawire" +) + +// fakePlex answers as Plex does (measured on demo-hp 9201, 2026-10-15): a Host that is not an address is „non-local", +// so the claim gets 401; by address the claim is taken (200 here — the real one asks plex.tv). The test client dials +// this server whatever the URL names, so the only difference between the two calls is the Host header. +func fakePlex(t *testing.T) (hosts *[]string) { + t.Helper() + var seen []string + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + seen = append(seen, r.Host) + h, _, err := net.SplitHostPort(r.Host) + if err != nil { + h = r.Host + } + local := net.ParseIP(h) != nil + switch r.URL.Path { + case "/myplex/claim": + if !local { + w.WriteHeader(http.StatusUnauthorized) + return + } + w.WriteHeader(http.StatusOK) + case "/identity": + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write([]byte(`{"MediaContainer":{"claimed":` + map[bool]string{true: "true", false: "false"}[local] + `}}`)) + default: + w.WriteHeader(http.StatusNotFound) + } + })) + t.Cleanup(srv.Close) + oldHTTP, oldLookup := plexHTTP, mediawire.PlexLookup + plexHTTP = &http.Client{Transport: &http.Transport{DialContext: func(ctx context.Context, network, _ string) (net.Conn, error) { + return (&net.Dialer{}).DialContext(ctx, network, srv.Listener.Addr().String()) + }}} + mediawire.PlexLookup = func(context.Context) ([]net.IPAddr, error) { return []net.IPAddr{{IP: net.ParseIP("10.9.8.7")}}, nil } + t.Cleanup(func() { plexHTTP, mediawire.PlexLookup = oldHTTP, oldLookup }) + return &seen +} + +// R-1060 — the household's claim reaches Plex BY ADDRESS, so Plex takes it as local; the identity call too. +// COMPANION RED-PROOF: make mediawire.PlexURL return "http://plex:" (today's call) → 401 and this fails. +func TestR1060_TheClaimReachesPlexByAddress(t *testing.T) { + hosts := fakePlex(t) + code, err := plexClaim("claim-felhomtestcode0000") + if err != nil || code != http.StatusOK { + t.Fatalf("claim → %d (%v); Plex refuses the name „plex” as non-local — the box must call it by address", code, err) + } + if !plexClaimed() { + t.Fatal("the identity call did not reach Plex as local") + } + for _, h := range *hosts { + if !strings.HasPrefix(h, "10.9.8.7:") { + t.Errorf("a call to Plex carried Host %q, not its address", h) + } + } +}