509 lines
15 KiB
Plaintext
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)
|
|
}
|