package web import ( "fmt" "reflect" "sort" "testing" ) func sortedWatchIDs(c *wsClient) []string { out := make([]string, 0, len(c.watchIDs)) for id := range c.watchIDs { out = append(out, id) } sort.Strings(out) return out } func TestApplyConnectWatchMulti(t *testing.T) { c := &wsClient{watchIDs: make(map[string]struct{})} if stopped, tooMany := applyConnectWatch(c, "a", true); len(stopped) != 0 || tooMany { t.Fatalf("first connect = (%v, %v), want ([], false)", stopped, tooMany) } if stopped, tooMany := applyConnectWatch(c, "b", true); len(stopped) != 0 || tooMany { t.Fatalf("second connect = (%v, %v), want ([], false)", stopped, tooMany) } if got, want := sortedWatchIDs(c), []string{"a", "b"}; !reflect.DeepEqual(got, want) { t.Fatalf("watch set = %v, want %v", got, want) } // Repeated connect (focus switch) must be a no-op. if stopped, tooMany := applyConnectWatch(c, "a", true); len(stopped) != 0 || tooMany { t.Fatalf("repeat connect = (%v, %v), want ([], false)", stopped, tooMany) } if got, want := sortedWatchIDs(c), []string{"a", "b"}; !reflect.DeepEqual(got, want) { t.Fatalf("watch set after repeat = %v, want %v", got, want) } } func TestApplyConnectWatchLegacyReplaces(t *testing.T) { c := &wsClient{watchIDs: map[string]struct{}{"a": {}, "b": {}}} stopped, tooMany := applyConnectWatch(c, "c", false) if tooMany { t.Fatal("legacy connect hit the cap, want not") } sort.Strings(stopped) if want := []string{"a", "b"}; !reflect.DeepEqual(stopped, want) { t.Fatalf("stopped = %v, want %v", stopped, want) } if got, want := sortedWatchIDs(c), []string{"c"}; !reflect.DeepEqual(got, want) { t.Fatalf("watch set = %v, want %v", got, want) } } func TestApplyConnectWatchCap(t *testing.T) { c := &wsClient{watchIDs: make(map[string]struct{})} for i := 0; i < maxWatchPerClient; i++ { applyConnectWatch(c, fmt.Sprintf("d%02d", i), true) } if _, tooMany := applyConnectWatch(c, "overflow", true); !tooMany { t.Fatal("expected the cap to reject a new device") } if len(c.watchIDs) != maxWatchPerClient { t.Fatalf("watch set size = %d, want %d", len(c.watchIDs), maxWatchPerClient) } // An already watched device must still be accepted at the cap. if _, tooMany := applyConnectWatch(c, "d00", true); tooMany { t.Fatal("repeat connect at the cap was rejected") } } func TestResolveWatchDevice(t *testing.T) { h := &wsHub{} c := &wsClient{watchIDs: map[string]struct{}{"a": {}}} if got := h.resolveWatchDevice(c, []byte(`{"id":"a"}`)); got != "a" { t.Fatalf("explicit watched id = %q, want a", got) } if got := h.resolveWatchDevice(c, []byte(`{"id":"nope"}`)); got != "" { t.Fatalf("explicit unwatched id = %q, want empty", got) } // Old frontend: no id, exactly one watched device. if got := h.resolveWatchDevice(c, []byte(`{}`)); got != "a" { t.Fatalf("no id, single device = %q, want a", got) } c.watchIDs["b"] = struct{}{} if got := h.resolveWatchDevice(c, []byte(`{}`)); got != "" { t.Fatalf("no id, two devices = %q, want empty", got) } if got := h.resolveWatchDevice(c, []byte(`{"id":"a"}`)); got != "a" { t.Fatalf("explicit id, two devices = %q, want a", got) } }