diff --git a/.github/workflows/quality.yaml b/.github/workflows/quality.yaml index 20e81bc..f2b7350 100644 --- a/.github/workflows/quality.yaml +++ b/.github/workflows/quality.yaml @@ -17,6 +17,7 @@ permissions: jobs: symfony-tests: strategy: + fail-fast: false matrix: php: ['8.0', '8.1', '8.2', '8.3'] runs-on: ubuntu-latest @@ -64,4 +65,4 @@ jobs: cd tests/Application bin/console doctrine:migration:migrate -n - name: Execute tests (Unit and Feature tests) via PHPUnit - run: vendor/bin/phpunit + run: vendor/bin/phpunit --process-isolation diff --git a/lib/Win32ServiceBundle.php b/lib/Win32ServiceBundle.php index d8825c0..98c8f44 100644 --- a/lib/Win32ServiceBundle.php +++ b/lib/Win32ServiceBundle.php @@ -16,7 +16,7 @@ use Win32ServiceBundle\DependencyInjection\TagRunnerCompilerPass; class Win32ServiceBundle extends Bundle { - public function build(ContainerBuilder $container) + public function build(ContainerBuilder $container): void { $autoconfig = $container->registerForAutoconfiguration(RunnerServiceInterface::class); $autoconfig->addTag(TagRunnerCompilerPass::WIN32SERVICE_RUNNER_TAG); diff --git a/tests/Application/config/packages/messenger.yaml b/tests/Application/config/packages/messenger.yaml index f73c7a4..4b9c3cd 100644 --- a/tests/Application/config/packages/messenger.yaml +++ b/tests/Application/config/packages/messenger.yaml @@ -17,3 +17,5 @@ framework: # 'App\Message\YourMessage': async 'Win32ServiceBundle\Tests\Application\Event\TestMessage': async 'Win32ServiceBundle\Tests\Application\Event\TestRetryMessage': async + 'Win32ServiceBundle\Tests\Application\Event\TestMemoryLimitMessage': async + 'Win32ServiceBundle\Tests\Application\Event\TestTimeLimitMessage': async diff --git a/tests/Application/config/packages/win32service.yaml b/tests/Application/config/packages/win32service.yaml index 200d8e1..9c76325 100644 --- a/tests/Application/config/packages/win32service.yaml +++ b/tests/Application/config/packages/win32service.yaml @@ -6,5 +6,6 @@ win32_service: limit: 10 displayed_name: Demo Messenger Consumer Async %d thread_count: 2 - memory_limit: 3600 + memory_limit: 128M + time_limit: 1 diff --git a/tests/Application/src/Event/TestMemoryLimitMessage.php b/tests/Application/src/Event/TestMemoryLimitMessage.php new file mode 100644 index 0000000..c175176 --- /dev/null +++ b/tests/Application/src/Event/TestMemoryLimitMessage.php @@ -0,0 +1,12 @@ +logger->info('Memory Limit Message : '.$message->size); + $this->buffer = str_repeat('-*+45defse', (int) ($message->size / 10)); + } +} diff --git a/tests/Application/src/Handler/TimeLimitMessageHandler.php b/tests/Application/src/Handler/TimeLimitMessageHandler.php new file mode 100644 index 0000000..8a42669 --- /dev/null +++ b/tests/Application/src/Handler/TimeLimitMessageHandler.php @@ -0,0 +1,23 @@ +logger->info('Time Limit Message : '.$message->durationInSeconds); + sleep($message->durationInSeconds); + } +} diff --git a/tests/Unit/MessengerIntegration/LimitNbMessageTest.php b/tests/Unit/MessengerIntegration/LimitNbMessageTest.php new file mode 100644 index 0000000..b32c722 --- /dev/null +++ b/tests/Unit/MessengerIntegration/LimitNbMessageTest.php @@ -0,0 +1,78 @@ +get('doctrine.dbal.default_connection'); + $connexion->rollBack(); + } + + public function testLimitMessage(): void + { + $serviceName = 'win32service.demo.messenger.async.0'; + self::bootKernel(); + $container = static::getContainer(); + + /** @var Connection $connexion */ + $connexion = $container->get('doctrine.dbal.default_connection'); + $connexion->beginTransaction(); + $connexion->query('DELETE FROM messenger_messages'); + /** @var MessageBusInterface $messengerBus */ + $messengerBus = $container->get('messenger.bus.default'); + $messagesTotal = 20; + for ($i = 1; $i <= $messagesTotal; ++$i) { + $messengerBus->dispatch(new TestMessage('message '.$i)); + } + + $c = $connexion->query('SELECT count(*) FROM messenger_messages WHERE queue_name = \'default\''); + + $this->assertSame($messagesTotal, (int) $c->fetchOne()); + + $runnerManager = $container->get(RunnerManager::class); + $serviceConfigurationManager = $container->get(ServiceConfigurationManager::class); + /** @var MessengerServiceRunner $runner */ + $runner = $runnerManager->getRunner($serviceConfigurationManager->getRunnerAliasForServiceId($serviceName)); + $runner->setServiceId(new ServiceIdentifier($serviceName)); + $runner->doRun($messagesTotal, 0); + + $rClass = new \ReflectionClass(AbstractServiceRunner::class); + $value = $rClass->getProperty('stopRequested'); + $value->setAccessible(true); + + $this->assertTrue($value->getValue($runner)); + + $c = $connexion->query('SELECT count(*) FROM messenger_messages WHERE queue_name = \'default\' AND delivered_at IS NULL'); + + $this->assertSame(10, (int) $c->fetchOne()); + + $c = $connexion->query('SELECT count(*) FROM messenger_messages WHERE queue_name = \'default\' AND delivered_at IS NOT NULL'); + // Other message has been deleted, only last processed message is keep + $this->assertSame(1, (int) $c->fetchOne()); + } +} diff --git a/tests/Unit/MessengerIntegration/MemoryLimitMessageTest.php b/tests/Unit/MessengerIntegration/MemoryLimitMessageTest.php new file mode 100644 index 0000000..e283992 --- /dev/null +++ b/tests/Unit/MessengerIntegration/MemoryLimitMessageTest.php @@ -0,0 +1,77 @@ +get('doctrine.dbal.default_connection'); + $connexion->rollBack(); + } + + public function testMemoryLimitMessage(): void + { + $serviceName = 'win32service.demo.messenger.async.0'; + self::bootKernel(); + $container = static::getContainer(); + + /** @var Connection $connexion */ + $connexion = $container->get('doctrine.dbal.default_connection'); + $connexion->beginTransaction(); + $connexion->query('DELETE FROM messenger_messages'); + /** @var MessageBusInterface $messengerBus */ + $messengerBus = $container->get('messenger.bus.default'); + $messengerBus->dispatch(new TestMemoryLimitMessage( /* 129 Mio */1024 * 1024 * 129)); + $messengerBus->dispatch(new TestMessage('message 1')); + + $c = $connexion->query('SELECT count(*) FROM messenger_messages WHERE queue_name = \'default\''); + + $this->assertSame(2, (int) $c->fetchOne()); + + $runnerManager = $container->get(RunnerManager::class); + $serviceConfigurationManager = $container->get(ServiceConfigurationManager::class); + /** @var MessengerServiceRunner $runner */ + $runner = $runnerManager->getRunner($serviceConfigurationManager->getRunnerAliasForServiceId($serviceName)); + $runner->setServiceId(new ServiceIdentifier($serviceName)); + $runner->doRun(5, 0); + + $rClass = new \ReflectionClass(AbstractServiceRunner::class); + $value = $rClass->getProperty('stopRequested'); + $value->setAccessible(true); + + $this->assertTrue($value->getValue($runner)); + + $c = $connexion->query('SELECT count(*) FROM messenger_messages WHERE queue_name = \'default\' AND delivered_at IS NULL'); + + $this->assertSame(1, (int) $c->fetchOne()); + + $c = $connexion->query('SELECT count(*) FROM messenger_messages WHERE queue_name = \'default\' AND delivered_at IS NOT NULL'); + + $this->assertSame(1, (int) $c->fetchOne()); + } +} diff --git a/tests/Unit/MessengerIntegration/MessageTest.php b/tests/Unit/MessengerIntegration/MessageTest.php new file mode 100644 index 0000000..9a527f1 --- /dev/null +++ b/tests/Unit/MessengerIntegration/MessageTest.php @@ -0,0 +1,68 @@ +get('doctrine.dbal.default_connection'); + $connexion->rollBack(); + } + + public function testNormalMessage(): void + { + $serviceName = 'win32service.demo.messenger.async.0'; + self::bootKernel(); + $container = static::getContainer(); + + /** @var Connection $connexion */ + $connexion = $container->get('doctrine.dbal.default_connection'); + $connexion->beginTransaction(); + $connexion->query('DELETE FROM messenger_messages'); + /** @var MessageBusInterface $messengerBus */ + $messengerBus = $container->get('messenger.bus.default'); + $messengerBus->dispatch(new TestMessage('message 1')); + + $c = $connexion->query('SELECT count(*) FROM messenger_messages WHERE queue_name = \'default\''); + + $this->assertSame(1, (int) $c->fetchOne()); + + $runnerManager = $container->get(RunnerManager::class); + $serviceConfigurationManager = $container->get(ServiceConfigurationManager::class); + /** @var MessengerServiceRunner $runner */ + $runner = $runnerManager->getRunner($serviceConfigurationManager->getRunnerAliasForServiceId($serviceName)); + $runner->setServiceId(new ServiceIdentifier($serviceName)); + $runner->doRun(1, 0); + + $c = $connexion->query('SELECT count(*) FROM messenger_messages WHERE queue_name = \'default\' AND delivered_at IS NULL'); + + $this->assertSame(0, (int) $c->fetchOne()); + + $c = $connexion->query('SELECT count(*) FROM messenger_messages WHERE queue_name = \'default\' AND delivered_at IS NOT NULL'); + + $this->assertSame(1, (int) $c->fetchOne()); + } +} diff --git a/tests/Unit/MessengerIntegration/RetryMessageTest.php b/tests/Unit/MessengerIntegration/RetryMessageTest.php index e80c372..05459c2 100644 --- a/tests/Unit/MessengerIntegration/RetryMessageTest.php +++ b/tests/Unit/MessengerIntegration/RetryMessageTest.php @@ -10,6 +10,7 @@ use Doctrine\DBAL\Driver\Connection; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\Messenger\MessageBusInterface; use Win32Service\Model\ServiceIdentifier; +use Win32Service\Model\Win32serviceState; use Win32ServiceBundle\Model\MessengerServiceRunner; use Win32ServiceBundle\Service\RunnerManager; use Win32ServiceBundle\Service\ServiceConfigurationManager; @@ -17,6 +18,11 @@ use Win32ServiceBundle\Tests\Application\Event\TestRetryMessage; final class RetryMessageTest extends KernelTestCase { + protected function setUp(): void + { + Win32serviceState::reset(); + } + protected function tearDown(): void { $container = static::getContainer(); diff --git a/tests/Unit/MessengerIntegration/TimeLimitMessageTest.php b/tests/Unit/MessengerIntegration/TimeLimitMessageTest.php new file mode 100644 index 0000000..e8baa4f --- /dev/null +++ b/tests/Unit/MessengerIntegration/TimeLimitMessageTest.php @@ -0,0 +1,77 @@ +get('doctrine.dbal.default_connection'); + $connexion->rollBack(); + } + + public function testTimeLimitMessage(): void + { + $serviceName = 'win32service.demo.messenger.async.0'; + self::bootKernel(); + $container = static::getContainer(); + + /** @var Connection $connexion */ + $connexion = $container->get('doctrine.dbal.default_connection'); + $connexion->beginTransaction(); + $connexion->query('DELETE FROM messenger_messages'); + /** @var MessageBusInterface $messengerBus */ + $messengerBus = $container->get('messenger.bus.default'); + $messengerBus->dispatch(new TestTimeLimitMessage(2)); + $messengerBus->dispatch(new TestMessage('message 1')); + + $c = $connexion->query('SELECT count(*) FROM messenger_messages WHERE queue_name = \'default\''); + + $this->assertSame(2, (int) $c->fetchOne()); + + $runnerManager = $container->get(RunnerManager::class); + $serviceConfigurationManager = $container->get(ServiceConfigurationManager::class); + /** @var MessengerServiceRunner $runner */ + $runner = $runnerManager->getRunner($serviceConfigurationManager->getRunnerAliasForServiceId($serviceName)); + $runner->setServiceId(new ServiceIdentifier($serviceName)); + $runner->doRun(5, 0); + + $rClass = new \ReflectionClass(AbstractServiceRunner::class); + $value = $rClass->getProperty('stopRequested'); + $value->setAccessible(true); + + $this->assertTrue($value->getValue($runner)); + + $c = $connexion->query('SELECT count(*) FROM messenger_messages WHERE queue_name = \'default\' AND delivered_at IS NULL'); + + $this->assertSame(1, (int) $c->fetchOne()); + + $c = $connexion->query('SELECT count(*) FROM messenger_messages WHERE queue_name = \'default\' AND delivered_at IS NOT NULL'); + + $this->assertSame(1, (int) $c->fetchOne()); + } +} diff --git a/tests/Win32serviceState.php b/tests/Win32serviceState.php index e5c7694..d3db917 100644 --- a/tests/Win32serviceState.php +++ b/tests/Win32serviceState.php @@ -2,6 +2,10 @@ declare(strict_types=1); +/** + * Mock for service library abstact. + */ + namespace Win32Service\Model; function win32_start_service_ctrl_dispatcher(string $serviceName): bool @@ -38,6 +42,11 @@ class Win32serviceState return self::$instance; } + public static function reset(): void + { + self::$instance = null; + } + public function setServiceName(string $serviceName): bool { if ($this->serviceName === null) {