//go:build integration package social import ( "context" "os" "testing" "github.com/google/uuid" "github.com/stretchr/testify/require" "pipu/api/internal/api/gen" "pipu/api/internal/platform/db" ) func TestPresenceAndOfflineInvitations(t *testing.T) { url := os.Getenv("TEST_DATABASE_URL") if url == "" { t.Skip("TEST_DATABASE_URL is not set") } ctx := context.Background() pool, err := db.Connect(ctx, url) require.NoError(t, err) defer pool.Close() require.NoError(t, db.Migrate(ctx, pool)) s := &Store{pool: pool} a, b, other := uuid.New(), uuid.New(), uuid.New() ids := []uuid.UUID{a, b, other} for _, id := range ids { _, err = pool.Exec(ctx, `INSERT INTO users(id,username,password_hash,listening_requests) VALUES($1,$2,'x','everyone')`, id, id.String()) require.NoError(t, err) } defer pool.Exec(ctx, `DELETE FROM users WHERE id=ANY($1)`, ids) require.NoError(t, s.action(ctx, a, gen.SocialAction{Action: "request", TargetId: b})) require.NoError(t, s.action(ctx, b, gen.SocialAction{Action: "accept", TargetId: a})) require.NoError(t, s.markPresent(ctx, a)) inbox, err := s.inbox(ctx, a) require.NoError(t, err) require.False(t, inbox.People[0].Online) // Reject before creating a room, even if an invite bypasses the UI. require.ErrorContains(t, s.listeningAction(ctx, a, gen.ListeningAction{Id: uuid.New(), Action: "invite", TargetId: b}), "offline") require.NoError(t, s.markPresent(ctx, b)) inbox, err = s.inbox(ctx, a) require.NoError(t, err) require.True(t, inbox.People[0].Online, "online must work with hidden music and paused playback") require.Nil(t, inbox.People[0].Activity) found, err := s.people(ctx, other, b.String()) require.NoError(t, err) require.Len(t, found, 1) require.False(t, found[0].Online, "non-friends cannot discover presence") _, err = pool.Exec(ctx, `UPDATE users SET social_seen_at=now()-interval '46 seconds' WHERE id=$1`, b) require.NoError(t, err) inbox, err = s.inbox(ctx, a) require.NoError(t, err) require.False(t, inbox.People[0].Online) // Looking at a person's inbox must not revive that person's presence. require.ErrorContains(t, s.listeningAction(ctx, a, gen.ListeningAction{Id: uuid.New(), Action: "join", TargetId: b}), "offline") require.NoError(t, s.markPresent(ctx, b)) require.NoError(t, s.action(ctx, a, gen.SocialAction{Action: "block", TargetId: b})) inbox, err = s.inbox(ctx, a) require.NoError(t, err) require.False(t, inbox.People[0].Online, "blocking hides online status") }