package feed import ( "context" "errors" "io" "log/slog" "testing" "time" "tangled.org/core/knotfeed" ) func TestFeedRefcountsAndReleasesSubscriptions(t *testing.T) { entered := make(chan string, 8) held := make(chan struct{}) f := New(slog.New(slog.NewTextHandler(io.Discard, nil)), Hooks{ LoadCursor: func(ctx context.Context, knot string) (knotfeed.Cursor, error) { select { case entered <- knot: case <-ctx.Done(): return knotfeed.Cursor{}, ctx.Err() } select { case <-held: case <-ctx.Done(): } return knotfeed.Cursor{}, errors.New("no network in tests") }, }) ctx, cancel := context.WithCancel(context.Background()) defer cancel() const knot = "knot.nel.pet" f.Subscribe(ctx, knot) f.Subscribe(ctx, knot) select { case got := <-entered: if got != knot { t.Fatalf("first session loaded the cursor for %q, want %q", got, knot) } case <-time.After(2 * time.Second): t.Fatal("no session started for a subscribed knot") } f.Unsubscribe(knot) f.Unsubscribe(knot) close(held) f.Subscribe(ctx, knot) select { case got := <-entered: if got != knot { t.Fatalf("second session loaded the cursor for %q, want %q", got, knot) } case <-time.After(2 * time.Second): t.Fatalf("a fresh session didn't start after the knot was released and resubscribed") } } func TestFeedRejectsUnsubscribableHost(t *testing.T) { entered := make(chan string, 1) f := New(slog.New(slog.NewTextHandler(io.Discard, nil)), Hooks{ LoadCursor: func(ctx context.Context, knot string) (knotfeed.Cursor, error) { entered <- knot return knotfeed.Cursor{}, errors.New("no network in tests") }, }) ctx, cancel := context.WithCancel(context.Background()) defer cancel() f.Subscribe(ctx, "192.0.2.1") f.Unsubscribe("192.0.2.1") select { case knot := <-entered: t.Fatalf("a session started for an unparsable host %q", knot) case <-time.After(100 * time.Millisecond): } }