package members_test import ( "context" "testing" "galo/internal/albums" "galo/internal/members" "galo/internal/models" "galo/internal/sse" ) // Accepting an invite gives the invitee album.created with the album object and // tells everyone already in the album that the member count changed. func TestAcceptInvitePublishesAlbumEvents(t *testing.T) { ctx := context.Background() st := newStack(t) owner := seedUser(t, st, "Owner") invitee := seedUser(t, st, "Invitee") album, err := st.albums.Create(ctx, owner, albums.CreateInput{Title: "Trip"}) if err != nil { t.Fatalf("create album: %v", err) } inv, err := st.svc.CreateInvite(ctx, album.ID, owner, members.CreateInviteInput{Role: "member", MaxUses: 1}) if err != nil { t.Fatalf("create invite: %v", err) } inviteeSub := st.hub.SubscribeUser(invitee) defer inviteeSub.Close() ownerSub := st.hub.SubscribeUser(owner) defer ownerSub.Close() if _, err := st.svc.Accept(ctx, inv.Token, invitee); err != nil { t.Fatalf("accept: %v", err) } ev := nextEvent(t, inviteeSub) if ev.Type != "album.created" { t.Fatalf("invitee event = %q, want album.created", ev.Type) } invitedAlbum, ok := ev.Data.(*models.Album) if !ok || invitedAlbum.ID != album.ID || invitedAlbum.MembersCount != 1 { t.Fatalf("invitee payload = %#v", ev.Data) } assertNoEvent(t, inviteeSub) ownerEv := nextEvent(t, ownerSub) if ownerEv.Type != "album.updated" { t.Fatalf("owner event = %q, want album.updated", ownerEv.Type) } ownerAlbum, ok := ownerEv.Data.(*models.Album) if !ok || ownerAlbum.MembersCount != 1 { t.Fatalf("owner payload = %#v", ownerEv.Data) } assertNoEvent(t, ownerSub) } // Changing a member's role notifies the owner, the remaining members and the // user whose role changed. func TestChangeRolePublishesAlbumUpdated(t *testing.T) { ctx := context.Background() st := newStack(t) owner := seedUser(t, st, "Owner") target := seedUser(t, st, "Target") album, err := st.albums.Create(ctx, owner, albums.CreateInput{Title: "Trip"}) if err != nil { t.Fatalf("create album: %v", err) } if err := st.repos.Members.Add(ctx, album.ID, target, "member", &owner); err != nil { t.Fatalf("add member: %v", err) } ownerSub := st.hub.SubscribeUser(owner) defer ownerSub.Close() targetSub := st.hub.SubscribeUser(target) defer targetSub.Close() if err := st.svc.ChangeRole(ctx, album.ID, owner, target, "editor"); err != nil { t.Fatalf("change role: %v", err) } for name, sub := range map[string]*sse.Subscription{"owner": ownerSub, "target": targetSub} { ev := nextEvent(t, sub) if ev.Type != "album.updated" { t.Fatalf("%s event = %q, want album.updated", name, ev.Type) } if _, ok := ev.Data.(*models.Album); !ok { t.Fatalf("%s payload type = %T, want *models.Album", name, ev.Data) } } } // Removing a member tells those who remain that the count changed, and sends // the removed member album.deleted carrying only the id. func TestRemoveMemberPublishesUpdatedAndDeleted(t *testing.T) { ctx := context.Background() st := newStack(t) owner := seedUser(t, st, "Owner") member := seedUser(t, st, "Member") album, err := st.albums.Create(ctx, owner, albums.CreateInput{Title: "Trip"}) if err != nil { t.Fatalf("create album: %v", err) } if err := st.repos.Members.Add(ctx, album.ID, member, "member", &owner); err != nil { t.Fatalf("add member: %v", err) } ownerSub := st.hub.SubscribeUser(owner) defer ownerSub.Close() memberSub := st.hub.SubscribeUser(member) defer memberSub.Close() if err := st.svc.Remove(ctx, album.ID, owner, member); err != nil { t.Fatalf("remove: %v", err) } ownerEv := nextEvent(t, ownerSub) if ownerEv.Type != "album.updated" { t.Fatalf("owner event = %q, want album.updated", ownerEv.Type) } if a, ok := ownerEv.Data.(*models.Album); !ok || a.MembersCount != 0 { t.Fatalf("owner payload = %#v", ownerEv.Data) } memberEv := nextEvent(t, memberSub) if memberEv.Type != "album.deleted" { t.Fatalf("member event = %q, want album.deleted", memberEv.Type) } if _, isAlbum := memberEv.Data.(*models.Album); isAlbum { t.Fatalf("member payload carried an album object") } payload, ok := memberEv.Data.(map[string]string) if !ok || payload["id"] != album.ID { t.Fatalf("member payload = %#v", memberEv.Data) } assertNoEvent(t, memberSub) }