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

273 lines
8.1 KiB
Go

package repository
import (
"context"
"encoding/json"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/gochat/gochat/internal/model"
)
// helper: build a minimal valid DashboardApp
func newTestDashboardApp(accountID uint, title string) *model.DashboardApp {
return &model.DashboardApp{
AccountID: accountID,
Title: title,
Kind: "frame",
Active: model.BoolPtr(true),
Content: json.RawMessage(`[{"type":"frame","url":"https://example.com"}]`),
}
}
// ========== Create ==========
func TestDashboardAppRepo_Create(t *testing.T) {
db := setupTestDB(t, &model.DashboardApp{})
repo := NewDashboardAppRepo(db)
app := newTestDashboardApp(1, "MyDashboard")
err := repo.Create(context.Background(), app)
require.NoError(t, err)
assert.NotZero(t, app.ID, "ID should be set after Create")
assert.Equal(t, uint(1), app.AccountID)
assert.Equal(t, "MyDashboard", app.Title)
assert.Equal(t, "frame", app.Kind)
assert.True(t, *app.Active)
}
// ========== GetByID ==========
func TestDashboardAppRepo_GetByID(t *testing.T) {
db := setupTestDB(t, &model.DashboardApp{})
repo := NewDashboardAppRepo(db)
app := newTestDashboardApp(1, "FindByIDApp")
err := repo.Create(context.Background(), app)
require.NoError(t, err)
found, err := repo.GetByID(context.Background(), app.ID)
require.NoError(t, err)
assert.Equal(t, app.ID, found.ID)
assert.Equal(t, app.Title, found.Title)
assert.Equal(t, app.AccountID, found.AccountID)
assert.Equal(t, "frame", found.Kind)
assert.True(t, *found.Active)
}
func TestDashboardAppRepo_GetByID_NotFound(t *testing.T) {
db := setupTestDB(t, &model.DashboardApp{})
repo := NewDashboardAppRepo(db)
found, err := repo.GetByID(context.Background(), 9999)
assert.Error(t, err)
assert.Nil(t, found)
}
// ========== Update ==========
func TestDashboardAppRepo_Update(t *testing.T) {
db := setupTestDB(t, &model.DashboardApp{})
repo := NewDashboardAppRepo(db)
app := newTestDashboardApp(1, "BeforeUpdate")
err := repo.Create(context.Background(), app)
require.NoError(t, err)
app.Title = "AfterUpdate"
app.Description = "新描述"
app.Icon = "chart-icon"
app.Active = model.BoolPtr(false)
app.Content = json.RawMessage(`[{"type":"frame","url":"https://updated.com/widget"}]`)
err = repo.Update(context.Background(), app)
require.NoError(t, err)
found, err := repo.GetByID(context.Background(), app.ID)
require.NoError(t, err)
assert.Equal(t, "AfterUpdate", found.Title)
assert.Equal(t, "新描述", found.Description)
assert.Equal(t, "chart-icon", found.Icon)
assert.False(t, *found.Active)
assert.Equal(t, `[{"type":"frame","url":"https://updated.com/widget"}]`, string(found.Content))
}
// ========== Delete ==========
func TestDashboardAppRepo_Delete(t *testing.T) {
db := setupTestDB(t, &model.DashboardApp{})
repo := NewDashboardAppRepo(db)
app := newTestDashboardApp(1, "DeleteApp")
err := repo.Create(context.Background(), app)
require.NoError(t, err)
err = repo.Delete(context.Background(), app.ID)
require.NoError(t, err)
// Verify deletion: GetByID should return error
found, err := repo.GetByID(context.Background(), app.ID)
assert.Error(t, err)
assert.Nil(t, found)
}
// ========== FindAllByAccountID ==========
func TestDashboardAppRepo_FindAllByAccountID(t *testing.T) {
db := setupTestDB(t, &model.DashboardApp{})
repo := NewDashboardAppRepo(db)
accountID := uint(10)
// Create 3 apps for this account
for i := 0; i < 3; i++ {
app := newTestDashboardApp(accountID, "App"+string(rune('A'+i)))
err := repo.Create(context.Background(), app)
require.NoError(t, err)
}
// Create 1 app for a different account (should not appear)
otherApp := newTestDashboardApp(99, "OtherAccountApp")
err := repo.Create(context.Background(), otherApp)
require.NoError(t, err)
// Find all without pagination (matches Chatwoot behavior)
apps, err := repo.FindAllByAccountID(context.Background(), accountID)
require.NoError(t, err)
assert.Len(t, apps, 3)
// Verify all apps belong to the correct account
for _, a := range apps {
assert.Equal(t, accountID, a.AccountID)
}
}
// ========== FindByUserID ==========
func TestDashboardAppRepo_FindByUserID(t *testing.T) {
db := setupTestDB(t, &model.DashboardApp{})
repo := NewDashboardAppRepo(db)
userID := uint(100)
accountID := uint(10)
// Create 2 apps with the given userID
for i := 0; i < 2; i++ {
app := newTestDashboardApp(accountID, "UserApp"+string(rune('A'+i)))
app.UserID = &userID
err := repo.Create(context.Background(), app)
require.NoError(t, err)
}
// Create 1 app with a different userID (should not appear)
otherUserID := uint(999)
otherApp := newTestDashboardApp(accountID, "OtherUserApp")
otherApp.UserID = &otherUserID
err := repo.Create(context.Background(), otherApp)
require.NoError(t, err)
apps, count, err := repo.FindByUserID(context.Background(), userID, 0, 10)
require.NoError(t, err)
assert.Equal(t, int64(2), count)
assert.Len(t, apps, 2)
for _, a := range apps {
assert.NotNil(t, a.UserID)
assert.Equal(t, userID, *a.UserID)
}
}
// ========== FindAllActiveByAccountID ==========
func TestDashboardAppRepo_FindAllActiveByAccountID(t *testing.T) {
db := setupTestDB(t, &model.DashboardApp{})
repo := NewDashboardAppRepo(db)
accountID := uint(30)
// Create 2 active apps
for i := 0; i < 2; i++ {
app := newTestDashboardApp(accountID, "ActiveApp"+string(rune('A'+i)))
app.Active = model.BoolPtr(true)
err := repo.Create(context.Background(), app)
require.NoError(t, err)
}
// Create 1 inactive app (should not appear)
inactiveApp := newTestDashboardApp(accountID, "InactiveApp")
inactiveApp.Active = model.BoolPtr(false)
err := repo.Create(context.Background(), inactiveApp)
require.NoError(t, err)
apps, err := repo.FindAllActiveByAccountID(context.Background(), accountID)
require.NoError(t, err)
assert.Len(t, apps, 2)
for _, a := range apps {
assert.True(t, *a.Active)
}
}
// ========== Search ==========
// Search uses ILIKE on PG / LIKE on SQLite — both DBs should work.
func TestDashboardAppRepo_Search(t *testing.T) {
db := setupTestDB(t, &model.DashboardApp{})
repo := NewDashboardAppRepo(db)
accountID := uint(40)
// Create apps with different titles
titles := []string{"销售仪表盘", "客服监控面板", "运营数据看板", "工单统计"}
for _, title := range titles {
app := newTestDashboardApp(accountID, title)
err := repo.Create(context.Background(), app)
require.NoError(t, err)
}
// Create app in different account (should not appear)
otherApp := newTestDashboardApp(99, "仪表盘")
err := repo.Create(context.Background(), otherApp)
require.NoError(t, err)
// Search for "仪表盘" — should match "销售仪表盘"
apps, count, err := repo.Search(context.Background(), accountID, "仪表盘", 0, 10)
require.NoError(t, err)
assert.Equal(t, int64(1), count)
assert.Len(t, apps, 1)
assert.Equal(t, "销售仪表盘", apps[0].Title)
}
func TestDashboardAppRepo_Search_空结果(t *testing.T) {
db := setupTestDB(t, &model.DashboardApp{})
repo := NewDashboardAppRepo(db)
accountID := uint(41)
// Create 1 app
app := newTestDashboardApp(accountID, "客服监控")
err := repo.Create(context.Background(), app)
require.NoError(t, err)
apps, count, err := repo.Search(context.Background(), accountID, "不存在", 0, 10)
require.NoError(t, err)
assert.Equal(t, int64(0), count)
assert.Len(t, apps, 0)
}
func TestDashboardAppRepo_Search_分页(t *testing.T) {
db := setupTestDB(t, &model.DashboardApp{})
repo := NewDashboardAppRepo(db)
accountID := uint(42)
// Create 3 apps matching "监控"
for i := 0; i < 3; i++ {
app := newTestDashboardApp(accountID, "监控面板"+string(rune('A'+i)))
err := repo.Create(context.Background(), app)
require.NoError(t, err)
}
// Page 1: offset 0, limit 2
apps, count, err := repo.Search(context.Background(), accountID, "监控", 0, 2)
require.NoError(t, err)
assert.Equal(t, int64(3), count)
assert.Len(t, apps, 2)
// Page 2: offset 2, limit 2
apps2, count2, err := repo.Search(context.Background(), accountID, "监控", 2, 2)
require.NoError(t, err)
assert.Equal(t, int64(3), count2)
assert.Len(t, apps2, 1)
}