Ctrl K
ComunidadGuías…

internal/store/postgres/dialog_snapshot_hash_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"
)

func TestChannelDialogSnapshotHashTracksDependenciesWithoutWideHeaders(t *testing.T) {
	pool := testPool(t)
	ctx := context.Background()
	suffix := randomSuffix(t)

	owner, err := NewUserStore(pool).Create(ctx, domain.User{
		AccessHash: 51,
		Phone:      "+1778" + suffix + "01",
		FirstName:  "SnapshotHashOwner",
	})
	if err != nil {
		t.Fatalf("create owner: %v", err)
	}
	created, err := NewChannelStore(pool).CreateChannel(ctx, domain.CreateChannelRequest{
		CreatorUserID: owner.ID,
		Title:         "Snapshot Hash " + suffix,
		Megagroup:     true,
		Date:          1700000600,
	})
	if err != nil {
		t.Fatalf("create channel: %v", err)
	}
	channelID := created.Channel.ID
	t.Cleanup(func() {
		_, _ = pool.Exec(ctx, "DELETE FROM channels WHERE id = $1", channelID)
		_, _ = pool.Exec(ctx, "DELETE FROM users WHERE id = $1", owner.ID)
	})

	channels := NewChannelStore(pool)
	load := func() domain.ChannelDialogList {
		t.Helper()
		list, err := channels.ListChannelDialogSnapshotHeaders(ctx, owner.ID, domain.DialogFilter{})
		if err != nil {
			t.Fatalf("list snapshot headers: %v", err)
		}
		if len(list.Dialogs) != 1 || list.Hash == 0 {
			t.Fatalf("snapshot = %+v, want one dialog and non-zero hash", list)
		}
		dialog := list.Dialogs[0]
		if dialog.Peer.ID != channelID || dialog.TopMessage == 0 || dialog.TopMessageDate == 0 {
			t.Fatalf("ordering header = %+v, want peer/top/date", dialog)
		}
		if dialog.ReadInboxMaxID != 0 || dialog.ReadOutboxMaxID != 0 || dialog.UnreadCount != 0 ||
			dialog.UnreadMentions != 0 || dialog.UnreadReactions != 0 || dialog.Pts != 0 {
			t.Fatalf("snapshot header retained mutable hydration fields: %+v", dialog)
		}
		return list
	}

	before := load()
	changed, err := channels.SetChannelDialogUnreadMark(ctx, owner.ID, channelID, true)
	if err != nil || !changed {
		t.Fatalf("set unread mark = %v, %v", changed, err)
	}
	afterOwnerState := load()
	if afterOwnerState.Hash == before.Hash {
		t.Fatalf("owner-local dependency hash stayed %d after unread mark", before.Hash)
	}
	if afterOwnerState.Dialogs[0].TopMessage != before.Dialogs[0].TopMessage ||
		afterOwnerState.Dialogs[0].TopMessageDate != before.Dialogs[0].TopMessageDate {
		t.Fatalf("unread mark changed ordering header: before=%+v after=%+v", before.Dialogs[0], afterOwnerState.Dialogs[0])
	}

	if _, err := pool.Exec(ctx, "UPDATE channels SET title = title || ' changed' WHERE id = $1", channelID); err != nil {
		t.Fatalf("update channel title: %v", err)
	}
	afterSharedState := load()
	if afterSharedState.Hash == afterOwnerState.Hash {
		t.Fatalf("shared channel dependency hash stayed %d after channel-base change", afterOwnerState.Hash)
	}
}

func TestPrivateDialogSnapshotHashTracksDraftDependency(t *testing.T) {
	pool := testPool(t)
	ctx := context.Background()
	suffix := randomSuffix(t)
	users := NewUserStore(pool)
	owner, err := users.Create(ctx, domain.User{
		AccessHash: 52,
		Phone:      "+1778" + suffix + "02",
		FirstName:  "PrivateSnapshotOwner",
	})
	if err != nil {
		t.Fatalf("create owner: %v", err)
	}
	peer, err := users.Create(ctx, domain.User{
		AccessHash: 53,
		Phone:      "+1778" + suffix + "03",
		FirstName:  "PrivateSnapshotPeer",
	})
	if err != nil {
		t.Fatalf("create peer: %v", err)
	}
	t.Cleanup(func() {
		_, _ = pool.Exec(ctx, "DELETE FROM users WHERE id = ANY($1::bigint[])", []int64{owner.ID, peer.ID})
	})

	dialogs := NewDialogStore(pool)
	dialogPeer := domain.Peer{Type: domain.PeerTypeUser, ID: peer.ID}
	if err := dialogs.Upsert(ctx, owner.ID, domain.Dialog{
		Peer:           dialogPeer,
		TopMessage:     7,
		TopMessageDate: 1700000610,
	}); err != nil {
		t.Fatalf("upsert dialog: %v", err)
	}
	before, err := dialogs.ListDialogSnapshotHeaders(ctx, owner.ID, domain.DialogFilter{})
	if err != nil {
		t.Fatalf("list snapshot before draft: %v", err)
	}
	if len(before.Dialogs) != 1 || before.Hash == 0 {
		t.Fatalf("snapshot before draft = %+v", before)
	}
	if err := dialogs.SaveDraft(ctx, owner.ID, domain.DialogDraft{
		Peer:    dialogPeer,
		Date:    1700000611,
		Message: "draft changes hash without changing ordering",
	}); err != nil {
		t.Fatalf("save draft: %v", err)
	}
	after, err := dialogs.ListDialogSnapshotHeaders(ctx, owner.ID, domain.DialogFilter{})
	if err != nil {
		t.Fatalf("list snapshot after draft: %v", err)
	}
	if after.Hash == before.Hash {
		t.Fatalf("private snapshot hash stayed %d after draft change", before.Hash)
	}
	if after.Dialogs[0].TopMessage != before.Dialogs[0].TopMessage || after.Dialogs[0].TopMessageDate != before.Dialogs[0].TopMessageDate {
		t.Fatalf("draft changed ordering header: before=%+v after=%+v", before.Dialogs[0], after.Dialogs[0])
	}
}

func TestPrivateDialogAllBuiltinSnapshotIncludesMainAndArchive(t *testing.T) {
	pool := testPool(t)
	ctx := context.Background()
	suffix := randomSuffix(t)
	users := NewUserStore(pool)
	owner, err := users.Create(ctx, domain.User{AccessHash: 61, Phone: "+1778" + suffix + "11", FirstName: "AllFolderOwner"})
	if err != nil {
		t.Fatal(err)
	}
	mainPeer, err := users.Create(ctx, domain.User{AccessHash: 62, Phone: "+1778" + suffix + "12", FirstName: "MainPeer"})
	if err != nil {
		t.Fatal(err)
	}
	archivePeer, err := users.Create(ctx, domain.User{AccessHash: 63, Phone: "+1778" + suffix + "13", FirstName: "ArchivePeer"})
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() {
		_, _ = pool.Exec(ctx, "DELETE FROM users WHERE id = ANY($1::bigint[])", []int64{owner.ID, mainPeer.ID, archivePeer.ID})
	})
	dialogs := NewDialogStore(pool)
	for index, peer := range []int64{mainPeer.ID, archivePeer.ID} {
		if err := dialogs.Upsert(ctx, owner.ID, domain.Dialog{
			Peer:       domain.Peer{Type: domain.PeerTypeUser, ID: peer},
			TopMessage: 10 + index, TopMessageDate: 1700000700 + index,
		}); err != nil {
			t.Fatal(err)
		}
	}
	if err := dialogs.EditPeerFolders(ctx, owner.ID, []domain.FolderPeerUpdate{{
		Peer: domain.Peer{Type: domain.PeerTypeUser, ID: archivePeer.ID}, FolderID: domain.DialogArchiveFolderID,
	}}); err != nil {
		t.Fatal(err)
	}
	all, err := dialogs.ListAllBuiltinDialogSnapshotHeaders(ctx, owner.ID)
	if err != nil {
		t.Fatal(err)
	}
	if len(all.Dialogs) != 2 {
		t.Fatalf("all built-in private dialogs = %+v", all.Dialogs)
	}
	folders := map[int64]int{}
	for _, dialog := range all.Dialogs {
		folders[dialog.Peer.ID] = dialog.FolderID
	}
	if folders[mainPeer.ID] != domain.DialogMainFolderID || folders[archivePeer.ID] != domain.DialogArchiveFolderID {
		t.Fatalf("all built-in private folders = %#v", folders)
	}
}