Files
gochat/backend/internal/repository/conversation_repo_pg_test.go
T
rogee aeddedf2a3 Reorganize repo: backend/, deploy/, docs/ layout + AGENTS.md
Restructure the monorepo into clear top-level directories:
- backend/: Go module root (cmd, internal, pkg, configs, migrations,
  docs/swagger, scripts, tests, go.mod, Makefile, .air.toml)
- deploy/: Docker (Dockerfile, docker-compose*), quickstart, fluentd
- docs/: project documentation + reports/ (moved from repo root)
- AGENTS.md: new AI coding-agent guide at repo root

Update all references to the new layout:
- Dockerfile: COPY backend/go.mod, COPY backend/ (context = repo root)
- docker-compose files: context ../.., dockerfile deploy/docker/Dockerfile,
  env_file ../../.env, volume mounts ../../backend:/app
- deploy/quickstart/compose.yaml: dockerfile deploy/docker/Dockerfile
- CI: working-directory: backend for go commands, file deploy/docker/Dockerfile,
  coverage path backend/coverage.out, health_check backend/scripts/
- backend/Makefile: docker target uses -f ../deploy/docker/Dockerfile ../
- README: architecture tree, quickstart, config paths updated

Move root stray scripts (rename_models.*, run_m11_tests.sh, verify_build.sh,
gorm_bool_main.go) to backend/scripts/legacy/. All moves via git mv to
preserve history. Build, vet, SQLite tests, and docker compose config verified.
2026-07-07 14:44:12 +08:00

175 lines
5.5 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()
accountID := uint(1)
convs := []model.Conversation{
{AccountID: accountID, InboxID: 1, Status: "open", Labels: "support,billing"},
{AccountID: accountID, InboxID: 1, Status: "open", Labels: "billing,urgent"},
{AccountID: accountID, InboxID: 1, Status: "open", Labels: "sales,lead"},
{AccountID: accountID, InboxID: 1, Status: "resolved", Labels: "support,closed"},
{AccountID: uint(2), InboxID: 1, Status: "open", Labels: "support,other"},
}
for _, c := range convs {
require.NoError(t, repo.Create(ctx, &c))
}
results, total, err := repo.Search(ctx, accountID, "billing", 0, 10, search.SearchModeILike)
require.NoError(t, err)
assert.Equal(t, int64(2), total)
_ = results
results, total, err = repo.Search(ctx, accountID, "support", 0, 10, search.SearchModeILike)
require.NoError(t, err)
assert.Equal(t, int64(2), total)
_ = results
results, total, err = repo.Search(ctx, accountID, "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()
accountID := uint(1)
convs := []model.Conversation{
{AccountID: accountID, InboxID: 1, Status: "open", Labels: "customer support query"},
{AccountID: accountID, InboxID: 1, Status: "open", Labels: "billing inquiry"},
}
for _, c := range convs {
require.NoError(t, repo.Create(ctx, &c))
}
results, total, err := repo.Search(ctx, accountID, "custmr", 0, 10, search.SearchModeTrigram)
if err != nil {
t.Skipf("pg_trgm extension not available: %v", 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()
accountID := uint(1)
convs := []model.Conversation{
{AccountID: accountID, InboxID: 1, Status: "open", AssigneeID: uintPtr(10)},
{AccountID: accountID, InboxID: 1, Status: "open", AssigneeID: uintPtr(20)},
{AccountID: accountID, InboxID: 1, 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", accountID).
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)", accountID).
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))
}