internal/store/postgres/channel_delete_monoforum_integration_test.go
Rama main · réplica de lectura del repositorio original.
package postgres
import (
"context"
"testing"
"telesrv/internal/domain"
)
// TestDeleteChannelCascadesLinkedMonoforumPostgres regression Risk A: when deleting a parent broadcast
// channel with Direct Messages enabled, the linked monoforum is soft-deleted in the same transaction and returned in the result. Not cascading would leave an orphan mono pointing at the deleted parent channel.
// Gated on TELESRV_TEST_POSTGRES_DSN.
func TestDeleteChannelCascadesLinkedMonoforumPostgres(t *testing.T) {
pool := testPool(t) // an unset DSN makes it t.Skip
ctx := context.Background()
suffix := randomSuffix(t)
users := NewUserStore(pool)
owner, err := users.Create(ctx, domain.User{AccessHash: 91, Phone: "+1778" + suffix + "31", FirstName: "DelMonoOwner"})
if err != nil {
t.Fatalf("create owner: %v", err)
}
var channelIDs []int64
t.Cleanup(func() {
if len(channelIDs) > 0 {
_, _ = pool.Exec(ctx, "DELETE FROM channels WHERE id = ANY($1::bigint[])", channelIDs)
}
_, _ = pool.Exec(ctx, "DELETE FROM users WHERE id = $1", owner.ID)
})
channels := NewChannelStore(pool)
created, err := channels.CreateChannel(ctx, domain.CreateChannelRequest{
CreatorUserID: owner.ID, Title: "Del Mono BC " + suffix, Broadcast: true, Date: 1700000900,
})
if err != nil {
t.Fatalf("create channel: %v", err)
}
parentID := created.Channel.ID
channelIDs = append(channelIDs, parentID)
enabled, err := channels.SetPaidMessagesPrice(ctx, owner.ID, parentID, 0, true)
if err != nil {
t.Fatalf("enable DM: %v", err)
}
monoID := enabled.Channel.LinkedMonoforumID
if monoID == 0 {
t.Fatalf("no monoforum created")
}
channelIDs = append(channelIDs, monoID)
res, err := channels.DeleteChannel(ctx, domain.DeleteChannelRequest{UserID: owner.ID, ChannelID: parentID, Date: 1700001000})
if err != nil {
t.Fatalf("delete parent: %v", err)
}
if !res.Channel.Deleted {
t.Fatalf("parent not marked deleted: %+v", res.Channel)
}
if res.LinkedMonoforum == nil || res.LinkedMonoforum.ID != monoID || !res.LinkedMonoforum.Deleted {
t.Fatalf("result LinkedMonoforum = %+v, want deleted mono %d", res.LinkedMonoforum, monoID)
}
// Both rows must be deleted=true in the DB.
var parentDeleted, monoDeleted bool
if err := pool.QueryRow(ctx, "SELECT deleted FROM channels WHERE id = $1", parentID).Scan(&parentDeleted); err != nil {
t.Fatalf("read parent deleted: %v", err)
}
if err := pool.QueryRow(ctx, "SELECT deleted FROM channels WHERE id = $1", monoID).Scan(&monoDeleted); err != nil {
t.Fatalf("read mono deleted: %v", err)
}
if !parentDeleted || !monoDeleted {
t.Fatalf("deleted flags parent=%v mono=%v, want both true (orphan monoforum left behind)", parentDeleted, monoDeleted)
}
// After the delete, getDialogs no longer returns the parent channel or the mono.
dialogs, err := channels.ListChannelDialogs(ctx, owner.ID, domain.DialogFilter{Limit: 100})
if err != nil {
t.Fatalf("list dialogs after delete: %v", err)
}
for _, d := range dialogs.Dialogs {
if d.Peer.ID == monoID || d.Peer.ID == parentID {
t.Fatalf("dialogs after delete still include parent/mono: %+v", d)
}
}
}