42
42
import io .airbyte .workers .temporal .scheduling .state .WorkflowState ;
43
43
import io .airbyte .workers .temporal .spec .SpecWorkflow ;
44
44
import io .airbyte .workers .temporal .sync .SyncWorkflow ;
45
+ import io .temporal .api .enums .v1 .WorkflowExecutionStatus ;
46
+ import io .temporal .api .workflow .v1 .WorkflowExecutionInfo ;
47
+ import io .temporal .api .workflowservice .v1 .DescribeWorkflowExecutionResponse ;
48
+ import io .temporal .api .workflowservice .v1 .WorkflowServiceGrpc .WorkflowServiceBlockingStub ;
45
49
import io .temporal .client .BatchRequest ;
46
50
import io .temporal .client .WorkflowClient ;
51
+ import io .temporal .client .WorkflowClientOptions ;
47
52
import io .temporal .client .WorkflowOptions ;
53
+ import io .temporal .client .WorkflowStub ;
48
54
import io .temporal .serviceclient .WorkflowServiceStubs ;
49
55
import io .temporal .workflow .Functions .Proc ;
50
56
import java .io .IOException ;
@@ -79,19 +85,26 @@ class TemporalClientTest {
79
85
.withJobId (String .valueOf (JOB_ID ))
80
86
.withAttemptId ((long ) ATTEMPT_ID )
81
87
.withDockerImage (IMAGE_NAME1 );
88
+ private static final String NAMESPACE = "namespace" ;
82
89
83
90
private WorkflowClient workflowClient ;
84
91
private TemporalClient temporalClient ;
85
92
private Path logPath ;
86
93
private WorkflowServiceStubs workflowServiceStubs ;
94
+ private WorkflowServiceBlockingStub workflowServiceBlockingStub ;
87
95
private Configs configs ;
88
96
89
97
@ BeforeEach
90
98
void setup () throws IOException {
91
99
final Path workspaceRoot = Files .createTempDirectory (Path .of ("/tmp" ), "temporal_client_test" );
92
100
logPath = workspaceRoot .resolve (String .valueOf (JOB_ID )).resolve (String .valueOf (ATTEMPT_ID )).resolve (LogClientSingleton .LOG_FILENAME );
93
101
workflowClient = mock (WorkflowClient .class );
102
+ when (workflowClient .getOptions ()).thenReturn (WorkflowClientOptions .newBuilder ().setNamespace (NAMESPACE ).build ());
94
103
workflowServiceStubs = mock (WorkflowServiceStubs .class );
104
+ when (workflowClient .getWorkflowServiceStubs ()).thenReturn (workflowServiceStubs );
105
+ workflowServiceBlockingStub = mock (WorkflowServiceBlockingStub .class );
106
+ when (workflowServiceStubs .blockingStub ()).thenReturn (workflowServiceBlockingStub );
107
+ mockWorkflowStatus (WorkflowExecutionStatus .WORKFLOW_EXECUTION_STATUS_RUNNING );
95
108
temporalClient = spy (new TemporalClient (workflowClient , workspaceRoot , workflowServiceStubs , configs ));
96
109
}
97
110
@@ -336,6 +349,7 @@ void testDeleteConnectionOnDeletedWorkflow() {
336
349
when (mConnectionManagerWorkflow .getState ()).thenReturn (mWorkflowState );
337
350
when (mWorkflowState .isDeleted ()).thenReturn (true );
338
351
when (workflowClient .newWorkflowStub (any (), anyString ())).thenReturn (mConnectionManagerWorkflow );
352
+ mockWorkflowStatus (WorkflowExecutionStatus .WORKFLOW_EXECUTION_STATUS_COMPLETED );
339
353
340
354
temporalClient .deleteConnection (CONNECTION_ID );
341
355
@@ -393,6 +407,7 @@ void testUpdateConnectionDeletedWorkflow() {
393
407
when (mConnectionManagerWorkflow .getState ()).thenReturn (mWorkflowState );
394
408
when (mWorkflowState .isDeleted ()).thenReturn (true );
395
409
when (workflowClient .newWorkflowStub (any (), anyString ())).thenReturn (mConnectionManagerWorkflow );
410
+ mockWorkflowStatus (WorkflowExecutionStatus .WORKFLOW_EXECUTION_STATUS_COMPLETED );
396
411
397
412
temporalClient .update (CONNECTION_ID );
398
413
@@ -490,6 +505,7 @@ void testStartNewManualSyncDeletedWorkflow() {
490
505
when (mConnectionManagerWorkflow .getState ()).thenReturn (mWorkflowState );
491
506
when (mWorkflowState .isDeleted ()).thenReturn (true );
492
507
when (workflowClient .newWorkflowStub (any (), anyString ())).thenReturn (mConnectionManagerWorkflow );
508
+ mockWorkflowStatus (WorkflowExecutionStatus .WORKFLOW_EXECUTION_STATUS_COMPLETED );
493
509
494
510
final ManualOperationResult result = temporalClient .startNewManualSync (CONNECTION_ID );
495
511
@@ -568,6 +584,7 @@ void testStartNewCancellationDeletedWorkflow() {
568
584
when (mConnectionManagerWorkflow .getState ()).thenReturn (mWorkflowState );
569
585
when (mWorkflowState .isDeleted ()).thenReturn (true );
570
586
when (workflowClient .newWorkflowStub (any (), anyString ())).thenReturn (mConnectionManagerWorkflow );
587
+ mockWorkflowStatus (WorkflowExecutionStatus .WORKFLOW_EXECUTION_STATUS_COMPLETED );
571
588
572
589
final ManualOperationResult result = temporalClient .startNewCancellation (CONNECTION_ID );
573
590
@@ -656,6 +673,7 @@ void testResetConnectionDeletedWorkflow() {
656
673
when (mConnectionManagerWorkflow .getState ()).thenReturn (mWorkflowState );
657
674
when (mWorkflowState .isDeleted ()).thenReturn (true );
658
675
when (workflowClient .newWorkflowStub (any (), anyString ())).thenReturn (mConnectionManagerWorkflow );
676
+ mockWorkflowStatus (WorkflowExecutionStatus .WORKFLOW_EXECUTION_STATUS_COMPLETED );
659
677
660
678
final ManualOperationResult result = temporalClient .resetConnection (CONNECTION_ID );
661
679
@@ -667,4 +685,90 @@ void testResetConnectionDeletedWorkflow() {
667
685
668
686
}
669
687
688
+ @ Test
689
+ @ DisplayName ("Test manual operation on quarantined workflow causes a restart" )
690
+ void testManualOperationOnQuarantinedWorkflow () {
691
+ final ConnectionManagerWorkflow mConnectionManagerWorkflow = mock (ConnectionManagerWorkflow .class );
692
+ final WorkflowState mWorkflowState = mock (WorkflowState .class );
693
+ when (mConnectionManagerWorkflow .getState ()).thenReturn (mWorkflowState );
694
+ when (mWorkflowState .isQuarantined ()).thenReturn (true );
695
+ when (workflowClient .newWorkflowStub (any (), anyString ())).thenReturn (mConnectionManagerWorkflow );
696
+
697
+ final ConnectionManagerWorkflow mNewConnectionManagerWorkflow = mock (ConnectionManagerWorkflow .class );
698
+ final WorkflowState mNewWorkflowState = mock (WorkflowState .class );
699
+ when (mNewConnectionManagerWorkflow .getState ()).thenReturn (mNewWorkflowState );
700
+ when (mNewWorkflowState .isRunning ()).thenReturn (false ).thenReturn (true );
701
+ when (mNewConnectionManagerWorkflow .getJobInformation ()).thenReturn (new JobInformation (JOB_ID , ATTEMPT_ID ));
702
+ when (workflowClient .newWorkflowStub (any (Class .class ), any (WorkflowOptions .class ))).thenReturn (mNewConnectionManagerWorkflow );
703
+ final BatchRequest mBatchRequest = mock (BatchRequest .class );
704
+ when (workflowClient .newSignalWithStartRequest ()).thenReturn (mBatchRequest );
705
+
706
+ final WorkflowStub mWorkflowStub = mock (WorkflowStub .class );
707
+ when (workflowClient .newUntypedWorkflowStub (anyString ())).thenReturn (mWorkflowStub );
708
+
709
+ final ManualOperationResult result = temporalClient .startNewManualSync (CONNECTION_ID );
710
+
711
+ assertTrue (result .getJobId ().isPresent ());
712
+ assertEquals (JOB_ID , result .getJobId ().get ());
713
+ assertFalse (result .getFailingReason ().isPresent ());
714
+ verify (workflowClient ).signalWithStart (mBatchRequest );
715
+ verify (mWorkflowStub ).terminate (anyString ());
716
+
717
+ // Verify that the submitManualSync signal was passed to the batch request by capturing the
718
+ // argument,
719
+ // executing the signal, and verifying that the desired signal was executed
720
+ final ArgumentCaptor <Proc > batchRequestAddArgCaptor = ArgumentCaptor .forClass (Proc .class );
721
+ verify (mBatchRequest ).add (batchRequestAddArgCaptor .capture ());
722
+ final Proc signal = batchRequestAddArgCaptor .getValue ();
723
+ signal .apply ();
724
+ verify (mNewConnectionManagerWorkflow ).submitManualSync ();
725
+ }
726
+
727
+ @ Test
728
+ @ DisplayName ("Test manual operation on completed workflow causes a restart" )
729
+ void testManualOperationOnCompletedWorkflow () {
730
+ final ConnectionManagerWorkflow mConnectionManagerWorkflow = mock (ConnectionManagerWorkflow .class );
731
+ final WorkflowState mWorkflowState = mock (WorkflowState .class );
732
+ when (mConnectionManagerWorkflow .getState ()).thenReturn (mWorkflowState );
733
+ when (mWorkflowState .isQuarantined ()).thenReturn (false );
734
+ when (mWorkflowState .isDeleted ()).thenReturn (false );
735
+ when (workflowClient .newWorkflowStub (any (), anyString ())).thenReturn (mConnectionManagerWorkflow );
736
+ mockWorkflowStatus (WorkflowExecutionStatus .WORKFLOW_EXECUTION_STATUS_COMPLETED );
737
+
738
+ final ConnectionManagerWorkflow mNewConnectionManagerWorkflow = mock (ConnectionManagerWorkflow .class );
739
+ final WorkflowState mNewWorkflowState = mock (WorkflowState .class );
740
+ when (mNewConnectionManagerWorkflow .getState ()).thenReturn (mNewWorkflowState );
741
+ when (mNewWorkflowState .isRunning ()).thenReturn (false ).thenReturn (true );
742
+ when (mNewConnectionManagerWorkflow .getJobInformation ()).thenReturn (new JobInformation (JOB_ID , ATTEMPT_ID ));
743
+ when (workflowClient .newWorkflowStub (any (Class .class ), any (WorkflowOptions .class ))).thenReturn (mNewConnectionManagerWorkflow );
744
+ final BatchRequest mBatchRequest = mock (BatchRequest .class );
745
+ when (workflowClient .newSignalWithStartRequest ()).thenReturn (mBatchRequest );
746
+
747
+ final WorkflowStub mWorkflowStub = mock (WorkflowStub .class );
748
+ when (workflowClient .newUntypedWorkflowStub (anyString ())).thenReturn (mWorkflowStub );
749
+
750
+ final ManualOperationResult result = temporalClient .startNewManualSync (CONNECTION_ID );
751
+
752
+ assertTrue (result .getJobId ().isPresent ());
753
+ assertEquals (JOB_ID , result .getJobId ().get ());
754
+ assertFalse (result .getFailingReason ().isPresent ());
755
+ verify (workflowClient ).signalWithStart (mBatchRequest );
756
+ verify (mWorkflowStub ).terminate (anyString ());
757
+
758
+ // Verify that the submitManualSync signal was passed to the batch request by capturing the
759
+ // argument,
760
+ // executing the signal, and verifying that the desired signal was executed
761
+ final ArgumentCaptor <Proc > batchRequestAddArgCaptor = ArgumentCaptor .forClass (Proc .class );
762
+ verify (mBatchRequest ).add (batchRequestAddArgCaptor .capture ());
763
+ final Proc signal = batchRequestAddArgCaptor .getValue ();
764
+ signal .apply ();
765
+ verify (mNewConnectionManagerWorkflow ).submitManualSync ();
766
+ }
767
+
768
+ private void mockWorkflowStatus (final WorkflowExecutionStatus status ) {
769
+ when (workflowServiceBlockingStub .describeWorkflowExecution (any ())).thenReturn (
770
+ DescribeWorkflowExecutionResponse .newBuilder ().setWorkflowExecutionInfo (
771
+ WorkflowExecutionInfo .newBuilder ().setStatus (status ).buildPartial ()).build ());
772
+ }
773
+
670
774
}
0 commit comments