Files
gochat/internal/service/platform_app_service_test.go_BAK
T
2026-06-04 15:44:48 +08:00

509 lines
15 KiB
Plaintext

package service
import (
"context"
"testing"
"github.com/gochat/gochat/internal/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// ========== Create ==========
func TestPlatformAppService_Create_Success(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
req := CreatePlatformAppRequest{
Name: "TestPlatformApp",
Description: "A test platform app",
Type: "api",
AccountID: account.ID,
}
app, err := svc.Create(context.Background(), req)
require.NoError(t, err)
assert.NotZero(t, app.ID)
assert.Equal(t, "TestPlatformApp", app.Name)
assert.NotEmpty(t, app.APIKey, "API key should be auto-generated")
assert.Equal(t, "api", app.Type)
assert.Equal(t, "active", app.Status, "status should default to active")
assert.Equal(t, account.ID, app.AccountID)
}
func TestPlatformAppService_Create_DefaultType(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
req := CreatePlatformAppRequest{
Name: "NoTypeApp",
AccountID: account.ID,
}
app, err := svc.Create(context.Background(), req)
require.NoError(t, err)
assert.Equal(t, "api", app.Type, "type should default to 'api' when empty")
}
func TestPlatformAppService_Create_AgentBotType(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
req := CreatePlatformAppRequest{
Name: "BotApp",
Type: "agent_bot",
AccountID: account.ID,
}
app, err := svc.Create(context.Background(), req)
require.NoError(t, err)
assert.Equal(t, "agent_bot", app.Type)
}
func TestPlatformAppService_Create_PlatformLevel(t *testing.T) {
_, _, svc := setupPlatformAppService(t)
// AccountID = 0 means platform-level (no account restriction)
req := CreatePlatformAppRequest{
Name: "PlatformApp",
Type: "api",
}
app, err := svc.Create(context.Background(), req)
require.NoError(t, err)
assert.Zero(t, app.AccountID, "platform-level app should have AccountID=0")
}
func TestPlatformAppService_Create_Validation_NameRequired(t *testing.T) {
_, _, svc := setupPlatformAppService(t)
req := CreatePlatformAppRequest{
Name: "", // empty name — should fail validation (min=2)
}
_, err := svc.Create(context.Background(), req)
assert.Error(t, err, "empty name should fail validation")
}
func TestPlatformAppService_Create_Validation_NameTooShort(t *testing.T) {
_, _, svc := setupPlatformAppService(t)
req := CreatePlatformAppRequest{
Name: "X", // single char — min=2
}
_, err := svc.Create(context.Background(), req)
assert.Error(t, err, "1-char name should fail validation (min=2)")
}
func TestPlatformAppService_Create_Validation_InvalidType(t *testing.T) {
_, _, svc := setupPlatformAppService(t)
req := CreatePlatformAppRequest{
Name: "ValidName",
Type: "invalid_type", // not in oneof=api agent_bot
}
_, err := svc.Create(context.Background(), req)
assert.Error(t, err, "invalid type should fail validation")
}
func TestPlatformAppService_Create_Validation_DescriptionTooLong(t *testing.T) {
_, _, svc := setupPlatformAppService(t)
// Create a description > 500 chars
longDesc := ""
for i := 0; i < 501; i++ {
longDesc += "x"
}
req := CreatePlatformAppRequest{
Name: "ValidName",
Description: longDesc,
}
_, err := svc.Create(context.Background(), req)
assert.Error(t, err, "description > 500 chars should fail validation")
}
func TestPlatformAppService_Create_UniqueAPIKey(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
req1 := CreatePlatformAppRequest{
Name: "App1",
Type: "api",
AccountID: account.ID,
}
app1, err := svc.Create(context.Background(), req1)
require.NoError(t, err)
req2 := CreatePlatformAppRequest{
Name: "App2",
Type: "api",
AccountID: account.ID,
}
app2, err := svc.Create(context.Background(), req2)
require.NoError(t, err)
assert.NotEqual(t, app1.APIKey, app2.APIKey, "each create should generate a unique API key")
}
// ========== GetByID ==========
func TestPlatformAppService_GetByID_Success(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
app := createTestPlatformApp(t, db, account.ID)
found, err := svc.GetByID(context.Background(), app.ID)
require.NoError(t, err)
assert.Equal(t, app.ID, found.ID)
assert.Equal(t, app.Name, found.Name)
assert.Equal(t, app.APIKey, found.APIKey)
}
func TestPlatformAppService_GetByID_NotFound(t *testing.T) {
_, _, svc := setupPlatformAppService(t)
_, err := svc.GetByID(context.Background(), 99999)
assert.Error(t, err)
}
// ========== Update ==========
func TestPlatformAppService_Update_Success(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
app := createTestPlatformApp(t, db, account.ID)
req := UpdatePlatformAppRequest{
Name: "UpdatedName",
Description: "Updated description",
}
updated, err := svc.Update(context.Background(), app.ID, req)
require.NoError(t, err)
assert.Equal(t, "UpdatedName", updated.Name)
assert.Equal(t, "Updated description", updated.Description)
}
func TestPlatformAppService_Update_Status(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
app := createTestPlatformApp(t, db, account.ID)
req := UpdatePlatformAppRequest{
Status: "disabled",
}
updated, err := svc.Update(context.Background(), app.ID, req)
require.NoError(t, err)
assert.Equal(t, "disabled", updated.Status)
}
func TestPlatformAppService_Update_Type(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
app := createTestPlatformApp(t, db, account.ID)
req := UpdatePlatformAppRequest{
Type: "agent_bot",
}
updated, err := svc.Update(context.Background(), app.ID, req)
require.NoError(t, err)
assert.Equal(t, "agent_bot", updated.Type)
}
func TestPlatformAppService_Update_PartialFields(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
app := createTestPlatformApp(t, db, account.ID)
originalDesc := app.Description
// Only update Name, leave other fields unchanged
req := UpdatePlatformAppRequest{
Name: "OnlyNameChanged",
}
updated, err := svc.Update(context.Background(), app.ID, req)
require.NoError(t, err)
assert.Equal(t, "OnlyNameChanged", updated.Name)
assert.Equal(t, originalDesc, updated.Description, "description should not change")
}
func TestPlatformAppService_Update_NotFound(t *testing.T) {
_, _, svc := setupPlatformAppService(t)
req := UpdatePlatformAppRequest{
Name: "NewName",
}
_, err := svc.Update(context.Background(), 99999, req)
assert.Error(t, err)
}
func TestPlatformAppService_Update_Validation_InvalidType(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
app := createTestPlatformApp(t, db, account.ID)
req := UpdatePlatformAppRequest{
Type: "invalid_type",
}
_, err := svc.Update(context.Background(), app.ID, req)
assert.Error(t, err, "invalid type should fail validation")
}
func TestPlatformAppService_Update_Validation_InvalidStatus(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
app := createTestPlatformApp(t, db, account.ID)
req := UpdatePlatformAppRequest{
Status: "unknown_status",
}
_, err := svc.Update(context.Background(), app.ID, req)
assert.Error(t, err, "invalid status should fail validation")
}
// ========== Delete ==========
func TestPlatformAppService_Delete_Success(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
app := createTestPlatformApp(t, db, account.ID)
err := svc.Delete(context.Background(), app.ID)
require.NoError(t, err)
// Verify soft-delete — GetByID should fail
_, err = svc.GetByID(context.Background(), app.ID)
assert.Error(t, err, "soft-deleted app should not be retrievable")
}
func TestPlatformAppService_Delete_NotFound(t *testing.T) {
_, _, svc := setupPlatformAppService(t)
err := svc.Delete(context.Background(), 99999)
// GORM Delete on non-existent record may or may not error depending on dialect
// SQLite: no error (0 rows affected is not an error for GORM)
assert.NoError(t, err)
}
// ========== ListAll ==========
func TestPlatformAppService_ListAll_Success(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
// Create multiple apps
for i := 0; i < 5; i++ {
createTestPlatformApp(t, db, account.ID, func(app *model.PlatformApp) {
app.Name = "ListApp" + string(rune('A'+i))
app.APIKey = "list-key-" + string(rune('A'+i))
})
}
apps, count, err := svc.ListAll(context.Background(), 0, 10)
require.NoError(t, err)
assert.Equal(t, int64(5), count)
assert.Len(t, apps, 5)
}
func TestPlatformAppService_ListAll_Pagination(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
for i := 0; i < 10; i++ {
createTestPlatformApp(t, db, account.ID, func(app *model.PlatformApp) {
app.Name = "PageApp" + string(rune('0'+i))
app.APIKey = "page-key-" + string(rune('0'+i))
})
}
apps, count, err := svc.ListAll(context.Background(), 0, 3)
require.NoError(t, err)
assert.Equal(t, int64(10), count)
assert.Len(t, apps, 3)
apps, count, err = svc.ListAll(context.Background(), 3, 3)
require.NoError(t, err)
assert.Equal(t, int64(10), count)
assert.Len(t, apps, 3)
}
func TestPlatformAppService_ListAll_Empty(t *testing.T) {
_, _, svc := setupPlatformAppService(t)
apps, count, err := svc.ListAll(context.Background(), 0, 10)
require.NoError(t, err)
assert.Equal(t, int64(0), count)
assert.Len(t, apps, 0)
}
// ========== ListByAccount ==========
func TestPlatformAppService_ListByAccount_Success(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account1 := createTestAccount(t, db)
account2 := createTestAccount(t, db)
// Create apps for account1
for i := 0; i < 3; i++ {
createTestPlatformApp(t, db, account1.ID, func(app *model.PlatformApp) {
app.Name = "Acc1App" + string(rune('A'+i))
app.APIKey = "acc1-key-" + string(rune('A'+i))
})
}
// Create apps for account2
for i := 0; i < 2; i++ {
createTestPlatformApp(t, db, account2.ID, func(app *model.PlatformApp) {
app.Name = "Acc2App" + string(rune('A'+i))
app.APIKey = "acc2-key-" + string(rune('A'+i))
})
}
apps, count, err := svc.ListByAccount(context.Background(), account1.ID, 0, 10)
require.NoError(t, err)
assert.Equal(t, int64(3), count)
assert.Len(t, apps, 3)
apps, count, err = svc.ListByAccount(context.Background(), account2.ID, 0, 10)
require.NoError(t, err)
assert.Equal(t, int64(2), count)
assert.Len(t, apps, 2)
}
func TestPlatformAppService_ListByAccount_Empty(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
apps, count, err := svc.ListByAccount(context.Background(), account.ID, 0, 10)
require.NoError(t, err)
assert.Equal(t, int64(0), count)
assert.Len(t, apps, 0)
}
// ========== RegenerateAPIKey ==========
func TestPlatformAppService_RegenerateAPIKey_Success(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
req := CreatePlatformAppRequest{
Name: "KeyRotateApp",
AccountID: account.ID,
}
app, err := svc.Create(context.Background(), req)
require.NoError(t, err)
originalKey := app.APIKey
require.NotEmpty(t, originalKey)
rotated, err := svc.RegenerateAPIKey(context.Background(), app.ID)
require.NoError(t, err)
assert.NotEqual(t, originalKey, rotated.APIKey, "new key should differ from old key")
assert.NotEmpty(t, rotated.APIKey, "new key should not be empty")
assert.Equal(t, app.ID, rotated.ID, "ID should stay the same")
assert.Equal(t, app.Name, rotated.Name, "name should stay the same")
}
func TestPlatformAppService_RegenerateAPIKey_NotFound(t *testing.T) {
_, _, svc := setupPlatformAppService(t)
_, err := svc.RegenerateAPIKey(context.Background(), 99999)
assert.Error(t, err, "should fail for nonexistent app")
}
func TestPlatformAppService_RegenerateAPIKey_DoubleRotate(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
req := CreatePlatformAppRequest{
Name: "DoubleRotateApp",
AccountID: account.ID,
}
app, err := svc.Create(context.Background(), req)
require.NoError(t, err)
first, err := svc.RegenerateAPIKey(context.Background(), app.ID)
require.NoError(t, err)
second, err := svc.RegenerateAPIKey(context.Background(), app.ID)
require.NoError(t, err)
assert.NotEqual(t, first.APIKey, second.APIKey, "each rotation should produce a different key")
}
// ========== Search ==========
func TestPlatformAppService_Search_EmptyQuery(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
// Create some apps so list is non-empty
createTestPlatformApp(t, db, account.ID, func(app *model.PlatformApp) { app.Name = "AlphaApp" })
createTestPlatformApp(t, db, account.ID, func(app *model.PlatformApp) { app.Name = "BetaApp" })
// Empty query should delegate to FindAll (return all apps)
apps, total, err := svc.Search(context.Background(), "", 0, 10)
require.NoError(t, err)
assert.Equal(t, int64(2), total)
assert.Len(t, apps, 2)
}
func TestPlatformAppService_Search_WithQuery(t *testing.T) {
// ILIKE requires PostgreSQL; SQLite does not support it.
// This test will skip if running against SQLite.
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
createTestPlatformApp(t, db, account.ID, func(app *model.PlatformApp) { app.Name = "MyAlphaApp" })
createTestPlatformApp(t, db, account.ID, func(app *model.PlatformApp) { app.Name = "MyBetaApp" })
apps, total, err := svc.Search(context.Background(), "Alpha", 0, 10)
if err != nil {
t.Logf("Search failed (likely SQLite ILIKE incompatibility): %v", err)
t.Skip("skip: SQLite does not support ILIKE (PlatformAppRepo.SearchByName needs PG)")
}
assert.Equal(t, int64(1), total)
assert.Len(t, apps, 1)
assert.Equal(t, "MyAlphaApp", apps[0].Name)
}
func TestPlatformAppService_SearchByAccount_EmptyQuery(t *testing.T) {
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
createTestPlatformApp(t, db, account.ID, func(app *model.PlatformApp) { app.Name = "App1" })
createTestPlatformApp(t, db, account.ID, func(app *model.PlatformApp) { app.Name = "App2" })
apps, total, err := svc.SearchByAccount(context.Background(), account.ID, "", 0, 10)
require.NoError(t, err)
assert.Equal(t, int64(2), total)
assert.Len(t, apps, 2)
}
func TestPlatformAppService_SearchByAccount_WithQuery(t *testing.T) {
// ILIKE requires PostgreSQL; SQLite does not support it.
db, _, svc := setupPlatformAppService(t)
account := createTestAccount(t, db)
createTestPlatformApp(t, db, account.ID, func(app *model.PlatformApp) { app.Name = "SearchApp1" })
createTestPlatformApp(t, db, account.ID, func(app *model.PlatformApp) { app.Name = "SearchApp2" })
apps, total, err := svc.SearchByAccount(context.Background(), account.ID, "App1", 0, 10)
if err != nil {
t.Logf("SearchByAccount failed (likely SQLite ILIKE incompatibility): %v", err)
t.Skip("skip: SQLite does not support ILIKE (PlatformAppRepo.SearchByNameByAccount needs PG)")
}
assert.Equal(t, int64(1), total)
assert.Len(t, apps, 1)
assert.Equal(t, "SearchApp1", apps[0].Name)
}