Plex (R-1045): the controller asks Plex itself whether it is claimed — after the claim and on the household's „Kész”; no template probe (an older controller would refuse the press forever)
gates / gates (push) Successful in 45s

Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-15 10:29:47 +02:00
parent 37ffa3beb5
commit 372d6e5994
4 changed files with 68 additions and 1 deletions
@@ -1,6 +1,10 @@
package web
import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
@@ -37,3 +41,34 @@ func TestPlexClaimCodeShape(t *testing.T) {
}
}
}
// R-1045: the household's „Kész" never opens an UNCLAIMED Plex (it answers everything to a private address with no
// token); once Plex says claimed, the press opens it. No template probe is needed (an old controller would refuse the
// press forever with one). COMPANION RED-PROOF: drop the plexClaimed check in appSetupGateOpenHandler → the first press
// opens the gate (200). Restored.
func TestPlexDonePress_RefusedWhileUnclaimed(t *testing.T) {
s := gateHarness(t)
app := filepath.Join(s.cfg.Paths.StacksDir, "gapp")
if err := os.WriteFile(filepath.Join(app, ".felhom.yml"), []byte("display_name: Plex\nslug: plex\nsetup_gate: true\n"), 0o644); err != nil {
t.Fatal(err)
}
if err := s.stackMgr.ScanStacks(); err != nil {
t.Fatal(err)
}
claimed := false
old := plexClaimed
plexClaimed = func() bool { return claimed }
defer func() { plexClaimed = old }()
press := func() int {
w := httptest.NewRecorder()
s.appSetupGateOpenHandler(w, httptest.NewRequest(http.MethodPost, "/apps/plex/setup-gate/open", nil), "plex")
return w.Code
}
if c := press(); c != http.StatusConflict {
t.Fatalf("„Kész” on an unclaimed Plex: HTTP %d, want 409 — the gate must stay closed", c)
}
claimed = true
if c := press(); c != http.StatusOK {
t.Fatalf("„Kész” on a claimed Plex: HTTP %d, want 200", c)
}
}