package services import ( "strings" "testing" "code.tczkiot.com/wlw/ai-agent/internal/models" "code.tczkiot.com/wlw/ai-agent/internal/pkg/dto" "code.tczkiot.com/wlw/ai-agent/internal/pkg/dto/request" "code.tczkiot.com/wlw/ai-agent/internal/pkg/enums" "github.com/glebarez/sqlite" "github.com/mlogclub/simple/sqls" "gorm.io/gorm" "gorm.io/gorm/schema" ) func TestUpdateAIAgentKeepsPublishedRevisionActive(t *testing.T) { dbName := strings.NewReplacer("/", "_", " ", "_").Replace(t.Name()) db, err := gorm.Open(sqlite.Open("file:"+dbName+"?mode=memory&cache=shared"), &gorm.Config{ NamingStrategy: schema.NamingStrategy{ TablePrefix: "t_", SingularTable: true, }, }) if err != nil { t.Fatalf("open sqlite: %v", err) } t.Cleanup(func() { sqlDB, dbErr := db.DB() if dbErr == nil { _ = sqlDB.Close() } }) if err := db.AutoMigrate(&models.AIConfig{}, &models.AIAgent{}); err != nil { t.Fatalf("auto migrate: %v", err) } sqls.SetDB(db) config := &models.AIConfig{ Name: "test", Status: enums.StatusOk, Provider: enums.AIProviderOpenAI, ModelType: enums.AIModelTypeLLM, ModelName: "test-model", } if err := db.Create(config).Error; err != nil { t.Fatalf("create ai config: %v", err) } createdModel, err := AIAgentService.buildAIAgentModel(0, request.CreateAIAgentRequest{ Name: "fixed ai reception agent", Avatar: " https://cdn.example.com/agent.png ", AIConfigID: config.ID, ServiceMode: enums.IMConversationServiceModeHumanOnly, HandoffMode: enums.AIAgentHandoffModeWaitPool, FallbackMode: enums.AIAgentFallbackModeNoAnswer, }) if err != nil { t.Fatalf("build ai agent model: %v", err) } if createdModel.ServiceMode != enums.IMConversationServiceModeAIFirst { t.Fatalf("service mode = %d, want AI first", createdModel.ServiceMode) } if createdModel.Avatar != "https://cdn.example.com/agent.png" { t.Fatalf("avatar = %q, want trimmed avatar URL", createdModel.Avatar) } agent := &models.AIAgent{ Name: "published agent", Status: enums.StatusOk, AIConfigID: config.ID, ServiceMode: enums.IMConversationServiceModeAIFirst, HandoffMode: enums.AIAgentHandoffModeWaitPool, FallbackMode: enums.AIAgentFallbackModeNoAnswer, RolloutPercent: 100, PublishedRevisionID: 18, } if err := db.Create(agent).Error; err != nil { t.Fatalf("create ai agent: %v", err) } err = AIAgentService.UpdateAIAgent(request.UpdateAIAgentRequest{ ID: agent.ID, CreateAIAgentRequest: request.CreateAIAgentRequest{ Name: "updated draft", Avatar: "https://cdn.example.com/updated.png", AIConfigID: config.ID, ServiceMode: enums.IMConversationServiceModeAIFirst, HandoffMode: enums.AIAgentHandoffModeWaitPool, FallbackMode: enums.AIAgentFallbackModeNoAnswer, RolloutPercent: 100, }, }, &dto.AuthPrincipal{UserID: 1, Username: "admin"}) if err != nil { t.Fatalf("UpdateAIAgent: %v", err) } var updated models.AIAgent if err := db.First(&updated, agent.ID).Error; err != nil { t.Fatalf("get updated ai agent: %v", err) } if updated.PublishedRevisionID != agent.PublishedRevisionID { t.Fatalf("published revision id = %d, want %d", updated.PublishedRevisionID, agent.PublishedRevisionID) } if updated.Name != "updated draft" { t.Fatalf("draft name = %q, want updated draft", updated.Name) } if updated.Avatar != "https://cdn.example.com/updated.png" { t.Fatalf("draft avatar = %q, want updated avatar", updated.Avatar) } }