Files
gochat/backend/internal/repository/conversation_repo_pg_test.go
T
Rogeeandrogee 02a188dc29 HH-443: establish production CI and supply-chain evidence (#93)
* ci: enforce production release gates

* ci: close release gate review blockers

* ci: preserve verified digests during promotion

* ci: serialize and verify release cleanup

* ci: build govulncheck with Shangwutong toolchain

---------

Co-authored-by: Rogee <rogee@ipao.vip>
2026-08-22 03:26:38 +08:00

185 lines
6.7 KiB
Go

package repository
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/gochat/gochat/internal/model"
"github.com/gochat/gochat/internal/search"
)
func uintPtr(v uint) *uint { return &v }
func TestConversationRepo_Search_ILIKE(t *testing.T) {
skipIfSQLite(t)
db := setupTestDB(t)
repo := NewConversationRepo(db)
ctx := context.Background()
account := createTestAccountForSearch(t, db)
otherAccount := createTestAccountForSearch(t, db)
inbox := createTestInboxForSearch(t, db, account.ID, "PG search")
contact := createTestContactForSearch(t, db, account.ID, "PG contact", "pg-search@example.com", "")
otherContact := createTestContactForSearch(t, db, otherAccount.ID, "Other PG contact", "other-pg-search@example.com", "")
convs := []model.Conversation{
{AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, Status: "open", Labels: "support,billing"},
{AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, Status: "open", Labels: "billing,urgent"},
{AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, Status: "open", Labels: "sales,lead"},
{AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, Status: "resolved", Labels: "support,closed"},
{AccountID: otherAccount.ID, InboxID: inbox.ID, ContactID: otherContact.ID, Status: "open", Labels: "support,other"},
}
for _, c := range convs {
require.NoError(t, repo.Create(ctx, &c))
}
results, total, err := repo.Search(ctx, account.ID, "billing", 0, 10, search.SearchModeILike)
require.NoError(t, err)
assert.Equal(t, int64(2), total)
_ = results
results, total, err = repo.Search(ctx, account.ID, "support", 0, 10, search.SearchModeILike)
require.NoError(t, err)
assert.Equal(t, int64(2), total)
_ = results
results, total, err = repo.Search(ctx, account.ID, "nonexistent", 0, 10, search.SearchModeILike)
require.NoError(t, err)
assert.Equal(t, int64(0), total)
assert.Empty(t, results)
}
func TestConversationRepo_Search_Trigram(t *testing.T) {
skipIfSQLite(t)
db := setupTestDB(t)
repo := NewConversationRepo(db)
ctx := context.Background()
account := createTestAccountForSearch(t, db)
inbox := createTestInboxForSearch(t, db, account.ID, "PG trigram")
contact := createTestContactForSearch(t, db, account.ID, "PG trigram contact", "pg-trigram@example.com", "")
convs := []model.Conversation{
{AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, Status: "open", Labels: "customer"},
{AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID, Status: "open", Labels: "billing inquiry"},
}
for _, c := range convs {
require.NoError(t, repo.Create(ctx, &c))
}
results, total, err := repo.Search(ctx, account.ID, "custmr", 0, 10, search.SearchModeTrigram)
require.NoError(t, err)
assert.GreaterOrEqual(t, total, int64(1))
assert.NotEmpty(t, results)
}
func TestConversationRepo_Filter_AssigneeType_PG(t *testing.T) {
skipIfSQLite(t)
db := setupTestDB(t)
repo := NewConversationRepo(db)
ctx := context.Background()
account := createTestAccountForSearch(t, db)
inbox := createTestInboxForSearch(t, db, account.ID, "PG assignee filter")
agent := createTestUserForSearch(t, db, account.ID, "pg-agent@example.com")
admin := createTestUserForSearch(t, db, account.ID, "pg-admin@example.com")
require.NoError(t, db.Create(&model.AccountUser{AccountID: account.ID, UserID: agent.ID, Role: "agent"}).Error)
require.NoError(t, db.Create(&model.AccountUser{AccountID: account.ID, UserID: admin.ID, Role: "administrator"}).Error)
convs := []model.Conversation{
{AccountID: account.ID, InboxID: inbox.ID, Status: "open", AssigneeID: uintPtr(agent.ID)},
{AccountID: account.ID, InboxID: inbox.ID, Status: "open", AssigneeID: uintPtr(admin.ID)},
{AccountID: account.ID, InboxID: inbox.ID, Status: "open", AssigneeID: nil}, // unassigned
}
for _, c := range convs {
require.NoError(t, repo.Create(ctx, &c))
}
var total int64
db.Model(&model.Conversation{}).
Where("account_id = ? AND assignee_id IS NOT NULL AND assignee_id != 0", account.ID).
Count(&total)
assert.Equal(t, int64(2), total, "assigned conversations")
db.Model(&model.Conversation{}).
Where("account_id = ? AND (assignee_id IS NULL OR assignee_id = 0)", account.ID).
Count(&total)
assert.Equal(t, int64(1), total, "unassigned conversations")
}
func TestConversationRepo_Filter_Mentions_PG(t *testing.T) {
skipIfSQLite(t)
db := setupTestDB(t)
repo := NewConversationRepo(db)
ctx := context.Background()
accountID := uint(1)
userID := uint(100)
conv1 := model.Conversation{AccountID: accountID, InboxID: 1, Status: "open"}
conv2 := model.Conversation{AccountID: accountID, InboxID: 1, Status: "open"}
require.NoError(t, repo.Create(ctx, &conv1))
require.NoError(t, repo.Create(ctx, &conv2))
mention := model.Mention{ConversationID: conv1.ID, UserID: userID, AccountID: accountID}
require.NoError(t, db.Create(&mention).Error)
var mentioned []model.Conversation
err := db.Where("account_id = ? AND id IN (SELECT conversation_id FROM mentions WHERE user_id = ?)", accountID, userID).
Find(&mentioned).Error
require.NoError(t, err)
assert.Len(t, mentioned, 1)
assert.Equal(t, conv1.ID, mentioned[0].ID)
}
func TestConversationRepo_Filter_Participants_PG(t *testing.T) {
skipIfSQLite(t)
db := setupTestDB(t)
repo := NewConversationRepo(db)
ctx := context.Background()
accountID := uint(1)
userID := uint(100)
conv1 := model.Conversation{AccountID: accountID, InboxID: 1, Status: "open"}
conv2 := model.Conversation{AccountID: accountID, InboxID: 1, Status: "open"}
require.NoError(t, repo.Create(ctx, &conv1))
require.NoError(t, repo.Create(ctx, &conv2))
participant := model.ConversationParticipant{ConversationID: conv1.ID, UserID: userID}
require.NoError(t, db.Create(&participant).Error)
var participating []model.Conversation
err := db.Where("account_id = ? AND id IN (SELECT conversation_id FROM conversation_participants WHERE user_id = ?)", accountID, userID).
Find(&participating).Error
require.NoError(t, err)
assert.Len(t, participating, 1)
assert.Equal(t, conv1.ID, participating[0].ID)
}
func TestConversationRepo_UpdatedWithin_PG(t *testing.T) {
skipIfSQLite(t)
db := setupTestDB(t)
repo := NewConversationRepo(db)
ctx := context.Background()
accountID := uint(1)
conv := model.Conversation{AccountID: accountID, InboxID: 1, Status: "open"}
require.NoError(t, repo.Create(ctx, &conv))
var total int64
db.Model(&model.Conversation{}).
Where("account_id = ? AND updated_at > NOW() - INTERVAL '3600 seconds'", accountID).
Count(&total)
assert.Equal(t, int64(1), total, "conversation updated within last hour")
db.Model(&model.Conversation{}).
Where("account_id = ? AND updated_at > NOW() - INTERVAL '0 seconds'", accountID).
Count(&total)
assert.LessOrEqual(t, total, int64(1))
}