From fe00850684223e226898cf1d3cf9adce58560e2a Mon Sep 17 00:00:00 2001 From: bota Date: Fri, 1 Aug 2025 12:43:14 +0300 Subject: [PATCH 01/10] Issue #50: Tests to improve code coverage Signed-off-by: bota --- composer.json | 3 +- src/App/ConfigProvider.php | 10 +- .../{ExampleMessage.php => Message.php} | 2 +- ...eMessageHandler.php => MessageHandler.php} | 10 +- src/Swoole/Delegators/TCPServerDelegator.php | 6 +- test/App/AppConfigProviderTest.php | 23 ++ test/App/Message/MessageHandlerTest.php | 153 ++++++++++++ test/App/Message/MessageTest.php | 17 ++ .../Factory/StartCommandFactoryTest.php | 27 ++ .../Factory/StopCommandFactoryTest.php | 35 +++ .../Command/GetDataFromLogsCommandTest.php | 202 +++++++++++++++ .../Command/GetQueuedMessagesCommandTest.php | 103 ++++++++ test/Swoole/Command/IsRunningTraitTest.php | 41 ++++ test/Swoole/Command/StartCommandTest.php | 92 +++++++ test/Swoole/Command/StopCommandTest.php | 90 +++++++ test/Swoole/Delegators/DummySwooleServer.php | 37 +++ .../Delegators/TCPServerDelegatorTest.php | 231 ++++++++++++++++++ ...dStaticResourceMiddlewareExceptionTest.php | 32 +++ test/Swoole/PidManagerFactoryTest.php | 54 ++++ test/Swoole/PidManagerTest.php | 92 +++++++ test/Swoole/ServerFactoryTest.php | 147 +++++++++++ 21 files changed, 1392 insertions(+), 15 deletions(-) rename src/App/Message/{ExampleMessage.php => Message.php} (91%) rename src/App/Message/{ExampleMessageHandler.php => MessageHandler.php} (83%) create mode 100644 test/App/AppConfigProviderTest.php create mode 100644 test/App/Message/MessageHandlerTest.php create mode 100644 test/App/Message/MessageTest.php create mode 100644 test/Swoole/Command/Factory/StartCommandFactoryTest.php create mode 100644 test/Swoole/Command/Factory/StopCommandFactoryTest.php create mode 100644 test/Swoole/Command/GetDataFromLogsCommandTest.php create mode 100644 test/Swoole/Command/GetQueuedMessagesCommandTest.php create mode 100644 test/Swoole/Command/IsRunningTraitTest.php create mode 100644 test/Swoole/Command/StartCommandTest.php create mode 100644 test/Swoole/Command/StopCommandTest.php create mode 100644 test/Swoole/Delegators/DummySwooleServer.php create mode 100644 test/Swoole/Delegators/TCPServerDelegatorTest.php create mode 100644 test/Swoole/Exception/InvalidStaticResourceMiddlewareExceptionTest.php create mode 100644 test/Swoole/PidManagerFactoryTest.php create mode 100644 test/Swoole/PidManagerTest.php create mode 100644 test/Swoole/ServerFactoryTest.php diff --git a/composer.json b/composer.json index 61b8d47..cc845be 100644 --- a/composer.json +++ b/composer.json @@ -69,7 +69,8 @@ }, "autoload-dev": { "psr-4": { - "QueueTest\\Swoole\\": "test/Swoole" + "QueueTest\\App\\": "test/App/", + "QueueTest\\Swoole\\": "test/Swoole/" } }, "scripts": { diff --git a/src/App/ConfigProvider.php b/src/App/ConfigProvider.php index 9d6963d..882f20f 100644 --- a/src/App/ConfigProvider.php +++ b/src/App/ConfigProvider.php @@ -10,8 +10,8 @@ use Netglue\PsrContainer\Messenger\Container\Middleware\MessageHandlerMiddlewareStaticFactory; use Netglue\PsrContainer\Messenger\Container\Middleware\MessageSenderMiddlewareStaticFactory; use Netglue\PsrContainer\Messenger\HandlerLocator\OneToManyFqcnContainerHandlerLocator; -use Queue\App\Message\ExampleMessage; -use Queue\App\Message\ExampleMessageHandler; +use Queue\App\Message\Message; +use Queue\App\Message\MessageHandler; use Symfony\Component\Messenger\MessageBusInterface; class ConfigProvider @@ -37,7 +37,7 @@ private function getDependencies(): array "message_bus_stamp_middleware" => [BusNameStampMiddlewareStaticFactory::class, "message_bus"], "message_bus_sender_middleware" => [MessageSenderMiddlewareStaticFactory::class, "message_bus"], "message_bus_handler_middleware" => [MessageHandlerMiddlewareStaticFactory::class, "message_bus"], - ExampleMessageHandler::class => AttributedServiceFactory::class, + MessageHandler::class => AttributedServiceFactory::class, ], "aliases" => [ MessageBusInterface::class => "message_bus", @@ -81,7 +81,7 @@ private function busConfig(): array */ 'handler_locator' => OneToManyFqcnContainerHandlerLocator::class, 'handlers' => [ - ExampleMessage::class => [ExampleMessageHandler::class], + Message::class => [MessageHandler::class], ], /** @@ -97,7 +97,7 @@ private function busConfig(): array * Route specific messages to specific transports by using the message name as the key. */ 'routes' => [ - ExampleMessage::class => ["redis_transport"], + Message::class => ["redis_transport"], ], ], ]; diff --git a/src/App/Message/ExampleMessage.php b/src/App/Message/Message.php similarity index 91% rename from src/App/Message/ExampleMessage.php rename to src/App/Message/Message.php index d094f4d..aeee893 100644 --- a/src/App/Message/ExampleMessage.php +++ b/src/App/Message/Message.php @@ -4,7 +4,7 @@ namespace Queue\App\Message; -class ExampleMessage +class Message { public function __construct( private array $payload, diff --git a/src/App/Message/ExampleMessageHandler.php b/src/App/Message/MessageHandler.php similarity index 83% rename from src/App/Message/ExampleMessageHandler.php rename to src/App/Message/MessageHandler.php index 63bf30a..74d008b 100644 --- a/src/App/Message/ExampleMessageHandler.php +++ b/src/App/Message/MessageHandler.php @@ -10,7 +10,7 @@ use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\Stamp\DelayStamp; -class ExampleMessageHandler +class MessageHandler { #[Inject( MessageBusInterface::class, @@ -24,7 +24,7 @@ public function __construct( ) { } - public function __invoke(ExampleMessage $message): void + public function __invoke(Message $message): void { $payload = $message->getPayload(); @@ -50,7 +50,7 @@ public function __invoke(ExampleMessage $message): void public function retry(array $payload): void { if (! isset($payload['retry'])) { - $this->bus->dispatch(new ExampleMessage(["foo" => $payload['foo'], 'retry' => 1]), [ + $this->bus->dispatch(new Message(["foo" => $payload['foo'], 'retry' => 1]), [ new DelayStamp($this->config['fail-safe']['first_retry']), ]); } else { @@ -58,13 +58,13 @@ public function retry(array $payload): void switch ($retry) { case 1: $delay = $this->config['fail-safe']['second_retry']; - $this->bus->dispatch(new ExampleMessage(["foo" => $payload['foo'], 'retry' => ++$retry]), [ + $this->bus->dispatch(new Message(["foo" => $payload['foo'], 'retry' => ++$retry]), [ new DelayStamp($delay), ]); break; case 2: $delay = $this->config['fail-safe']['third_retry']; - $this->bus->dispatch(new ExampleMessage(["foo" => $payload['foo'], 'retry' => ++$retry]), [ + $this->bus->dispatch(new Message(["foo" => $payload['foo'], 'retry' => ++$retry]), [ new DelayStamp($delay), ]); break; diff --git a/src/Swoole/Delegators/TCPServerDelegator.php b/src/Swoole/Delegators/TCPServerDelegator.php index e7353ec..3b9b67a 100644 --- a/src/Swoole/Delegators/TCPServerDelegator.php +++ b/src/Swoole/Delegators/TCPServerDelegator.php @@ -5,7 +5,7 @@ namespace Queue\Swoole\Delegators; use Psr\Container\ContainerInterface; -use Queue\App\Message\ExampleMessage; +use Queue\App\Message\Message; use Queue\Swoole\Command\GetFailedMessagesCommand; use Queue\Swoole\Command\GetProcessedMessagesCommand; use Queue\Swoole\Command\GetQueuedMessagesCommand; @@ -79,8 +79,8 @@ public function __invoke(ContainerInterface $container, string $serviceName, cal $logger->error("Error running command: " . $e->getMessage()); } } else { - $bus->dispatch(new ExampleMessage(["foo" => $message])); - $bus->dispatch(new ExampleMessage(["foo" => "with 5 seconds delay"]), [ + $bus->dispatch(new Message(["foo" => $message])); + $bus->dispatch(new Message(["foo" => "with 5 seconds delay"]), [ new DelayStamp(5000), ]); diff --git a/test/App/AppConfigProviderTest.php b/test/App/AppConfigProviderTest.php new file mode 100644 index 0000000..62590b6 --- /dev/null +++ b/test/App/AppConfigProviderTest.php @@ -0,0 +1,23 @@ +config = (new ConfigProvider())(); + } + + public function testHasDependencies(): void + { + $this->assertArrayHasKey('dependencies', $this->config); + } +} diff --git a/test/App/Message/MessageHandlerTest.php b/test/App/Message/MessageHandlerTest.php new file mode 100644 index 0000000..9e50151 --- /dev/null +++ b/test/App/Message/MessageHandlerTest.php @@ -0,0 +1,153 @@ +bus = $this->createMock(MessageBusInterface::class); + $this->logger = new Logger([ + 'writers' => [ + 'FileWriter' => [ + 'name' => 'null', + 'level' => Logger::ALERT, + ], + ], + ]); + $this->config = [ + 'fail-safe' => [ + 'first_retry' => 1000, + 'second_retry' => 2000, + 'third_retry' => 3000, + ], + 'notification' => [ + 'server' => [ + 'protocol' => 'tcp', + 'host' => 'localhost', + 'port' => '8556', + 'eof' => "\n", + ], + ], + 'application' => [ + 'name' => 'dotkernel', + ], + ]; + + $this->handler = new MessageHandler($this->bus, $this->logger, $this->config); + } + + /** + * @throws Exception + */ + public function testInvokeSuccessfulProcessing(): void + { + $payload = ['foo' => 'control']; + $message = $this->createMock(Message::class); + $message->method('getPayload')->willReturn($payload); + + $this->handler->__invoke($message); + + $this->expectNotToPerformAssertions(); + } + + /** + * @throws Exception + */ + public function testInvokeFailureTriggersFirstRetry(): void + { + $payload = ['foo' => 'fail']; + $message = $this->createMock(Message::class); + $message->method('getPayload')->willReturn($payload); + + $this->bus->expects($this->once()) + ->method('dispatch') + ->with( + $this->callback(function ($msg) { + return $msg instanceof Message + && $msg->getPayload()['foo'] === 'fail' + && $msg->getPayload()['retry'] === 1; + }), + $this->callback(function ($stamps) { + return isset($stamps[0]) && $stamps[0] instanceof DelayStamp + && $stamps[0]->getDelay() === 1000; + }) + ) + ->willReturn(new Envelope($message)); + + $this->handler->__invoke($message); + } + + /** + * @throws ExceptionInterface + */ + public function testRetrySecondTime(): void + { + $payload = ['foo' => 'retry_test', 'retry' => 1]; + + $this->bus->expects($this->once()) + ->method('dispatch') + ->with( + $this->callback(function ($msg) { + return $msg instanceof Message + && $msg->getPayload()['retry'] === 2 + && $msg->getPayload()['foo'] === 'retry_test'; + }), + $this->callback(function ($stamps) { + return isset($stamps[0]) && $stamps[0] instanceof DelayStamp + && $stamps[0]->getDelay() === 2000; + }) + ) + ->willReturn(new Envelope(new Message($payload))); + + $this->handler->retry($payload); + } + + /** + * @throws ExceptionInterface + */ + public function testRetryThirdTime(): void + { + $payload = ['foo' => 'retry_test', 'retry' => 2]; + + $this->bus->expects($this->once()) + ->method('dispatch') + ->with( + $this->callback(function ($msg) { + return $msg instanceof Message + && $msg->getPayload()['retry'] === 3 + && $msg->getPayload()['foo'] === 'retry_test'; + }), + $this->callback(function ($stamps) { + return isset($stamps[0]) && $stamps[0] instanceof DelayStamp + && $stamps[0]->getDelay() === 3000; + }) + ) + ->willReturn(new Envelope(new Message($payload))); + + $this->handler->retry($payload); + } +} diff --git a/test/App/Message/MessageTest.php b/test/App/Message/MessageTest.php new file mode 100644 index 0000000..bf98557 --- /dev/null +++ b/test/App/Message/MessageTest.php @@ -0,0 +1,17 @@ + "test message payload"]); + $this->assertSame(["payload" => "test message payload"], $admin->getPayload()); + } +} diff --git a/test/Swoole/Command/Factory/StartCommandFactoryTest.php b/test/Swoole/Command/Factory/StartCommandFactoryTest.php new file mode 100644 index 0000000..40e63a0 --- /dev/null +++ b/test/Swoole/Command/Factory/StartCommandFactoryTest.php @@ -0,0 +1,27 @@ +createMock(ContainerInterface::class); + + $factory = new StartCommandFactory(); + $command = $factory($container); + + $this->assertContainsOnlyInstancesOf(StartCommand::class, [$command]); + } +} diff --git a/test/Swoole/Command/Factory/StopCommandFactoryTest.php b/test/Swoole/Command/Factory/StopCommandFactoryTest.php new file mode 100644 index 0000000..a2ca055 --- /dev/null +++ b/test/Swoole/Command/Factory/StopCommandFactoryTest.php @@ -0,0 +1,35 @@ +createMock(PidManager::class); + + $container = $this->createMock(ContainerInterface::class); + $container->expects($this->once()) + ->method('get') + ->with(PidManager::class) + ->willReturn($pidManager); + + $factory = new StopCommandFactory(); + + $command = $factory($container); + + $this->assertContainsOnlyInstancesOf(StopCommand::class, [$command]); + } +} diff --git a/test/Swoole/Command/GetDataFromLogsCommandTest.php b/test/Swoole/Command/GetDataFromLogsCommandTest.php new file mode 100644 index 0000000..f2b29ea --- /dev/null +++ b/test/Swoole/Command/GetDataFromLogsCommandTest.php @@ -0,0 +1,202 @@ +logDir = dirname(__DIR__, 3) . '/log'; + $this->logPath = $this->logDir . '/queue-log.log'; + if (! is_dir($this->logDir)) { + mkdir($this->logDir, 0777, true); + } + file_put_contents($this->logPath, ''); + } + + protected function tearDown(): void + { + if (file_exists($this->logPath)) { + unlink($this->logPath); + } + } + + /** + * @dataProvider commandProvider + */ + public function testInvalidDateFormat(string $commandClass): void + { + $command = new $commandClass(); + $input = new ArrayInput(['--start' => 'not-a-date']); + $output = new BufferedOutput(); + + $exit = $command->run($input, $output); + + $this->assertEquals(Command::FAILURE, $exit); + $this->assertStringContainsString('Invalid date format', $output->fetch()); + } + + /** + * @dataProvider commandProvider + */ + public function testStartAfterEnd(string $commandClass): void + { + $command = new $commandClass(); + $input = new ArrayInput([ + '--start' => '2024-01-02 00:00:00', + '--end' => '2024-01-01 00:00:00', + ]); + $output = new BufferedOutput(); + + $exit = $command->run($input, $output); + + $this->assertEquals(Command::FAILURE, $exit); + $this->assertStringContainsString('start date cannot be after the end date', $output->fetch()); + } + + /** + * @dataProvider commandProvider + */ + public function testMissingLogFile(string $commandClass): void + { + unlink($this->logPath); + + $command = new $commandClass(); + $input = new ArrayInput([]); + $output = new BufferedOutput(); + + $exit = $command->run($input, $output); + + $this->assertEquals(Command::FAILURE, $exit); + $this->assertStringContainsString('Log file not found', $output->fetch()); + } + + /** + * @dataProvider commandProvider + */ + public function testNoMatchingEntries(string $commandClass): void + { + file_put_contents($this->logPath, json_encode([ + 'levelName' => 'debug', + 'timestamp' => '2024-01-01 12:00:00', + ]) . PHP_EOL); + + $command = new $commandClass(); + $input = new ArrayInput([]); + $output = new BufferedOutput(); + + $exit = $command->run($input, $output); + + $this->assertEquals(Command::SUCCESS, $exit); + $this->assertStringContainsString('No matching log entries found', $output->fetch()); + } + + /** + * @dataProvider commandProvider + */ + public function testMalformedLogLineIgnored(string $commandClass): void + { + file_put_contents($this->logPath, "not-a-json\n"); + + $command = new $commandClass(); + $input = new ArrayInput([]); + $output = new BufferedOutput(); + + $exit = $command->run($input, $output); + + $this->assertEquals(Command::SUCCESS, $exit); + $this->assertStringContainsString('No matching log entries found', $output->fetch()); + } + + /** + * @dataProvider levelProvider + */ + public function testMatchEntryOutput(string $commandClass, string $expectedLevel): void + { + $line = json_encode([ + 'levelName' => $expectedLevel, + 'timestamp' => (new \DateTime())->format('Y-m-d H:i:s'), + 'message' => 'Message here', + ]); + file_put_contents($this->logPath, $line . PHP_EOL); + + $command = new $commandClass(); + $input = new ArrayInput([]); + $output = new BufferedOutput(); + + $exit = $command->run($input, $output); + + $this->assertEquals(Command::SUCCESS, $exit); + $this->assertStringContainsString('Message here', $output->fetch()); + } + + /** + * @throws ExceptionInterface + * @throws \DateMalformedStringException + */ + public function testLimitAddsDaysToStartDateOnly(): void + { + $start = '2024-01-01 00:00:00'; + $limit = 5; + + $command = new GetProcessedMessagesCommand(); // or GetFailedMessagesCommand + $input = new ArrayInput([ + '--start' => $start, + '--limit' => $limit, + ]); + + $output = new BufferedOutput(); + $logDate = (new DateTimeImmutable($start))->modify("+{$limit} days")->format('Y-m-d H:i:s'); + + file_put_contents($this->logPath, json_encode([ + 'levelName' => 'info', + 'timestamp' => $logDate, + 'message' => 'Auto-inferred end', + ]) . PHP_EOL); + + $exit = $command->run($input, $output); + + $this->assertEquals(Command::SUCCESS, $exit); + $this->assertStringContainsString('Auto-inferred end', $output->fetch()); + } + + public static function commandProvider(): array + { + return [ + [GetProcessedMessagesCommand::class], + [GetFailedMessagesCommand::class], + ]; + } + + public static function levelProvider(): array + { + return [ + [GetProcessedMessagesCommand::class, 'info'], + [GetFailedMessagesCommand::class, 'error'], + ]; + } +} diff --git a/test/Swoole/Command/GetQueuedMessagesCommandTest.php b/test/Swoole/Command/GetQueuedMessagesCommandTest.php new file mode 100644 index 0000000..a8edf4b --- /dev/null +++ b/test/Swoole/Command/GetQueuedMessagesCommandTest.php @@ -0,0 +1,103 @@ +redisMock = $this->createMock(Redis::class); + } + + public function testExecuteWithNoMessages(): void + { + $this->redisMock + ->expects($this->once()) + ->method('xRange') + ->with('messages', '-', '+') + ->willReturn([]); + + $command = new GetQueuedMessagesCommand($this->redisMock); + $input = new ArrayInput([]); + $output = new BufferedOutput(); + + $exitCode = $command->run($input, $output); + $outputText = $output->fetch(); + + $this->assertEquals(Command::SUCCESS, $exitCode); + $this->assertStringContainsString('No messages queued found', $outputText); + } + + /** + * @throws ExceptionInterface + */ + public function testExecuteWithMessages(): void + { + $fakeMessages = [ + '1691000000000-0' => ['type' => 'testEmail', 'payload' => '{"to":"test@dotkernel.com"}'], + '1691000000001-0' => ['type' => 'testSms', 'payload' => '{"to":"+123456789"}'], + ]; + + $this->redisMock + ->expects($this->once()) + ->method('xRange') + ->with('messages', '-', '+') + ->willReturn($fakeMessages); + + $command = new GetQueuedMessagesCommand($this->redisMock); + $input = new ArrayInput([]); + $output = new BufferedOutput(); + + $exitCode = $command->run($input, $output); + $outputText = $output->fetch(); + + $this->assertEquals(Command::SUCCESS, $exitCode); + + foreach (array_keys($fakeMessages) as $id) { + $this->assertStringContainsString("Message ID:", $outputText); + $this->assertStringContainsString($id, $outputText); + } + + $this->assertStringContainsString('Total queued messages in stream', $outputText); + $this->assertStringContainsString((string) count($fakeMessages), $outputText); + } + + /** + * @throws ExceptionInterface + */ + public function testRedisThrowsException(): void + { + $this->redisMock + ->expects($this->once()) + ->method('xRange') + ->willThrowException(new RedisException("Redis unavailable")); + + $command = new GetQueuedMessagesCommand($this->redisMock); + $input = new ArrayInput([]); + $output = new BufferedOutput(); + + $this->expectException(RedisException::class); + $command->run($input, $output); + } +} diff --git a/test/Swoole/Command/IsRunningTraitTest.php b/test/Swoole/Command/IsRunningTraitTest.php new file mode 100644 index 0000000..ef59e0d --- /dev/null +++ b/test/Swoole/Command/IsRunningTraitTest.php @@ -0,0 +1,41 @@ +traitUser = new class { + use IsRunningTrait; + + public PidManager $pidManager; + }; + + $this->traitUser->pidManager = $this->createMock(PidManager::class); + } + + public function testIsRunningReturnsFalseWhenNoPids(): void + { + $this->traitUser->pidManager->method('read')->willReturn([]); + $this->assertFalse($this->traitUser->isRunning()); + } + + public function testIsRunningReturnsFalseWhenPidsAreZero(): void + { + $this->traitUser->pidManager->method('read')->willReturn([0, 0]); + $this->assertFalse($this->traitUser->isRunning()); + } +} diff --git a/test/Swoole/Command/StartCommandTest.php b/test/Swoole/Command/StartCommandTest.php new file mode 100644 index 0000000..246976b --- /dev/null +++ b/test/Swoole/Command/StartCommandTest.php @@ -0,0 +1,92 @@ +createMock(InputInterface::class); + $output = $this->createMock(OutputInterface::class); + $pidManager = $this->createMock(PidManager::class); + $server = $this->createMock(Server::class); + + $pidManager->method('read')->willReturn([]); + + $server->master_pid = 1234; + $server->manager_pid = 4321; + + $server->expects($this->once())->method('on'); + $server->expects($this->once())->method('start'); + + $config = [ + 'dotkernel-queue-swoole' => [ + 'swoole-server' => [ + 'process-name' => 'test-process', + ], + ], + ]; + + $container = $this->createMock(ContainerInterface::class); + $container->method('get')->willReturnCallback(function (string $id) use ($pidManager, $server, $config) { + return match ($id) { + PidManager::class => $pidManager, + Server::class => $server, + 'config' => $config, + default => null, + }; + }); + + $command = new StartCommand($container); + $statusCode = $command->run($input, $output); + + $this->assertSame(0, $statusCode); + } + + /** + * @throws ExceptionInterface + * @throws Exception + */ + public function testExecuteWhenServerIsAlreadyRunning(): void + { + $container = $this->createMock(ContainerInterface::class); + $pidManager = $this->createMock(PidManager::class); + $container->method('get') + ->with(PidManager::class) + ->willReturn($pidManager); + + $input = $this->createMock(InputInterface::class); + $output = $this->createMock(OutputInterface::class); + + $output->expects($this->once()) + ->method('writeln') + ->with('Server is already running!'); + + $command = $this->getMockBuilder(StartCommand::class) + ->setConstructorArgs([$container]) + ->onlyMethods(['isRunning']) + ->getMock(); + + $command->method('isRunning')->willReturn(true); + + $exitCode = $command->run($input, $output); + + $this->assertSame(1, $exitCode); + } +} diff --git a/test/Swoole/Command/StopCommandTest.php b/test/Swoole/Command/StopCommandTest.php new file mode 100644 index 0000000..dbdcca2 --- /dev/null +++ b/test/Swoole/Command/StopCommandTest.php @@ -0,0 +1,90 @@ +createMock(PidManager::class); + + $command = $this->getMockBuilder(StopCommand::class) + ->setConstructorArgs([$pidManager]) + ->onlyMethods(['isRunning']) + ->getMock(); + + $command->method('isRunning')->willReturn(false); + + $tester = new CommandTester($command); + $exitCode = $tester->execute([]); + + $this->assertSame(0, $exitCode); + $this->assertStringContainsString('Server is not running', $tester->getDisplay()); + } + + /** + * @throws Exception + */ + public function testExecuteWhenServerStopsSuccessfully(): void + { + $pidManager = $this->createMock(PidManager::class); + $pidManager->method('read')->willReturn(['1234']); + $pidManager->expects($this->once())->method('delete'); + + $command = $this->getMockBuilder(StopCommand::class) + ->setConstructorArgs([$pidManager]) + ->onlyMethods(['isRunning']) + ->getMock(); + + $command->method('isRunning')->willReturn(true); + + $command->killProcess = function (int $pid, ?int $signal = null): bool { + return true; + }; + + $tester = new CommandTester($command); + $exitCode = $tester->execute([]); + + $this->assertSame(0, $exitCode); + $this->assertStringContainsString('Server stopped', $tester->getDisplay()); + } + + /** + * @throws Exception + */ + public function testExecuteWhenServerFailsToStop(): void + { + $pidManager = $this->createMock(PidManager::class); + $pidManager->method('read')->willReturn(['1234']); + $pidManager->expects($this->never())->method('delete'); + + $command = $this->getMockBuilder(StopCommand::class) + ->setConstructorArgs([$pidManager]) + ->onlyMethods(['isRunning']) + ->getMock(); + + $command->method('isRunning')->willReturn(true); + $command->waitThreshold = 1; + + $command->killProcess = function (int $pid, ?int $signal = null): bool { + return $signal === 0; + }; + + $tester = new CommandTester($command); + $exitCode = $tester->execute([]); + + $this->assertSame(1, $exitCode); + $this->assertStringContainsString('Error stopping server', $tester->getDisplay()); + } +} diff --git a/test/Swoole/Delegators/DummySwooleServer.php b/test/Swoole/Delegators/DummySwooleServer.php new file mode 100644 index 0000000..d864bb9 --- /dev/null +++ b/test/Swoole/Delegators/DummySwooleServer.php @@ -0,0 +1,37 @@ + */ + public array $callbacks = []; + + public function __construct() + { + } + + /** + * @param string $eventName + * @param callable $callback + */ + public function on($eventName, $callback): bool + { + $this->callbacks[$eventName] = $callback; + return true; + } + + /** + * @param int|string $fd + * @param string $data + * @param int $serverSocket + */ + public function send($fd, $data, $serverSocket = -1): bool + { + return true; + } +} diff --git a/test/Swoole/Delegators/TCPServerDelegatorTest.php b/test/Swoole/Delegators/TCPServerDelegatorTest.php new file mode 100644 index 0000000..43fa807 --- /dev/null +++ b/test/Swoole/Delegators/TCPServerDelegatorTest.php @@ -0,0 +1,231 @@ +logger = new Logger([ + 'writers' => [ + 'FileWriter' => [ + 'name' => 'null', + 'level' => Logger::ALERT, + ], + ], + ]); + + $this->bus = $this->createMock(MessageBusInterface::class); + $this->container = $this->createMock(ContainerInterface::class); + $this->server = new DummySwooleServer(); + } + + public function testCallbacksAreRegistered(): void + { + $callback = fn() => $this->server; + + $this->container->method('get')->willReturnMap([ + [MessageBusInterface::class, $this->bus], + ['dot-log.queue-log', $this->logger], + ]); + + $delegator = new TCPServerDelegator(); + $result = $delegator($this->container, 'tcp-server', $callback); + + $this->assertSame($this->server, $result); + $this->assertArrayHasKey('Connect', $this->server->callbacks); + $this->assertArrayHasKey('receive', $this->server->callbacks); + $this->assertArrayHasKey('Close', $this->server->callbacks); + + foreach (['Connect', 'receive', 'Close'] as $event) { + $this->assertIsCallable($this->server->callbacks[$event]); + } + } + + public function testConnectOutputsExpectedString(): void + { + $callback = fn() => $this->server; + + $this->container->method('get')->willReturnMap([ + [MessageBusInterface::class, $this->bus], + ['dot-log.queue-log', $this->logger], + ]); + + $delegator = new TCPServerDelegator(); + $delegator($this->container, 'tcp-server', $callback); + + $this->expectOutputString("Client: Connect.\n"); + + $connectCb = $this->server->callbacks['Connect']; + $connectCb($this->server, 1); + } + + public function testCloseOutputsExpectedString(): void + { + $callback = fn() => $this->server; + + $this->container->method('get')->willReturnMap([ + [MessageBusInterface::class, $this->bus], + ['dot-log.queue-log', $this->logger], + ]); + + $delegator = new TCPServerDelegator(); + $delegator($this->container, 'tcp-server', $callback); + + $this->expectOutputString("Client: Close.\n"); + + $closeCb = $this->server->callbacks['Close']; + $closeCb($this->server, 1); + } + + public function testReceiveDispatchesMessagesAndLogsWhenUnknownCommand(): void + { + $callback = fn() => $this->server; + + $this->bus->expects($this->exactly(2)) + ->method('dispatch') + ->willReturnCallback(function ($message) { + static $callCount = 0; + $callCount++; + + if ($callCount === 1) { + $this->assertInstanceOf(Message::class, $message); + $this->assertEquals('hello', $message->getPayload()['foo']); + } elseif ($callCount === 2) { + $this->assertInstanceOf(Message::class, $message); + $this->assertEquals('with 5 seconds delay', $message->getPayload()['foo']); + } else { + $this->fail('dispatch called more than twice'); + } + + return new Envelope($message); + }); + + $this->container->method('get')->willReturnMap([ + [MessageBusInterface::class, $this->bus], + ['dot-log.queue-log', $this->logger], + ]); + + $delegator = new TCPServerDelegator(); + $delegator($this->container, 'tcp-server', $callback); + + $receiveCb = $this->server->callbacks['receive']; + + $receiveCb($this->server, 42, 5, "hello"); + } + + public function testReceiveExecutesKnownCommandSuccessfully(): void + { + $callback = fn() => $this->server; + + $commandMock = $this->getMockBuilder(GetProcessedMessagesCommand::class) + ->onlyMethods(['execute']) + ->getMock(); + + $commandMock->method('execute')->willReturnCallback(function ($input, $output) { + $output->writeln('processed output text'); + return 0; + }); + + $this->server = new class extends DummySwooleServer { + public ?string $sentData = null; + + /** + * @param int $fd + * @param string $data + * @param int $serverSocket + */ + public function send($fd, $data, $serverSocket = -1): bool + { + $this->sentData = $data; + return true; + } + }; + + // Make sure the container returns our mock command instance + $this->container->method('get')->willReturnMap([ + [MessageBusInterface::class, $this->bus], + ['dot-log.queue-log', $this->logger], + [GetProcessedMessagesCommand::class, $commandMock], + ]); + + $delegator = new TCPServerDelegator(); + $delegator($this->container, 'tcp-server', $callback); + + $receiveCb = $this->server->callbacks['receive']; + + $receiveCb($this->server, 1, 1, "processed"); + + $this->assertNotNull($this->server->sentData); + $this->assertStringContainsString('processed output text', $this->server->sentData); + } + + public function testReceiveParsesKnownOptions(): void + { + $callback = fn() => $this->server; + + $sentData = null; + $this->server = new class extends DummySwooleServer { + public ?string $sentData = null; + + /** + * @param int $fd + * @param string $data + * @param int $serverSocket + */ + public function send($fd, $data, $serverSocket = -1): bool + { + $this->sentData = $data; + return true; + } + }; + + $commandMock = $this->getMockBuilder(GetProcessedMessagesCommand::class) + ->onlyMethods(['execute']) + ->getMock(); + + $commandMock->method('execute')->willReturnCallback(function ($input, $output) { + $output->writeln('processed output text with known options'); + return 0; + }); + + $this->container->method('get')->willReturnMap([ + [MessageBusInterface::class, $this->bus], + ['dot-log.queue-log', $this->logger], + [GetProcessedMessagesCommand::class, $commandMock], + ]); + + $delegator = new TCPServerDelegator(); + $delegator($this->container, 'tcp-server', $callback); + + $receiveCb = $this->server->callbacks['receive']; + + $receiveCb($this->server, 1, 1, "processed --start=1 --end=5"); + + $this->assertNotNull($this->server->sentData); + $this->assertStringContainsString('processed output text with known options', $this->server->sentData); + } +} diff --git a/test/Swoole/Exception/InvalidStaticResourceMiddlewareExceptionTest.php b/test/Swoole/Exception/InvalidStaticResourceMiddlewareExceptionTest.php new file mode 100644 index 0000000..461edda --- /dev/null +++ b/test/Swoole/Exception/InvalidStaticResourceMiddlewareExceptionTest.php @@ -0,0 +1,32 @@ +assertContainsOnlyInstancesOf(InvalidStaticResourceMiddlewareException::class, [$exception]); + + $expectedMessage = sprintf( + 'Static resource middleware must be callable; received middleware of type "%s" in position %s', + get_debug_type($middleware), + $position + ); + + $this->assertSame($expectedMessage, $exception->getMessage()); + } +} diff --git a/test/Swoole/PidManagerFactoryTest.php b/test/Swoole/PidManagerFactoryTest.php new file mode 100644 index 0000000..b5e52db --- /dev/null +++ b/test/Swoole/PidManagerFactoryTest.php @@ -0,0 +1,54 @@ + [ + 'swoole-tcp-server' => [ + 'options' => [ + 'pid_file' => $expectedPath, + ], + ], + ], + ]; + + $container = $this->createMock(ContainerInterface::class); + $container->method('get') + ->with('config') + ->willReturn($config); + + $factory = new PidManagerFactory(); + $pidManager = $factory($container); + + $pidFilePath = $this->getPrivateProperty($pidManager); + $this->assertSame($expectedPath, $pidFilePath); + } + + /** + * @throws ReflectionException + */ + private function getPrivateProperty(object $object): mixed + { + $reflection = new \ReflectionClass($object); + $property = $reflection->getProperty('pidFile'); + return $property->getValue($object); + } +} diff --git a/test/Swoole/PidManagerTest.php b/test/Swoole/PidManagerTest.php new file mode 100644 index 0000000..f6c22e4 --- /dev/null +++ b/test/Swoole/PidManagerTest.php @@ -0,0 +1,92 @@ +tempPidFile = sys_get_temp_dir() . '/test.pid'; + if (file_exists($this->tempPidFile)) { + unlink($this->tempPidFile); + } + } + + protected function tearDown(): void + { + if (file_exists($this->tempPidFile)) { + unlink($this->tempPidFile); + } + } + + public function testWriteAndReadPids(): void + { + $manager = new PidManager($this->tempPidFile); + + $manager->write(12345, 67890); + + $result = $manager->read(); + + $this->assertSame(['12345', '67890'], $result); + $this->assertFileExists($this->tempPidFile); + } + + public function testDeleteRemovesPidFile(): void + { + file_put_contents($this->tempPidFile, 'dummyData'); + + $manager = new PidManager($this->tempPidFile); + $deleted = $manager->delete(); + + $this->assertTrue($deleted); + $this->assertFileDoesNotExist($this->tempPidFile); + } + + public function testDeleteReturnsFalseIfFileNotWritable(): void + { + file_put_contents($this->tempPidFile, 'dummyData'); + chmod($this->tempPidFile, 0444); + + $manager = new PidManager($this->tempPidFile); + $result = $manager->delete(); + + $this->assertFalse($result); + + chmod($this->tempPidFile, 0644); + } + + public function testWriteThrowsWhenFileNotWritable(): void + { + $unwritableDir = sys_get_temp_dir() . '/unwritable_dir'; + mkdir($unwritableDir, 0444); + $unwritableFile = $unwritableDir . '/file.pid'; + + $manager = new PidManager($unwritableFile); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('/not writable/'); + + try { + $manager->write(1, 2); + } finally { + chmod($unwritableDir, 0755); + rmdir($unwritableDir); + } + } +} diff --git a/test/Swoole/ServerFactoryTest.php b/test/Swoole/ServerFactoryTest.php new file mode 100644 index 0000000..a1346f5 --- /dev/null +++ b/test/Swoole/ServerFactoryTest.php @@ -0,0 +1,147 @@ +factory = new ServerFactory(); + } + + /** + * @throws Exception|ErrorException + */ + #[RunInSeparateProcess] + public function testInvokeWithMinimalValidConfig(): void + { + $config = [ + 'dotkernel-queue-swoole' => [ + 'swoole-tcp-server' => [], + ], + ]; + + $container = $this->createMock(ContainerInterface::class); + $container->method('get')->with('config')->willReturn($config); + + $server = $this->factory->__invoke($container); + + $this->assertContainsOnlyInstancesOf(Server::class, [$server]); + } + + /** + * @throws Exception + * @throws ErrorException + */ + #[RunInSeparateProcess] + public function testInvokeWithCustomValidConfig(): void + { + $config = [ + 'dotkernel-queue-swoole' => [ + 'enable_coroutine' => true, + 'swoole-tcp-server' => [ + 'host' => '127.0.0.1', + 'port' => 9502, + 'mode' => SWOOLE_BASE, + 'protocol' => SWOOLE_SOCK_TCP, + 'options' => [ + 'worker_num' => 1, + ], + ], + ], + ]; + + $container = $this->createMock(ContainerInterface::class); + $container->method('get')->with('config')->willReturn($config); + + $server = $this->factory->__invoke($container); + + $this->assertContainsOnlyInstancesOf(Server::class, [$server]); + } + + /** + * @throws Exception + * @throws ErrorException + */ + public function testThrowsOnInvalidPort(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid port'); + + $config = [ + 'dotkernel-queue-swoole' => [ + 'swoole-tcp-server' => [ + 'port' => 70000, + ], + ], + ]; + + $container = $this->createMock(ContainerInterface::class); + $container->method('get')->with('config')->willReturn($config); + + $this->factory->__invoke($container); + } + + /** + * @throws Exception|ErrorException + */ + public function testThrowsOnInvalidMode(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid server mode'); + + $config = [ + 'dotkernel-queue-swoole' => [ + 'swoole-tcp-server' => [ + 'mode' => -1, + ], + ], + ]; + + $container = $this->createMock(ContainerInterface::class); + $container->method('get')->with('config')->willReturn($config); + + $this->factory->__invoke($container); + } + + /** + * @throws Exception + * @throws ErrorException + */ + public function testThrowsOnInvalidProtocol(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid server protocol'); + + $config = [ + 'dotkernel-queue-swoole' => [ + 'swoole-tcp-server' => [ + 'protocol' => -99, + ], + ], + ]; + + $container = $this->createMock(ContainerInterface::class); + $container->method('get')->with('config')->willReturn($config); + + $this->factory->__invoke($container); + } +} From dff8fefb0abbcff6347f3e5ad144e8a793ad21e0 Mon Sep 17 00:00:00 2001 From: bota Date: Fri, 1 Aug 2025 12:52:50 +0300 Subject: [PATCH 02/10] add swoole extension to codecov workflow Signed-off-by: bota --- .github/workflows/codecov.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 3eb01b6..fb293b8 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -27,6 +27,7 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: "${{ matrix.php }}" + extensions: swoole coverage: pcov ini-values: assert.exception=1, zend.assertions=1, error_reporting=-1, log_errors_max_len=0, display_errors=On tools: composer:v2, cs2pr From 46ae65d03bc204cd69ee8887b1a02780162e576f Mon Sep 17 00:00:00 2001 From: bota Date: Fri, 1 Aug 2025 13:01:57 +0300 Subject: [PATCH 03/10] added swoole extension to other workflows Signed-off-by: bota --- .github/workflows/qodana_code_quality.yml | 1 + .github/workflows/static-analysis.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/qodana_code_quality.yml b/.github/workflows/qodana_code_quality.yml index d341e2d..11ec78a 100644 --- a/.github/workflows/qodana_code_quality.yml +++ b/.github/workflows/qodana_code_quality.yml @@ -25,6 +25,7 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-versions }} + extensions: swoole coverage: pcov ini-values: assert.exception=1, zend.assertions=1, error_reporting=-1, log_errors_max_len=0, display_errors=On tools: composer:v2, cs2pr diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index b9d4c50..07fbae6 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -27,6 +27,7 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: "${{ matrix.php }}" + extensions: swoole coverage: pcov ini-values: assert.exception=1, zend.assertions=1, error_reporting=-1, log_errors_max_len=0, display_errors=On tools: composer:v2, cs2pr From 5c7b9e9c90286796c33597a7bc39827ebd29ea42 Mon Sep 17 00:00:00 2001 From: bota Date: Fri, 1 Aug 2025 13:13:09 +0300 Subject: [PATCH 04/10] added swoole extentions to laminas-ci Signed-off-by: bota --- .github/workflows/qodana_code_quality.yml | 1 - .github/workflows/static-analysis.yml | 1 - .laminas-ci.json | 3 ++- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/qodana_code_quality.yml b/.github/workflows/qodana_code_quality.yml index 11ec78a..d341e2d 100644 --- a/.github/workflows/qodana_code_quality.yml +++ b/.github/workflows/qodana_code_quality.yml @@ -25,7 +25,6 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-versions }} - extensions: swoole coverage: pcov ini-values: assert.exception=1, zend.assertions=1, error_reporting=-1, log_errors_max_len=0, display_errors=On tools: composer:v2, cs2pr diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 07fbae6..b9d4c50 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -27,7 +27,6 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: "${{ matrix.php }}" - extensions: swoole coverage: pcov ini-values: assert.exception=1, zend.assertions=1, error_reporting=-1, log_errors_max_len=0, display_errors=On tools: composer:v2, cs2pr diff --git a/.laminas-ci.json b/.laminas-ci.json index af5962f..1f8a7bd 100644 --- a/.laminas-ci.json +++ b/.laminas-ci.json @@ -3,7 +3,8 @@ "--no-scripts" ], "extensions": [ - "redis" + "redis", + "swoole" ], "ignore_php_platform_requirements": { } From 53ca005fa8f787e774534044b18b3395d51f24cf Mon Sep 17 00:00:00 2001 From: bota Date: Fri, 1 Aug 2025 13:26:21 +0300 Subject: [PATCH 05/10] fixed command name and manually install swoole extension Signed-off-by: bota --- .laminas-ci.json | 8 ++++++-- src/Swoole/Command/GetFailedMessagesCommand.php | 3 ++- src/Swoole/Command/GetProcessedMessagesCommand.php | 3 ++- src/Swoole/Command/GetQueuedMessagesCommand.php | 3 ++- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.laminas-ci.json b/.laminas-ci.json index 1f8a7bd..eb039db 100644 --- a/.laminas-ci.json +++ b/.laminas-ci.json @@ -3,8 +3,12 @@ "--no-scripts" ], "extensions": [ - "redis", - "swoole" + "redis" + ], + "before_script": [ + "apt-get update && apt-get install -y php-dev php-pear libcurl4-openssl-dev libssl-dev", + "pecl install swoole", + "echo 'extension=swoole.so' > /etc/php/cli/conf.d/20-swoole.ini" ], "ignore_php_platform_requirements": { } diff --git a/src/Swoole/Command/GetFailedMessagesCommand.php b/src/Swoole/Command/GetFailedMessagesCommand.php index 21fab0a..83da758 100644 --- a/src/Swoole/Command/GetFailedMessagesCommand.php +++ b/src/Swoole/Command/GetFailedMessagesCommand.php @@ -28,7 +28,8 @@ )] class GetFailedMessagesCommand extends Command { - protected static string $defaultName = 'failed'; + /** @var string $defaultName */ + protected static $defaultName = 'failed'; #[Inject()] public function __construct() diff --git a/src/Swoole/Command/GetProcessedMessagesCommand.php b/src/Swoole/Command/GetProcessedMessagesCommand.php index 9732c66..846dfe7 100644 --- a/src/Swoole/Command/GetProcessedMessagesCommand.php +++ b/src/Swoole/Command/GetProcessedMessagesCommand.php @@ -28,7 +28,8 @@ )] class GetProcessedMessagesCommand extends Command { - protected static string $defaultName = 'processed'; + /** @var string $defaultName */ + protected static $defaultName = 'processed'; #[Inject()] public function __construct() diff --git a/src/Swoole/Command/GetQueuedMessagesCommand.php b/src/Swoole/Command/GetQueuedMessagesCommand.php index a40227d..ed039cd 100644 --- a/src/Swoole/Command/GetQueuedMessagesCommand.php +++ b/src/Swoole/Command/GetQueuedMessagesCommand.php @@ -25,7 +25,8 @@ )] class GetQueuedMessagesCommand extends Command { - protected static string $defaultName = 'inventory'; + /** @var string $defaultName */ + protected static $defaultName = 'inventory'; private Redis $redis; From 987325967f18e83ebbf1c11b910ca3d4846f43cb Mon Sep 17 00:00:00 2001 From: bota Date: Fri, 1 Aug 2025 13:31:56 +0300 Subject: [PATCH 06/10] git update before_script Signed-off-by: bota --- .laminas-ci.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.laminas-ci.json b/.laminas-ci.json index eb039db..3b4fdfa 100644 --- a/.laminas-ci.json +++ b/.laminas-ci.json @@ -6,9 +6,9 @@ "redis" ], "before_script": [ - "apt-get update && apt-get install -y php-dev php-pear libcurl4-openssl-dev libssl-dev", - "pecl install swoole", - "echo 'extension=swoole.so' > /etc/php/cli/conf.d/20-swoole.ini" + "sudo apt-get update && sudo apt-get install -y php-dev php-pear libcurl4-openssl-dev libssl-dev gcc make autoconf", + "sudo pecl install swoole", + "echo 'extension=swoole.so' | sudo tee /etc/php/cli/conf.d/20-swoole.ini" ], "ignore_php_platform_requirements": { } From f7b340d5807a570ce7fdd766771539484c3bd693 Mon Sep 17 00:00:00 2001 From: bota Date: Fri, 1 Aug 2025 13:43:36 +0300 Subject: [PATCH 07/10] install swoole in laminas-ci pre-run Signed-off-by: bota --- .laminas-ci.json | 5 ----- .laminas-ci/pre-run.sh | 7 +++++++ 2 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 .laminas-ci/pre-run.sh diff --git a/.laminas-ci.json b/.laminas-ci.json index 3b4fdfa..af5962f 100644 --- a/.laminas-ci.json +++ b/.laminas-ci.json @@ -5,11 +5,6 @@ "extensions": [ "redis" ], - "before_script": [ - "sudo apt-get update && sudo apt-get install -y php-dev php-pear libcurl4-openssl-dev libssl-dev gcc make autoconf", - "sudo pecl install swoole", - "echo 'extension=swoole.so' | sudo tee /etc/php/cli/conf.d/20-swoole.ini" - ], "ignore_php_platform_requirements": { } } diff --git a/.laminas-ci/pre-run.sh b/.laminas-ci/pre-run.sh new file mode 100644 index 0000000..4c3c8ca --- /dev/null +++ b/.laminas-ci/pre-run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +JOB=$3 +PHP_VERSION=$(echo "${JOB}" | jq -r '.php') + +apt update +apt install -y "php${PHP_VERSION}-swoole" From 648aff10c2fffd3b7fb04686f3e2dce403d4b3ca Mon Sep 17 00:00:00 2001 From: bota Date: Fri, 1 Aug 2025 13:59:03 +0300 Subject: [PATCH 08/10] updated pre-run Signed-off-by: bota --- .laminas-ci/pre-run.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) mode change 100644 => 100755 .laminas-ci/pre-run.sh diff --git a/.laminas-ci/pre-run.sh b/.laminas-ci/pre-run.sh old mode 100644 new mode 100755 index 4c3c8ca..5603f1e --- a/.laminas-ci/pre-run.sh +++ b/.laminas-ci/pre-run.sh @@ -1,7 +1,8 @@ -#!/bin/bash +apt-get update +apt-get install -y php-dev php-pear libcurl4-openssl-dev libssl-dev gcc make autoconf -JOB=$3 -PHP_VERSION=$(echo "${JOB}" | jq -r '.php') +pecl channel-update pecl.php.net -apt update -apt install -y "php${PHP_VERSION}-swoole" +pecl install -f swoole + +echo "extension=swoole.so" > /etc/php/cli/conf.d/20-swoole.ini From 1497db43b8c16363cf47c445ba0520a0b2306538 Mon Sep 17 00:00:00 2001 From: bota Date: Fri, 1 Aug 2025 14:01:41 +0300 Subject: [PATCH 09/10] reverted pre-run Signed-off-by: bota --- .laminas-ci/pre-run.sh | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/.laminas-ci/pre-run.sh b/.laminas-ci/pre-run.sh index 5603f1e..b7ba4af 100755 --- a/.laminas-ci/pre-run.sh +++ b/.laminas-ci/pre-run.sh @@ -1,8 +1,5 @@ -apt-get update -apt-get install -y php-dev php-pear libcurl4-openssl-dev libssl-dev gcc make autoconf +JOB=$3 +PHP_VERSION=$(echo "${JOB}" | jq -r '.php') -pecl channel-update pecl.php.net - -pecl install -f swoole - -echo "extension=swoole.so" > /etc/php/cli/conf.d/20-swoole.ini +apt update +apt install -y "php${PHP_VERSION}-swoole" From 57ffd34544933dfe310b063f25153c7c3a4fd08d Mon Sep 17 00:00:00 2001 From: bota Date: Fri, 1 Aug 2025 14:16:38 +0300 Subject: [PATCH 10/10] removed unnecessary comments Signed-off-by: bota --- test/Swoole/Command/GetDataFromLogsCommandTest.php | 2 +- test/Swoole/Delegators/TCPServerDelegatorTest.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/Swoole/Command/GetDataFromLogsCommandTest.php b/test/Swoole/Command/GetDataFromLogsCommandTest.php index f2b29ea..92803d2 100644 --- a/test/Swoole/Command/GetDataFromLogsCommandTest.php +++ b/test/Swoole/Command/GetDataFromLogsCommandTest.php @@ -163,7 +163,7 @@ public function testLimitAddsDaysToStartDateOnly(): void $start = '2024-01-01 00:00:00'; $limit = 5; - $command = new GetProcessedMessagesCommand(); // or GetFailedMessagesCommand + $command = new GetProcessedMessagesCommand(); $input = new ArrayInput([ '--start' => $start, '--limit' => $limit, diff --git a/test/Swoole/Delegators/TCPServerDelegatorTest.php b/test/Swoole/Delegators/TCPServerDelegatorTest.php index 43fa807..dd90db2 100644 --- a/test/Swoole/Delegators/TCPServerDelegatorTest.php +++ b/test/Swoole/Delegators/TCPServerDelegatorTest.php @@ -165,7 +165,6 @@ public function send($fd, $data, $serverSocket = -1): bool } }; - // Make sure the container returns our mock command instance $this->container->method('get')->willReturnMap([ [MessageBusInterface::class, $this->bus], ['dot-log.queue-log', $this->logger],