oficina / meet Public

Clone
git clone https://amadan.net/oficina/meet

Plain git — no account needed to clone.

Download

Download this file

1package hub
2
3import (
4 "context"
5 "errors"
6 "io"
7 "log/slog"
8 "testing"
9 "time"
10)
11
12func TestAuthorizeIsTheAdmittedParticipationRule(t *testing.T) {
13 now := time.Date(2026, 9, 10, 9, 0, 0, 0, time.UTC)
14 h := testHub(&now)
15 ctx := context.Background()
16 a, _ := h.Open("r1", "sa", 1, "Ann", KindMember)
17 if err := h.Authorize(ctx, "r1", "sa", a.Peer); !errors.Is(err, ErrNotAdmitted) {
18 t.Fatalf("unjoined: want ErrNotAdmitted, got %v", err)
19 }
20 if err := h.Join(ctx, "r1", "sa", a.Peer); err != nil {
21 t.Fatal(err)
22 }
23 if err := h.Authorize(ctx, "r1", "sa", a.Peer); err != nil {
24 t.Fatalf("admitted member: %v", err)
25 }
26 if err := h.Authorize(ctx, "r1", "sb", a.Peer); !errors.Is(err, ErrUnknownPeer) {
27 t.Fatalf("another session: want ErrUnknownPeer, got %v", err)
28 }
29 if err := h.Authorize(ctx, "r2", "sa", a.Peer); !errors.Is(err, ErrUnknownPeer) {
30 t.Fatalf("another room: want ErrUnknownPeer, got %v", err)
31 }
32 // personID 100 is testHub's own guest threshold (personID < 100 is a
33 // member, as TestMemberJoinsAndGuestWaits in admission_test.go
34 // already relies on) — a personID of 2 here would derive as a
35 // member and be admitted outright, proving nothing about a waiting
36 // guest.
37 g, _ := h.Open("r1", "sg", 100, "Gus", KindGuest)
38 h.Join(ctx, "r1", "sg", g.Peer)
39 if err := h.Authorize(ctx, "r1", "sg", g.Peer); !errors.Is(err, ErrNotAdmitted) {
40 t.Fatalf("waiting guest: want ErrNotAdmitted, got %v", err)
41 }
42}
43
44// TestAuthorizeDropsAMemberWhoseStandingIsGoneAndKeepsAnAdmittedGuest is
45// §15.12 through Authorize, mirroring admission_test.go's
46// TestJoinDropsAndAnnouncesAMemberWhoLostStanding: standing is a
47// mutable map keyed on personID, moved without a tick running, so the
48// only thing that could have refused the member is Authorize's own
49// re-derivation. Bob is admitted as a guest (personID 100, testHub's
50// own guest threshold) before his grant "expires" — ruling 14 says
51// Authorize never even *asks* for a guest, which is asserted directly
52// by counting StandingFor calls: standingLostLocked's own admitted-
53// guest guard would still make the *outcome* (nil, participation kept)
54// look right even if memberStandingGone's early return for a
55// non-member kind were deleted and it called StandingFor for Bob
56// anyway — so the outcome alone does not discriminate that mutation.
57// The call count does.
58func TestAuthorizeDropsAMemberWhoseStandingIsGoneAndKeepsAnAdmittedGuest(t *testing.T) {
59 now := time.Date(2026, 9, 10, 9, 0, 0, 0, time.UTC)
60 standing := map[int64]bool{1: true, 100: true}
61 guestStandingCalls := 0
62 h := New(Config{
63 Now: func() time.Time { return now },
64 Logger: slog.New(slog.NewTextHandler(io.Discard, nil)),
65 StandingFor: func(ctx context.Context, room string, id int64) (Kind, bool, error) {
66 if id == 100 {
67 guestStandingCalls++
68 return KindGuest, standing[id], nil
69 }
70 return KindMember, standing[id], nil
71 },
72 })
73 ctx := context.Background()
74 a, _ := h.Open("r1", "sa", 1, "Ann", KindMember)
75 if err := h.Join(ctx, "r1", "sa", a.Peer); err != nil {
76 t.Fatal(err)
77 }
78 b, _ := h.Open("r1", "sb", 100, "Bob", KindGuest)
79 if err := h.Join(ctx, "r1", "sb", b.Peer); err != nil {
80 t.Fatal(err)
81 }
82 if err := h.Admit(ctx, "r1", "sa", a.Peer, b.Peer); err != nil {
83 t.Fatal(err)
84 }
85 drain(a.Sub)
86 drain(b.Sub)
87
88 standing[1] = false // Ann taken off the team, no tick has run
89 if err := h.Authorize(ctx, "r1", "sa", a.Peer); !errors.Is(err, ErrNotYours) {
90 t.Fatalf("member whose standing is gone: want ErrNotYours, got %v", err)
91 }
92 if _, found := h.Find("r1", "sa", a.Peer); found {
93 t.Fatal("Ann's participation should have ended")
94 }
95 bev := drain(b.Sub)
96 if len(bev) == 0 || bev[len(bev)-1].Type != TypeGone || bev[len(bev)-1].From != a.Peer {
97 t.Fatalf("Bob's stream got %v, want gone naming Ann last", types(bev))
98 }
99
100 standing[100] = false // Bob's grant has "expired"
101 before := guestStandingCalls
102 if err := h.Authorize(ctx, "r1", "sb", b.Peer); err != nil {
103 t.Fatalf("admitted guest with a lapsed grant: %v", err)
104 }
105 if guestStandingCalls != before {
106 t.Fatalf("Authorize asked StandingFor for a guest: %d calls during this Authorize, want 0", guestStandingCalls-before)
107 }
108}
109