Files
gochat/backend/internal/repository/widget_offline_message_repo_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

274 lines
9.0 KiB
Go

package repository
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/gochat/gochat/internal/model"
)
// helper to create a minimal test offline message
func newTestOfflineMessage(accountID uint, inboxID uint, content string) *model.WidgetOfflineMessage {
return &model.WidgetOfflineMessage{
AccountID: accountID,
InboxID: inboxID,
Content: content,
Status: model.OfflineStatusPending,
ContactName: "Visitor",
}
}
// --- Test: Create ---
func TestWidgetOfflineMessageRepo_Create(t *testing.T) {
db := setupTestDB(t, &model.WidgetOfflineMessage{})
repo := NewWidgetOfflineMessageRepo(db)
msg := newTestOfflineMessage(1, 1, "Hello, I need help")
err := repo.Create(context.Background(), msg)
require.NoError(t, err)
assert.NotZero(t, msg.ID)
assert.Equal(t, uint(1), msg.AccountID)
assert.Equal(t, uint(1), msg.InboxID)
assert.Equal(t, "Hello, I need help", msg.Content)
assert.Equal(t, model.OfflineStatusPending, msg.Status)
}
// --- Test: FindByID ---
func TestWidgetOfflineMessageRepo_FindByID(t *testing.T) {
db := setupTestDB(t, &model.WidgetOfflineMessage{})
repo := NewWidgetOfflineMessageRepo(db)
msg := newTestOfflineMessage(1, 1, "Find me")
err := repo.Create(context.Background(), msg)
require.NoError(t, err)
found, err := repo.FindByID(context.Background(), msg.ID)
require.NoError(t, err)
assert.Equal(t, msg.ID, found.ID)
assert.Equal(t, "Find me", found.Content)
assert.Equal(t, model.OfflineStatusPending, found.Status)
}
// --- Test: FindByID Not Found ---
func TestWidgetOfflineMessageRepo_FindByID_NotFound(t *testing.T) {
db := setupTestDB(t, &model.WidgetOfflineMessage{})
repo := NewWidgetOfflineMessageRepo(db)
found, err := repo.FindByID(context.Background(), 9999)
assert.Error(t, err)
assert.Nil(t, found)
}
// --- Test: FindByAccountID ---
func TestWidgetOfflineMessageRepo_FindByAccountID(t *testing.T) {
db := setupTestDB(t, &model.WidgetOfflineMessage{})
repo := NewWidgetOfflineMessageRepo(db)
// Create messages for account 1
m1 := newTestOfflineMessage(1, 10, "Account1 msg1")
m2 := newTestOfflineMessage(1, 10, "Account1 msg2")
require.NoError(t, repo.Create(context.Background(), m1))
require.NoError(t, repo.Create(context.Background(), m2))
// Create a message for account 2 (should not appear)
m3 := newTestOfflineMessage(2, 20, "Account2 msg")
require.NoError(t, repo.Create(context.Background(), m3))
msgs, total, err := repo.FindByAccountID(context.Background(), 1, 0, 10)
require.NoError(t, err)
assert.Equal(t, int64(2), total)
assert.Len(t, msgs, 2)
// Verify account 2 has 1 message
msgs2, total2, err := repo.FindByAccountID(context.Background(), 2, 0, 10)
require.NoError(t, err)
assert.Equal(t, int64(1), total2)
assert.Len(t, msgs2, 1)
}
// --- Test: FindByAccountID with pagination ---
func TestWidgetOfflineMessageRepo_FindByAccountID_Pagination(t *testing.T) {
db := setupTestDB(t, &model.WidgetOfflineMessage{})
repo := NewWidgetOfflineMessageRepo(db)
for i := 0; i < 5; i++ {
msg := newTestOfflineMessage(1, 10, "msg"+string(rune('a'+i)))
require.NoError(t, repo.Create(context.Background(), msg))
}
// Page 1: offset=0, limit=2
msgs, total, err := repo.FindByAccountID(context.Background(), 1, 0, 2)
require.NoError(t, err)
assert.Equal(t, int64(5), total)
assert.Len(t, msgs, 2)
// Page 2: offset=2, limit=2
msgs2, total2, err := repo.FindByAccountID(context.Background(), 1, 2, 2)
require.NoError(t, err)
assert.Equal(t, int64(5), total2)
assert.Len(t, msgs2, 2)
// Verify pages don't overlap
assert.NotEqual(t, msgs[0].ID, msgs2[0].ID)
}
// --- Test: FindByInboxID ---
func TestWidgetOfflineMessageRepo_FindByInboxID(t *testing.T) {
db := setupTestDB(t, &model.WidgetOfflineMessage{})
repo := NewWidgetOfflineMessageRepo(db)
// Create pending messages for inbox 10
m1 := newTestOfflineMessage(1, 10, "Inbox10 pending1")
m2 := newTestOfflineMessage(1, 10, "Inbox10 pending2")
require.NoError(t, repo.Create(context.Background(), m1))
require.NoError(t, repo.Create(context.Background(), m2))
// Create a converted message for inbox 10 — should NOT be returned
m3 := newTestOfflineMessage(1, 10, "Inbox10 converted")
m3.Status = model.OfflineStatusConverted
require.NoError(t, repo.Create(context.Background(), m3))
// Create a pending message for inbox 20 — should NOT be returned
m4 := newTestOfflineMessage(1, 20, "Inbox20 pending")
require.NoError(t, repo.Create(context.Background(), m4))
msgs, err := repo.FindByInboxID(context.Background(), 10)
require.NoError(t, err)
assert.Len(t, msgs, 2) // only pending ones
for _, m := range msgs {
assert.Equal(t, model.OfflineStatusPending, m.Status)
assert.Equal(t, uint(10), m.InboxID)
}
}
// --- Test: Update ---
func TestWidgetOfflineMessageRepo_Update(t *testing.T) {
db := setupTestDB(t, &model.WidgetOfflineMessage{})
repo := NewWidgetOfflineMessageRepo(db)
msg := newTestOfflineMessage(1, 10, "Original content")
require.NoError(t, repo.Create(context.Background(), msg))
msg.ContactName = "Updated Visitor"
msg.Content = "Updated content"
err := repo.Update(context.Background(), msg)
require.NoError(t, err)
found, err := repo.FindByID(context.Background(), msg.ID)
require.NoError(t, err)
assert.Equal(t, "Updated Visitor", found.ContactName)
assert.Equal(t, "Updated content", found.Content)
}
// --- Test: Delete ---
func TestWidgetOfflineMessageRepo_Delete(t *testing.T) {
db := setupTestDB(t, &model.WidgetOfflineMessage{})
repo := NewWidgetOfflineMessageRepo(db)
msg := newTestOfflineMessage(1, 10, "Delete me")
require.NoError(t, repo.Create(context.Background(), msg))
err := repo.Delete(context.Background(), msg.ID)
require.NoError(t, err)
// After soft-delete, FindByID should not find it
found, err := repo.FindByID(context.Background(), msg.ID)
assert.Error(t, err)
assert.Nil(t, found)
}
// --- Test: CountPendingByInboxID ---
func TestWidgetOfflineMessageRepo_CountPendingByInboxID(t *testing.T) {
db := setupTestDB(t, &model.WidgetOfflineMessage{})
repo := NewWidgetOfflineMessageRepo(db)
// Create 3 pending messages for inbox 10
for i := 0; i < 3; i++ {
msg := newTestOfflineMessage(1, 10, "pending msg")
require.NoError(t, repo.Create(context.Background(), msg))
}
// Create 1 converted message for inbox 10 — should not count
convertedMsg := newTestOfflineMessage(1, 10, "converted msg")
convertedMsg.Status = model.OfflineStatusConverted
require.NoError(t, repo.Create(context.Background(), convertedMsg))
// Create 1 dismissed message for inbox 10 — should not count
dismissedMsg := newTestOfflineMessage(1, 10, "dismissed msg")
dismissedMsg.Status = model.OfflineStatusDismissed
require.NoError(t, repo.Create(context.Background(), dismissedMsg))
// Create 2 pending messages for inbox 20 — different inbox
for i := 0; i < 2; i++ {
msg := newTestOfflineMessage(1, 20, "other inbox pending")
require.NoError(t, repo.Create(context.Background(), msg))
}
count, err := repo.CountPendingByInboxID(context.Background(), 10)
require.NoError(t, err)
assert.Equal(t, int64(3), count)
count2, err := repo.CountPendingByInboxID(context.Background(), 20)
require.NoError(t, err)
assert.Equal(t, int64(2), count2)
// Empty inbox
count3, err := repo.CountPendingByInboxID(context.Background(), 99)
require.NoError(t, err)
assert.Equal(t, int64(0), count3)
}
// --- Test: MarkConverted ---
func TestWidgetOfflineMessageRepo_MarkConverted(t *testing.T) {
db := setupTestDB(t, &model.WidgetOfflineMessage{})
repo := NewWidgetOfflineMessageRepo(db)
msg := newTestOfflineMessage(1, 10, "Convert me")
require.NoError(t, repo.Create(context.Background(), msg))
err := repo.MarkConverted(context.Background(), msg.ID, 100)
require.NoError(t, err)
found, err := repo.FindByID(context.Background(), msg.ID)
require.NoError(t, err)
assert.Equal(t, model.OfflineStatusConverted, found.Status)
assert.NotNil(t, found.ConversationID)
assert.Equal(t, uint(100), *found.ConversationID)
}
// --- Test: MarkConverted Not Found ---
func TestWidgetOfflineMessageRepo_MarkConverted_NotFound(t *testing.T) {
db := setupTestDB(t, &model.WidgetOfflineMessage{})
repo := NewWidgetOfflineMessageRepo(db)
err := repo.MarkConverted(context.Background(), 9999, 100)
assert.Error(t, err)
}
// --- Test: MarkDismissed ---
func TestWidgetOfflineMessageRepo_MarkDismissed(t *testing.T) {
db := setupTestDB(t, &model.WidgetOfflineMessage{})
repo := NewWidgetOfflineMessageRepo(db)
msg := newTestOfflineMessage(1, 10, "Dismiss me")
require.NoError(t, repo.Create(context.Background(), msg))
err := repo.MarkDismissed(context.Background(), msg.ID)
require.NoError(t, err)
found, err := repo.FindByID(context.Background(), msg.ID)
require.NoError(t, err)
assert.Equal(t, model.OfflineStatusDismissed, found.Status)
}
// --- Test: MarkDismissed Not Found ---
func TestWidgetOfflineMessageRepo_MarkDismissed_NotFound(t *testing.T) {
db := setupTestDB(t, &model.WidgetOfflineMessage{})
repo := NewWidgetOfflineMessageRepo(db)
err := repo.MarkDismissed(context.Background(), 9999)
assert.Error(t, err)
}