@@ -3,6 +3,7 @@ package dbos
33import (
44 "context"
55 "fmt"
6+ "log/slog"
67 "testing"
78 "time"
89
@@ -463,6 +464,48 @@ func TestCustomSystemDBSchema(t *testing.T) {
463464}
464465
465466func TestCustomPool (t * testing.T ) {
467+ // Test workflows for custom pool testing
468+ type customPoolWorkflowInput struct {
469+ PartnerWorkflowID string
470+ Message string
471+ }
472+
473+ // Workflow A: Uses Send() and GetEvent() - waits for workflow B
474+ sendGetEventWorkflowCustom := func (ctx DBOSContext , input customPoolWorkflowInput ) (string , error ) {
475+ // Send a message to the partner workflow
476+ err := Send (ctx , input .PartnerWorkflowID , input .Message , "custom-pool-topic" )
477+ if err != nil {
478+ return "" , err
479+ }
480+
481+ // Wait for an event from the partner workflow
482+ result , err := GetEvent [string ](ctx , input .PartnerWorkflowID , "custom-response-key" , 5 * time .Hour )
483+ if err != nil {
484+ return "" , err
485+ }
486+
487+ return result , nil
488+ }
489+
490+ // Workflow B: Uses Recv() and SetEvent() - waits for workflow A
491+ recvSetEventWorkflowCustom := func (ctx DBOSContext , input customPoolWorkflowInput ) (string , error ) {
492+ // Receive a message from the partner workflow
493+ receivedMsg , err := Recv [string ](ctx , "custom-pool-topic" , 5 * time .Hour )
494+ if err != nil {
495+ return "" , err
496+ }
497+
498+ time .Sleep (1 * time .Second )
499+
500+ // Set an event for the partner workflow
501+ err = SetEvent (ctx , "custom-response-key" , "response-from-custom-pool-workflow" )
502+ if err != nil {
503+ return "" , err
504+ }
505+
506+ return receivedMsg , nil
507+ }
508+
466509 t .Run ("NewSystemDatabaseWithCustomPool" , func (t * testing.T ) {
467510 // Custom Pool
468511 databaseURL := getDatabaseURL ()
@@ -506,6 +549,60 @@ func TestCustomPool(t *testing.T) {
506549 assert .Equal (t , 2 * time .Hour , sysdbConfig .MaxConnLifetime )
507550 assert .Equal (t , 2 * time .Minute , sysdbConfig .MaxConnIdleTime )
508551 assert .Equal (t , 10 * time .Second , sysdbConfig .ConnConfig .ConnectTimeout )
552+
553+ // Register the test workflows
554+ RegisterWorkflow (customdbosContext , sendGetEventWorkflowCustom )
555+ RegisterWorkflow (customdbosContext , recvSetEventWorkflowCustom )
556+
557+ // Launch the DBOS context
558+ err = customdbosContext .Launch ()
559+ require .NoError (t , err )
560+ defer dbosCtx .Shutdown (1 * time .Minute )
561+
562+ // Test RunWorkflow - start both workflows that will communicate with each other
563+ workflowAID := uuid .NewString ()
564+ workflowBID := uuid .NewString ()
565+
566+ // Start workflow B first (receiver)
567+ handleB , err := RunWorkflow (customdbosContext , recvSetEventWorkflowCustom , customPoolWorkflowInput {
568+ PartnerWorkflowID : workflowAID ,
569+ Message : "custom-pool-message-from-b" ,
570+ }, WithWorkflowID (workflowBID ))
571+ require .NoError (t , err , "failed to start recvSetEventWorkflowCustom" )
572+
573+ // Small delay to ensure workflow B is ready to receive
574+ time .Sleep (100 * time .Millisecond )
575+
576+ // Start workflow A (sender)
577+ handleA , err := RunWorkflow (customdbosContext , sendGetEventWorkflowCustom , customPoolWorkflowInput {
578+ PartnerWorkflowID : workflowBID ,
579+ Message : "custom-pool-message-from-a" ,
580+ }, WithWorkflowID (workflowAID ))
581+ require .NoError (t , err , "failed to start sendGetEventWorkflowCustom" )
582+
583+ // Wait for both workflows to complete
584+ resultA , err := handleA .GetResult ()
585+ require .NoError (t , err , "failed to get result from workflow A" )
586+ assert .Equal (t , "response-from-custom-pool-workflow" , resultA , "workflow A should receive response from workflow B" )
587+
588+ resultB , err := handleB .GetResult ()
589+ require .NoError (t , err , "failed to get result from workflow B" )
590+ assert .Equal (t , "custom-pool-message-from-a" , resultB , "workflow B should receive message from workflow A" )
591+
592+ // Test GetWorkflowSteps
593+ stepsA , err := GetWorkflowSteps (customdbosContext , workflowAID )
594+ require .NoError (t , err , "failed to get workflow A steps" )
595+ require .Len (t , stepsA , 3 , "workflow A should have 3 steps (Send + GetEvent + Sleep)" )
596+ assert .Equal (t , "DBOS.send" , stepsA [0 ].StepName , "first step should be Send" )
597+ assert .Equal (t , "DBOS.getEvent" , stepsA [1 ].StepName , "second step should be GetEvent" )
598+ assert .Equal (t , "DBOS.sleep" , stepsA [2 ].StepName , "third step should be Sleep" )
599+
600+ stepsB , err := GetWorkflowSteps (customdbosContext , workflowBID )
601+ require .NoError (t , err , "failed to get workflow B steps" )
602+ require .Len (t , stepsB , 3 , "workflow B should have 3 steps (Recv + Sleep + SetEvent)" )
603+ assert .Equal (t , "DBOS.recv" , stepsB [0 ].StepName , "first step should be Recv" )
604+ assert .Equal (t , "DBOS.sleep" , stepsB [1 ].StepName , "second step should be Sleep" )
605+ assert .Equal (t , "DBOS.setEvent" , stepsB [2 ].StepName , "third step should be SetEvent" )
509606 })
510607
511608 wf := func (ctx DBOSContext , input string ) (string , error ) {
@@ -539,4 +636,71 @@ func TestCustomPool(t *testing.T) {
539636 _ , err = RunWorkflow (dbosCtx , wf , "test-input" )
540637 require .NoError (t , err )
541638 })
639+
640+ t .Run ("InvalidCustomPool" , func (t * testing.T ) {
641+ databaseURL := getDatabaseURL ()
642+ poolConfig , err := pgxpool .ParseConfig (databaseURL )
643+ require .NoError (t , err )
644+ poolConfig .ConnConfig .Host = "invalid-host"
645+ pool , err := pgxpool .NewWithConfig (context .Background (), poolConfig )
646+ require .NoError (t , err )
647+
648+ config := Config {
649+ DatabaseURL : databaseURL ,
650+ AppName : "test-invalid-custom-pool" ,
651+ SystemDBPool : pool ,
652+ }
653+ _ , err = NewDBOSContext (context .Background (), config )
654+ require .Error (t , err )
655+ dbosErr , ok := err .(* DBOSError )
656+ require .True (t , ok , "expected DBOSError, got %T" , err )
657+ assert .Equal (t , InitializationError , dbosErr .Code )
658+ expectedMsg := "Error initializing DBOS Transact: failed to create system database"
659+ assert .Contains (t , dbosErr .Message , expectedMsg )
660+ })
661+
662+ t .Run ("DirectSystemDatabase" , func (t * testing.T ) {
663+ ctx , cancel := context .WithCancel (context .Background ())
664+ databaseURL := getDatabaseURL ()
665+ logger := slog .Default ()
666+
667+ // Create custom pool
668+ poolConfig , err := pgxpool .ParseConfig (databaseURL )
669+ require .NoError (t , err )
670+ poolConfig .MaxConns = 15
671+ poolConfig .MinConns = 3
672+ customPool , err := pgxpool .NewWithConfig (ctx , poolConfig )
673+ require .NoError (t , err )
674+ defer customPool .Close ()
675+
676+ // Create system database with custom pool
677+ sysDBInput := newSystemDatabaseInput {
678+ databaseURL : databaseURL ,
679+ databaseSchema : "dbos_test_custom_direct" ,
680+ customPool : customPool ,
681+ logger : logger ,
682+ }
683+
684+ systemDB , err := newSystemDatabase (ctx , sysDBInput )
685+ require .NoError (t , err , "failed to create system database with custom pool" )
686+ require .NotNil (t , systemDB )
687+
688+ // Launch the system database
689+ systemDB .launch (ctx )
690+
691+ require .Eventually (t , func () bool {
692+ conn , err := systemDB .(* sysDB ).pool .Acquire (ctx )
693+ require .NoError (t , err )
694+ defer conn .Release ()
695+ err = conn .Ping (ctx )
696+ require .NoError (t , err )
697+ return true
698+ }, 5 * time .Second , 100 * time .Millisecond , "system database should be reachable" )
699+
700+ // Shutdown the system database
701+ cancel () // Cancel context
702+ shutdownTimeout := 2 * time .Second
703+ systemDB .shutdown (ctx , shutdownTimeout )
704+ assert .False (t , systemDB .(* sysDB ).launched )
705+ })
542706}
0 commit comments