mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-10-31 17:28:23 +00:00 
			
		
		
		
	Adjust test to work with actual workflow + minor fix of handler logic
This commit is contained in:
		| @@ -38,7 +38,7 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface | ||||
|     /** | ||||
|      * @var Collection<int, \Chill\MainBundle\Entity\Workflow\EntityWorkflowComment> | ||||
|      */ | ||||
|     #[ORM\OneToMany(targetEntity: EntityWorkflowComment::class, mappedBy: 'entityWorkflow', orphanRemoval: true)] | ||||
|     #[ORM\OneToMany(mappedBy: 'entityWorkflow', targetEntity: EntityWorkflowComment::class, orphanRemoval: true)] | ||||
|     private Collection $comments; | ||||
|  | ||||
|     #[ORM\Id] | ||||
|   | ||||
| @@ -35,7 +35,7 @@ class CancelStaleWorkflowHandler | ||||
|  | ||||
|         $workflow = $this->workflowRepository->find($workflowId); | ||||
|  | ||||
|         if (in_array($workflow, $staleWorkflows, true)) { | ||||
|         if (!in_array($workflow, $staleWorkflows, true)) { | ||||
|             $this->logger->alert('Workflow has transitioned in the meantime.', [$workflowId]); | ||||
|             return; | ||||
|         } | ||||
| @@ -69,7 +69,7 @@ class CancelStaleWorkflowHandler | ||||
|             } | ||||
|  | ||||
|             if (!$transitionApplied) { | ||||
|                 $this->logger->error('No valid transition found for EntityWorkflow %d.', [$workflowId]); | ||||
|                 $this->logger->error('No valid transition found for EntityWorkflow.', [$workflowId]); | ||||
|                 throw new UnrecoverableMessageHandlingException(sprintf('No valid transition found for EntityWorkflow %d.', $workflowId)); | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -2,139 +2,117 @@ | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| /* | ||||
|  * Chill is a software for social workers | ||||
|  * | ||||
|  * For the full copyright and license information, please view | ||||
|  * the LICENSE file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| namespace Services\Workflow; | ||||
|  | ||||
| use Chill\MainBundle\Entity\Workflow\EntityWorkflow; | ||||
| use Chill\MainBundle\Entity\Workflow\EntityWorkflowStep; | ||||
| use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository; | ||||
| use Chill\MainBundle\Service\Workflow\CancelStaleWorkflow; | ||||
| use Chill\MainBundle\Service\Workflow\CancelStaleWorkflowHandler; | ||||
| use Chill\MainBundle\Service\Workflow\CancelStaleWorkflowMessage; | ||||
| use Doctrine\Common\Collections\ArrayCollection; | ||||
| use Doctrine\ORM\EntityManagerInterface; | ||||
| use PHPUnit\Framework\TestCase; | ||||
| use Psr\Log\LoggerInterface; | ||||
| use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; | ||||
| use Symfony\Component\Workflow\Metadata\MetadataStoreInterface; | ||||
| use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; | ||||
| use Symfony\Component\Clock\ClockInterface; | ||||
| use Symfony\Component\Workflow\Registry; | ||||
| use Symfony\Component\Workflow\Transition; | ||||
| use Symfony\Component\Workflow\WorkflowInterface; | ||||
| use Symfony\Component\Yaml\Yaml; | ||||
| use DateTimeImmutable; | ||||
|  | ||||
| /** | ||||
|  * @internal | ||||
|  * | ||||
|  * @coversNothing | ||||
|  */ | ||||
| class CancelStaleWorkflowHandlerTest extends TestCase | ||||
| class CancelStaleWorkflowHandlerTest extends KernelTestCase | ||||
| { | ||||
|     public function testInvokeWorkflowWithOneStep(): void | ||||
|     private EntityManagerInterface $em; | ||||
|     private Registry $registry; | ||||
|     private LoggerInterface $logger; | ||||
|     private EntityWorkflowRepository $workflowRepository; | ||||
|     private ClockInterface $clock; | ||||
|     private string $workflowName; | ||||
|  | ||||
|     protected function setUp(): void | ||||
|     { | ||||
|         $workflow = $this->createMock(EntityWorkflow::class); | ||||
|         $workflow->method('getSteps')->willReturn(new ArrayCollection([$this->createMock(EntityWorkflowStep::class)])); | ||||
|         $workflow->expects($this->once())->method('getCurrentStep')->willReturn(new EntityWorkflowStep()); | ||||
|         // Boot the Symfony kernel | ||||
|         self::bootKernel(); | ||||
|  | ||||
|         $workflowRepository = $this->createMock(EntityWorkflowRepository::class); | ||||
|         $workflowRepository->expects($this->once())->method('find')->with($this->identicalTo(1))->willReturn($workflow); | ||||
|         // Get the actual services from the container | ||||
|         $this->em = self::getContainer()->get(EntityManagerInterface::class); | ||||
|         $this->registry = self::getContainer()->get(Registry::class); | ||||
|         $this->logger = self::getContainer()->get(LoggerInterface::class); | ||||
|         $this->clock = self::getContainer()->get(ClockInterface::class); | ||||
|         $this->workflowRepository = $this->createMock(EntityWorkflowRepository::class); | ||||
|  | ||||
|         $em = $this->createMock(EntityManagerInterface::class); | ||||
|         $em->expects($this->exactly(2))->method('remove')->with($this->isInstanceOf(EntityWorkflowStep::class)); | ||||
|         $em->expects($this->once())->method('flush'); | ||||
|         // Retrieve the workflow configuration dynamically | ||||
|         $configPath = self::$kernel->getProjectDir() . '/config/packages/workflow.yaml'; // Adjust the path if needed | ||||
|         $config = Yaml::parseFile($configPath); | ||||
|  | ||||
|         $registry = $this->createMock(Registry::class); | ||||
|         $logger = $this->createMock(LoggerInterface::class); | ||||
|  | ||||
|         $handler = new CancelStaleWorkflowHandler($workflowRepository, $registry, $em, $logger); | ||||
|  | ||||
|         $handler(new CancelStaleWorkflowMessage(1)); | ||||
|         // Extract the workflow name from the configuration | ||||
|         $this->workflowName = array_key_first($config['framework']['workflows']); | ||||
|     } | ||||
|  | ||||
|     public function testInvokeWorkflowWithMultipleStepsAndValidTransition(): void | ||||
|     public function testWorkflowWithOneStepOlderThan90DaysIsDeleted(): void | ||||
|     { | ||||
|         $workflow = $this->createMock(EntityWorkflow::class); | ||||
|         $workflow->method('getSteps')->willReturn(new ArrayCollection([$this->createMock(EntityWorkflowStep::class), $this->createMock(EntityWorkflowStep::class)])); | ||||
|         $workflow = new EntityWorkflow(); | ||||
|         $initialStep = new EntityWorkflowStep(); | ||||
|         $initialStep->setTransitionAt(new DateTimeImmutable('-93 days')); | ||||
|         $workflow->addStep($initialStep); | ||||
|  | ||||
|         $transition = $this->createMock(Transition::class); | ||||
|         $this->em->persist($workflow); | ||||
|         $this->em->flush(); | ||||
|  | ||||
|         $workflowComponent = $this->createMock(WorkflowInterface::class); | ||||
|         $registryMock = $this->createMock(Registry::class); | ||||
|         $registryMock->method('get') | ||||
|             ->willReturn($workflowComponent); | ||||
|         $this->handleStaleWorkflow($workflow); | ||||
|  | ||||
|         $workflowComponent->method('getEnabledTransitions')->willReturn([$transition]); | ||||
|         $workflowComponent->expects($this->once())->method('apply')->with($workflow, 'annule'); | ||||
|         $deletedWorkflow = $this->workflowRepository->find($workflow->getId()); | ||||
|         $this->assertNull($deletedWorkflow, 'The workflow should be deleted.'); | ||||
|  | ||||
|         $metadataStore = $this->createMock(MetadataStore::class); | ||||
|         $metadataStore->method('getMetadata')->willReturnMap([ | ||||
|             ['isFinal', $transition, true], | ||||
|             ['isFinalPositive', $transition, false], | ||||
|         ]); | ||||
|  | ||||
|         $workflowComponent->method('getMetadataStore')->willReturn($metadataStore); | ||||
|  | ||||
|         $workflowRepository = $this->createMock(EntityWorkflowRepository::class); | ||||
|         $workflowRepository->expects($this->once())->method('find')->with($this->identicalTo(1))->willReturn($workflow); | ||||
|  | ||||
|         $em = $this->createMock(EntityManagerInterface::class); | ||||
|         $em->expects($this->never())->method('remove'); | ||||
|         $em->expects($this->once())->method('flush'); | ||||
|  | ||||
|         $registry = $this->createMock(Registry::class); | ||||
|         $registry->method('get')->willReturn($workflowComponent); | ||||
|  | ||||
|         $logger = $this->createMock(LoggerInterface::class); | ||||
|         $logger->expects($this->once())->method('info')->with('EntityWorkflow 1 has been transitioned.'); | ||||
|  | ||||
|         $handler = new CancelStaleWorkflowHandler($workflowRepository, $registry, $em, $logger); | ||||
|  | ||||
|         $handler(new CancelStaleWorkflowMessage(1)); | ||||
|         $this->assertNull($this->em->getRepository(EntityWorkflowStep::class)->find($initialStep->getId()), 'The workflow step should be deleted.'); | ||||
|     } | ||||
|  | ||||
|     public function testInvokeWorkflowWithMultipleStepsAndNoValidTransition(): void | ||||
|     public function testWorkflowWithMultipleStepsAndNoRecentTransitionsIsCanceled(): void | ||||
|     { | ||||
|         $this->expectException(UnrecoverableMessageHandlingException::class); | ||||
|         $this->expectExceptionMessage('No valid transition found for EntityWorkflow 1.'); | ||||
|         $workflow = new EntityWorkflow(); | ||||
|         $step1 = new EntityWorkflowStep(); | ||||
|         $step2 = new EntityWorkflowStep(); | ||||
|  | ||||
|         $workflow = $this->createMock(EntityWorkflow::class); | ||||
|         $workflow->method('getSteps')->willReturn(new ArrayCollection([$this->createMock(EntityWorkflowStep::class), $this->createMock(EntityWorkflowStep::class)])); | ||||
|         $step1->setTransitionAt(new DateTimeImmutable('-92 days')); | ||||
|         $step2->setTransitionAt(new DateTimeImmutable('-91 days')); | ||||
|  | ||||
|         $transition = $this->createMock(Transition::class); | ||||
|         $workflow->addStep($step1); | ||||
|         $workflow->addStep($step2); | ||||
|  | ||||
|         $workflowComponent = $this->createMock(WorkflowInterface::class); | ||||
|         $registryMock = $this->createMock(Registry::class); | ||||
|         $registryMock->method('get') | ||||
|             ->willReturn($workflowComponent); | ||||
|         $workflowComponent->method('getEnabledTransitions')->willReturn([$transition]); | ||||
|         $this->em->persist($workflow); | ||||
|         $this->em->flush(); | ||||
|  | ||||
|         $metadataStore = $this->createMock(MetadataStoreInterface::class); | ||||
|         $metadataStore->method('getMetadata')->willReturnMap([ | ||||
|             ['isFinal', $transition, false], | ||||
|             ['isFinalPositive', $transition, true], | ||||
|         ]); | ||||
|         /** @var WorkflowInterface $workflowComponent */ | ||||
|         $workflowComponent = $this->registry->get($workflow, $this->workflowName); | ||||
|  | ||||
|         $workflowComponent->method('getMetadataStore')->willReturn($metadataStore); | ||||
|         $transitions = $workflowComponent->getEnabledTransitions($workflow); | ||||
|         $metadataStore = $workflowComponent->getMetadataStore(); | ||||
|  | ||||
|         $workflowRepository = $this->createMock(EntityWorkflowRepository::class); | ||||
|         $workflowRepository->expects($this->once())->method('find')->with($this->identicalTo(1))->willReturn($workflow); | ||||
|         $expectedTransition = null; | ||||
|  | ||||
|         $em = $this->createMock(EntityManagerInterface::class); | ||||
|         $em->expects($this->never())->method('remove'); | ||||
|         $em->expects($this->never())->method('flush'); | ||||
|         // Find the transition that was expected to be applied by the handler | ||||
|         foreach ($transitions as $transition) { | ||||
|             $isFinal = $metadataStore->getMetadata('isFinal', $transition); | ||||
|             $isFinalPositive = $metadataStore->getMetadata('isFinalPositive', $transition); | ||||
|  | ||||
|         $registry = $this->createMock(Registry::class); | ||||
|         $registry->method('get')->willReturn($workflowComponent); | ||||
|             if ($isFinal === true && $isFinalPositive === false) { | ||||
|                 $expectedTransition = $transition; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         $logger = $this->createMock(LoggerInterface::class); | ||||
|         $logger->expects($this->once())->method('error')->with('No valid transition found for EntityWorkflow 1.'); | ||||
|         $this->assertNotNull($expectedTransition, 'Expected to find a valid transition with isFinal = true and isFinalPositive = false.'); | ||||
|  | ||||
|         $handler = new CancelStaleWorkflowHandler($workflowRepository, $registry, $em, $logger); | ||||
|         $this->handleStaleWorkflow($workflow); | ||||
|         $updatedWorkflow = $this->workflowRepository->find($workflow->getId()); | ||||
|  | ||||
|         $this->assertEquals($expectedTransition->getName(), $updatedWorkflow->getCurrentStep()); | ||||
|  | ||||
|         $handler(new CancelStaleWorkflowMessage(1)); | ||||
|     } | ||||
|  | ||||
|     public function handleStaleWorkflow($workflow): void | ||||
|     { | ||||
|         $handler = new CancelStaleWorkflowHandler($this->workflowRepository, $this->registry, $this->em, $this->logger, $this->clock); | ||||
|         $handler(new CancelStaleWorkflowMessage($workflow->getId())); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user