* 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>
185 lines
6.7 KiB
Go
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))
|
|
}
|