@@ -4131,3 +4131,156 @@ func TestSpecialSteps(t *testing.T) {
41314131 require .Equal (t , "success" , result , "workflow should return success" )
41324132 })
41334133}
4134+
4135+ func TestRegisteredWorkflowListing (t * testing.T ) {
4136+ dbosCtx := setupDBOS (t , true , true )
4137+
4138+ // Register some regular workflows
4139+ RegisterWorkflow (dbosCtx , simpleWorkflow )
4140+ RegisterWorkflow (dbosCtx , simpleWorkflowError , WithMaxRetries (5 ))
4141+ RegisterWorkflow (dbosCtx , simpleWorkflowWithStep , WithWorkflowName ("CustomStepWorkflow" ))
4142+
4143+ // Register some scheduled workflows
4144+ RegisterWorkflow (dbosCtx , func (ctx DBOSContext , scheduledTime time.Time ) (string , error ) {
4145+ return "scheduled" , nil
4146+ }, WithSchedule ("0 0 * * * *" ), WithMaxRetries (3 ), WithWorkflowName ("DailyWorkflow" ))
4147+
4148+ RegisterWorkflow (dbosCtx , func (ctx DBOSContext , scheduledTime time.Time ) (string , error ) {
4149+ return "hourly" , nil
4150+ }, WithSchedule ("0 0 * * * *" ))
4151+
4152+ // Stop the cron scheduler to prevent goroutine leaks in tests
4153+ // The scheduler is started when scheduled workflows are registered
4154+ if dbosCtx .(* dbosContext ).workflowScheduler != nil {
4155+ ctx := dbosCtx .(* dbosContext ).workflowScheduler .Stop ()
4156+ <- ctx .Done () // Wait for it to stop
4157+ dbosCtx .(* dbosContext ).workflowScheduler = nil
4158+ }
4159+
4160+ t .Run ("ListRegisteredWorkflows" , func (t * testing.T ) {
4161+ workflows := dbosCtx .(* dbosContext ).listRegisteredWorkflows ()
4162+
4163+ // Should have at least 5 workflows (3 regular + 2 scheduled)
4164+ require .GreaterOrEqual (t , len (workflows ), 5 , "Should have at least 5 registered workflows" )
4165+
4166+ // Create a map for easier lookup
4167+ workflowMap := make (map [string ]RegisteredWorkflowInfo )
4168+ for _ , wf := range workflows {
4169+ workflowMap [wf .FQN ] = wf
4170+ }
4171+
4172+ // Check that simpleWorkflow is registered
4173+ simpleWorkflowFQN := runtime .FuncForPC (reflect .ValueOf (simpleWorkflow ).Pointer ()).Name ()
4174+ simpleWf , exists := workflowMap [simpleWorkflowFQN ]
4175+ require .True (t , exists , "simpleWorkflow should be registered" )
4176+ require .Equal (t , _DEFAULT_MAX_RECOVERY_ATTEMPTS , simpleWf .MaxRetries , "simpleWorkflow should have default max retries" )
4177+ require .Empty (t , simpleWf .CustomName , "simpleWorkflow should not have custom name" )
4178+
4179+ // Check that simpleWorkflowError is registered with custom max retries
4180+ simpleWorkflowErrorFQN := runtime .FuncForPC (reflect .ValueOf (simpleWorkflowError ).Pointer ()).Name ()
4181+ errorWf , exists := workflowMap [simpleWorkflowErrorFQN ]
4182+ require .True (t , exists , "simpleWorkflowError should be registered" )
4183+ require .Equal (t , 5 , errorWf .MaxRetries , "simpleWorkflowError should have custom max retries" )
4184+
4185+ // Check that custom named workflow is registered
4186+ var customWf RegisteredWorkflowInfo
4187+ for _ , wf := range workflows {
4188+ if wf .CustomName == "CustomStepWorkflow" {
4189+ customWf = wf
4190+ break
4191+ }
4192+ }
4193+ require .NotEmpty (t , customWf .FQN , "CustomStepWorkflow should be found" )
4194+ require .Equal (t , "CustomStepWorkflow" , customWf .CustomName , "Custom name should be preserved" )
4195+ })
4196+
4197+ t .Run ("ListRegisteredWorkflowsPackageFunction" , func (t * testing.T ) {
4198+ workflows , err := ListRegisteredWorkflows (dbosCtx )
4199+ require .NoError (t , err , "ListRegisteredWorkflows should not return an error" )
4200+ require .GreaterOrEqual (t , len (workflows ), 5 , "Should have at least 5 registered workflows" )
4201+
4202+ // Create a map for easier lookup
4203+ workflowMap := make (map [string ]RegisteredWorkflowInfo )
4204+ for _ , wf := range workflows {
4205+ workflowMap [wf .FQN ] = wf
4206+ }
4207+
4208+ // Check that simpleWorkflow is registered
4209+ simpleWorkflowFQN := runtime .FuncForPC (reflect .ValueOf (simpleWorkflow ).Pointer ()).Name ()
4210+ simpleWf , exists := workflowMap [simpleWorkflowFQN ]
4211+ require .True (t , exists , "simpleWorkflow should be registered" )
4212+ require .Equal (t , _DEFAULT_MAX_RECOVERY_ATTEMPTS , simpleWf .MaxRetries , "simpleWorkflow should have default max retries" )
4213+ require .Empty (t , simpleWf .CustomName , "simpleWorkflow should not have custom name" )
4214+ })
4215+
4216+ t .Run ("ListScheduledWorkflows" , func (t * testing.T ) {
4217+ scheduledWorkflows := dbosCtx .(* dbosContext ).listScheduledWorkflows ()
4218+
4219+ // Should have exactly 2 scheduled workflows
4220+ require .Equal (t , 2 , len (scheduledWorkflows ), "Should have exactly 2 scheduled workflows" )
4221+
4222+ // Create a map for easier lookup
4223+ scheduledMap := make (map [string ]ScheduledWorkflowInfo )
4224+ for _ , wf := range scheduledWorkflows {
4225+ scheduledMap [wf .FQN ] = wf
4226+ }
4227+
4228+ // Check that both scheduled workflows have cron schedules
4229+ for _ , wf := range scheduledWorkflows {
4230+ require .NotEmpty (t , wf .CronSchedule , "Scheduled workflow should have cron schedule" )
4231+ require .Equal (t , "0 0 * * * *" , wf .CronSchedule , "Both scheduled workflows should have the same schedule" )
4232+ }
4233+
4234+ // Check that one has a custom name
4235+ var hasCustomName bool
4236+ for _ , wf := range scheduledWorkflows {
4237+ if wf .CustomName == "DailyWorkflow" {
4238+ hasCustomName = true
4239+ require .Equal (t , 3 , wf .MaxRetries , "DailyWorkflow should have custom max retries" )
4240+ break
4241+ }
4242+ }
4243+ require .True (t , hasCustomName , "One scheduled workflow should have custom name" )
4244+ })
4245+
4246+ t .Run ("ListScheduledWorkflowsPackageFunction" , func (t * testing.T ) {
4247+ scheduledWorkflows , err := ListScheduledWorkflows (dbosCtx )
4248+ require .NoError (t , err , "ListScheduledWorkflows should not return an error" )
4249+ require .Equal (t , 2 , len (scheduledWorkflows ), "Should have exactly 2 scheduled workflows" )
4250+
4251+ // Create a map for easier lookup
4252+ scheduledMap := make (map [string ]ScheduledWorkflowInfo )
4253+ for _ , wf := range scheduledWorkflows {
4254+ scheduledMap [wf .FQN ] = wf
4255+ }
4256+
4257+ // Check that both scheduled workflows have cron schedules
4258+ for _ , wf := range scheduledWorkflows {
4259+ require .NotEmpty (t , wf .CronSchedule , "Scheduled workflow should have cron schedule" )
4260+ require .Equal (t , "0 0 * * * *" , wf .CronSchedule , "Both scheduled workflows should have the same schedule" )
4261+ }
4262+
4263+ // Check that one has a custom name
4264+ var hasCustomName bool
4265+ for _ , wf := range scheduledWorkflows {
4266+ if wf .CustomName == "DailyWorkflow" {
4267+ hasCustomName = true
4268+ require .Equal (t , 3 , wf .MaxRetries , "DailyWorkflow should have custom max retries" )
4269+ break
4270+ }
4271+ }
4272+ require .True (t , hasCustomName , "One scheduled workflow should have custom name" )
4273+ })
4274+
4275+ t .Run ("EmptyRegistry" , func (t * testing.T ) {
4276+ // Create a new context without any registered workflow
4277+ emptyCtx := setupDBOS (t , true , false )
4278+
4279+ workflows := emptyCtx .(* dbosContext ).listRegisteredWorkflows ()
4280+ require .Empty (t , workflows , "Empty context should have no registered workflows" )
4281+
4282+ scheduledWorkflows := emptyCtx .(* dbosContext ).listScheduledWorkflows ()
4283+ require .Empty (t , scheduledWorkflows , "Empty context should have no scheduled workflows" )
4284+ })
4285+
4286+ }
0 commit comments