3535import org .finos .waltz .model .entity_workflow .EntityWorkflowDefinition ;
3636import org .finos .waltz .model .logical_flow .ImmutableLogicalFlow ;
3737import org .finos .waltz .model .logical_flow .LogicalFlow ;
38- import org .finos .waltz .model .physical_flow .FlowAttributes ;
39- import org .finos .waltz .model .physical_flow .ImmutablePhysicalFlowCreateCommand ;
40- import org .finos .waltz .model .physical_flow .PhysicalFlowCreateCommandResponse ;
41- import org .finos .waltz .model .physical_flow .FrequencyKindValue ;
42- import org .finos .waltz .model .physical_flow .CriticalityValue ;
43- import org .finos .waltz .model .physical_flow .TransportKindValue ;
44- import org .finos .waltz .model .physical_flow .ImmutableFlowAttributes ;
38+ import org .finos .waltz .model .physical_flow .*;
4539import org .finos .waltz .model .physical_specification .PhysicalSpecification ;
46- import org .finos .waltz .model .proposed_flow .ProposedFlowResponse ;
47- import org .finos .waltz .model .proposed_flow .ProposedFlowCommand ;
48- import org .finos .waltz .model .proposed_flow .ImmutableProposedFlowCommand ;
49- import org .finos .waltz .model .proposed_flow .ProposedFlowCommandResponse ;
50- import org .finos .waltz .model .proposed_flow .ProposedFlowActionCommand ;
51- import org .finos .waltz .model .proposed_flow .ImmutableProposedFlowActionCommand ;
52- import org .finos .waltz .model .proposed_flow .FlowIdResponse ;
53- import org .finos .waltz .model .proposed_flow .ProposalType ;
54- import org .finos .waltz .model .proposed_flow .Reason ;
55- import org .finos .waltz .schema .tables .ProposedFlow ;
40+ import org .finos .waltz .model .proposed_flow .*;
5641import org .finos .waltz .schema .tables .records .InvolvementGroupRecord ;
5742import org .finos .waltz .service .changelog .ChangeLogService ;
5843import org .finos .waltz .service .data_flow .DataFlowService ;
6247import org .finos .waltz .service .proposed_flow_workflow .ProposedFlowWorkflowService ;
6348import org .finos .waltz .service .workflow_state_machine .exception .TransitionNotFoundException ;
6449import org .finos .waltz .service .workflow_state_machine .exception .TransitionPredicateFailedException ;
65- import org .finos .waltz .service .workflow_state_machine .proposed_flow .ProposedFlowWorkflowTransitionAction ;
6650import org .finos .waltz .test_common .helpers .*;
6751import org .jooq .DSLContext ;
6852import org .junit .jupiter .api .BeforeEach ;
6953import org .junit .jupiter .api .Test ;
70- import org .slf4j .Logger ;
71- import org .slf4j .LoggerFactory ;
7254import org .springframework .beans .factory .annotation .Autowired ;
7355
7456import java .time .LocalDateTime ;
75- import java .util .ArrayList ;
76- import java .util .List ;
7757import java .util .Optional ;
7858import java .util .Set ;
79- import java .util .concurrent .CountDownLatch ;
80- import java .util .concurrent .TimeUnit ;
8159
8260import static org .finos .waltz .common .DateTimeUtilities .nowUtc ;
8361import static org .finos .waltz .data .proposed_flow .ProposedFlowDao .PROPOSE_FLOW_LIFECYCLE_WORKFLOW ;
10078
10179public class ProposedFlowWorkflowServiceTest extends BaseInMemoryIntegrationTest {
10280
103- private static final Logger LOG = LoggerFactory .getLogger (ProposedFlowWorkflowServiceTest .class );
10481 private final String USER_NAME = "testUser" ;
10582
10683 @ Autowired
@@ -176,7 +153,7 @@ public class ProposedFlowWorkflowServiceTest extends BaseInMemoryIntegrationTest
176153
177154 @ BeforeEach
178155 public void setUp () {
179- dsl .deleteFrom (ProposedFlow .PROPOSED_FLOW ).execute ();
156+ dsl .deleteFrom (org . finos . waltz . schema . tables . ProposedFlow .PROPOSED_FLOW ).execute ();
180157 dsl .deleteFrom (PHYSICAL_FLOW ).execute ();
181158 dsl .deleteFrom (PHYSICAL_SPECIFICATION ).execute ();
182159 dsl .deleteFrom (LOGICAL_FLOW ).execute ();
@@ -421,7 +398,7 @@ void twoStepApproval_shouldTransitionToFullyApproved_andCallOperation() throws F
421398 .specification (physicalSpecification )
422399 .flowAttributes (flowAttributes )
423400 .dataTypeIds (dataTypeIdSet )
424- .proposalType (CREATE )
401+ .proposalType (ProposalType . CREATE )
425402 .build ();
426403
427404 String userName = mkName (USER_NAME , "user1" );
@@ -528,7 +505,7 @@ void proposedFlowAction_rejectionWithInvalidPermissions_throwsException() throws
528505 .specification (physicalSpecification )
529506 .flowAttributes (flowAttributes )
530507 .dataTypeIds (dataTypeIdSet )
531- .proposalType (CREATE )
508+ .proposalType (ProposalType . CREATE )
532509 .build ();
533510
534511 String userName = mkName (USER_NAME , "user1" );
@@ -545,7 +522,7 @@ void proposedFlowAction_rejectionWithInvalidPermissions_throwsException() throws
545522 // 2. Act ----------------------------------------------------
546523 ProposedFlowResponse proposedFlowResponse = proposedFlowWorkflowService .proposedFlowAction (
547524 proposedFlowId ,
548- ProposedFlowWorkflowTransitionAction .REJECT ,
525+ org . finos . waltz . service . workflow_state_machine . proposed_flow . ProposedFlowWorkflowTransitionAction .REJECT ,
549526 userName ,
550527 rejectCommand );
551528
@@ -573,7 +550,7 @@ public void testCannotApproveProposedFlowTwice() throws FlowCreationException, T
573550 .specification (physicalSpecification )
574551 .flowAttributes (flowAttributes )
575552 .dataTypeIds (dataTypeIdSet )
576- .proposalType (CREATE )
553+ .proposalType (ProposalType . CREATE )
577554 .build ();
578555
579556 String userName = mkName (USER_NAME , "user1" );
@@ -673,100 +650,4 @@ public void validateProposedFlow_shouldPassIfFlowAttributeIsDifferent() {
673650 // 3. Assert: Validation should pass
674651 assertNull (validationResponse , "Validation should pass when a flow attribute (e.g., frequency) is different" );
675652 }
676-
677- @ Test
678- public void multipleUsersCannotActOnFlowAtTheSameTime () throws FlowCreationException , TransitionNotFoundException {
679- Reason reason = proposedFlowWorkflowHelper .getReason ();
680- EntityReference owningEntity = proposedFlowWorkflowHelper .getOwningEntity ();
681- PhysicalSpecification physicalSpecification = proposedFlowWorkflowHelper .getPhysicalSpecification (owningEntity );
682- FlowAttributes flowAttributes = proposedFlowWorkflowHelper .getFlowAttributes ();
683- Set <Long > dataTypeIdSet = proposedFlowWorkflowHelper .getDataTypeIdSet ();
684-
685- EntityReference sourceRef = appHelper .createNewApp (mkName (USER_NAME , "concurrent_src" ), ouIds .a );
686- EntityReference targetRef = appHelper .createNewApp (mkName (USER_NAME , "concurrent_tgt" ), ouIds .a1 );
687-
688- ProposedFlowCommand command = ImmutableProposedFlowCommand .builder ()
689- .source (sourceRef )
690- .target (targetRef )
691- .reason (reason )
692- .specification (physicalSpecification )
693- .flowAttributes (flowAttributes )
694- .dataTypeIds (dataTypeIdSet )
695- .proposalType (CREATE )
696- .build ();
697-
698- ProposedFlowCommandResponse proposeResponse = proposedFlowWorkflowService .proposeNewFlow (USER_NAME , command );
699- Long proposedFlowId = proposeResponse .proposedFlowId ();
700- assertNotNull (proposedFlowId , "Proposed flow should be created" );
701-
702- String userA = mkName (USER_NAME , "concurrent_user_a" );
703- String userB = mkName (USER_NAME , "concurrent_user_b" );
704- Long personA = personHelper .createPerson (userA );
705- Long personB = personHelper .createPerson (userB );
706-
707- long involvementKind = involvementHelper .mkInvolvementKind ("rel_abcde" );
708- involvementHelper .createInvolvement (personA , involvementKind , sourceRef );
709- involvementHelper .createInvolvement (personB , involvementKind , targetRef );
710-
711- InvolvementGroupRecord ig = permissionHelper .setupInvolvementGroup (involvementKind , USER_NAME );
712- permissionHelper .setupPermissionGroupForProposedFlow (sourceRef , ig , USER_NAME , Operation .APPROVE );
713- permissionHelper .setupPermissionGroupForProposedFlow (targetRef , ig , USER_NAME , Operation .APPROVE );
714-
715- ProposedFlowActionCommand approveCommand = ImmutableProposedFlowActionCommand .builder ()
716- .comment ("Approved by source approver" )
717- .build ();
718-
719- CountDownLatch startGate = new CountDownLatch (1 );
720- CountDownLatch doneGate = new CountDownLatch (2 );
721-
722- List <ProposedFlowResponse > responses = new ArrayList <>();
723- List <Throwable > failures = new ArrayList <>();
724-
725- Runnable approveTaskUserA = () -> mkRunnableTask (startGate , doneGate , proposedFlowId , responses , failures , approveCommand , userA );
726- Runnable approveTaskUserB = () -> mkRunnableTask (startGate , doneGate , proposedFlowId , responses , failures , approveCommand , userB );
727-
728- Thread thread1 = new Thread (approveTaskUserA , "approve-user-a" );
729- Thread thread2 = new Thread (approveTaskUserB , "approve-user-b" );
730-
731- thread1 .start ();
732- thread2 .start ();
733-
734- try {
735- startGate .countDown ();
736- assertTrue (doneGate .await (10 , TimeUnit .SECONDS ), "Concurrent approve tasks did not finish in time" );
737- } catch (InterruptedException e ) {
738- LOG .error ("Thread interrupted" , e );
739- Thread .currentThread ().interrupt ();
740- }
741-
742- assertTrue (failures .isEmpty (), "Unexpected thread failure occurred, check logs for DB/transaction errors" );
743- assertEquals (2 , responses .size (), "Expected one response per user action" );
744- }
745-
746- private void mkRunnableTask (CountDownLatch startGate ,
747- CountDownLatch doneGate ,
748- Long proposedFlowId ,
749- List <ProposedFlowResponse > responses ,
750- List <Throwable > failures ,
751- ProposedFlowActionCommand approveCommand ,
752- String user ) {
753- try {
754- startGate .await (5 , TimeUnit .SECONDS );
755- ProposedFlowResponse response = proposedFlowWorkflowService .proposedFlowAction (
756- proposedFlowId ,
757- APPROVE ,
758- user ,
759- approveCommand );
760- synchronized (responses ) {
761- responses .add (response );
762- }
763- } catch (Exception e ) {
764- LOG .error ("Concurrent approve failed for user {}" , user , e );
765- synchronized (failures ) {
766- failures .add (e );
767- }
768- } finally {
769- doneGate .countDown ();
770- }
771- }
772653}
0 commit comments