Ctrl K
ComunidadGuías…

internal/store/postgres/channel_recent_repliers_integration_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package postgres

import (
	"context"
	"testing"

	"telesrv/internal/domain"
)

// TestChannelStoreRecentRepliersPostgres regresses populateChannelMessageReplies: previously it
// only computed Replies/MaxID/RepliesPts and never filled RecentRepliers (always nil), so under
// Postgres (production) the channel post comment entry could not get the "recent replier avatars" —
// while the memory store always filled them, an inconsistency between the two stores. This verifies
// Postgres also backfills by "each replier's latest reply id, newest-first, deduped, top 3",
// matching memory.
func TestChannelStoreRecentRepliersPostgres(t *testing.T) {
	pool := testPool(t) // without TELESRV_TEST_POSTGRES_DSN set this will t.Skip
	ctx := context.Background()
	suffix := randomSuffix(t)

	users := NewUserStore(pool)
	owner, err := users.Create(ctx, domain.User{AccessHash: 61, Phone: "+1779" + suffix + "01", FirstName: "ReplyStatOwner"})
	if err != nil {
		t.Fatalf("create owner: %v", err)
	}
	alice, err := users.Create(ctx, domain.User{AccessHash: 62, Phone: "+1779" + suffix + "02", FirstName: "ReplyStatAlice"})
	if err != nil {
		t.Fatalf("create alice: %v", err)
	}
	bob, err := users.Create(ctx, domain.User{AccessHash: 63, Phone: "+1779" + suffix + "03", FirstName: "ReplyStatBob"})
	if err != nil {
		t.Fatalf("create bob: %v", err)
	}
	var channelID int64
	t.Cleanup(func() {
		if channelID != 0 {
			_, _ = pool.Exec(ctx, "DELETE FROM channels WHERE id = $1", channelID)
		}
		_, _ = pool.Exec(ctx, "DELETE FROM users WHERE id = ANY($1::bigint[])", []int64{owner.ID, alice.ID, bob.ID})
	})

	channels := NewChannelStore(pool)
	created, err := channels.CreateChannel(ctx, domain.CreateChannelRequest{
		CreatorUserID: owner.ID,
		Title:         "Recent Repliers " + suffix,
		Megagroup:     true,
		MemberUserIDs: []int64{alice.ID, bob.ID},
		Date:          1700000800,
	})
	if err != nil {
		t.Fatalf("create channel: %v", err)
	}
	channelID = created.Channel.ID

	root, err := channels.SendChannelMessage(ctx, domain.SendChannelMessageRequest{
		UserID: owner.ID, ChannelID: channelID, RandomID: 9301, Message: "root post", Date: 1700000801,
	})
	if err != nil {
		t.Fatalf("send root: %v", err)
	}
	reply := func(u, rid int64, date int) {
		t.Helper()
		if _, err := channels.SendChannelMessage(ctx, domain.SendChannelMessageRequest{
			UserID: u, ChannelID: channelID, RandomID: rid, Message: "c",
			ReplyTo: &domain.MessageReply{MessageID: root.Message.ID}, Date: date,
		}); err != nil {
			t.Fatalf("reply from %d: %v", u, err)
		}
	}
	reply(alice.ID, 9302, 1700000802) // alice oldest
	reply(bob.ID, 9303, 1700000803)   // bob in the middle
	reply(alice.ID, 9304, 1700000804) // alice newest

	got, err := channels.GetChannelMessages(ctx, owner.ID, channelID, []int{root.Message.ID})
	if err != nil {
		t.Fatalf("get channel messages: %v", err)
	}
	if len(got.Messages) != 1 {
		t.Fatalf("get messages = %d, want 1", len(got.Messages))
	}
	replies := got.Messages[0].Replies
	if replies == nil {
		t.Fatalf("root.Replies == nil, want reply stats")
	}
	if replies.Replies != 3 {
		t.Fatalf("replies count = %d, want 3", replies.Replies)
	}
	// Dedup + newest-first: alice (latest 9304) first, bob (9303) next; alice's older entry
	// (9302) is deduped because alice already appeared, leaving only two distinct repliers.
	want := []domain.Peer{
		{Type: domain.PeerTypeUser, ID: alice.ID},
		{Type: domain.PeerTypeUser, ID: bob.ID},
	}
	if len(replies.RecentRepliers) != len(want) {
		t.Fatalf("recent repliers = %+v, want %+v", replies.RecentRepliers, want)
	}
	for i := range want {
		if replies.RecentRepliers[i] != want[i] {
			t.Fatalf("recent repliers[%d] = %+v, want %+v (full=%+v)", i, replies.RecentRepliers[i], want[i], replies.RecentRepliers)
		}
	}
}