Skip to content
Open

Tests #248

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"require-dev": {
"maglnet/composer-require-checker": "^4.7.1",
"phpbench/phpbench": "^1.4.1",
"phpunit/phpunit": "^10.5.45",
"phpunit/phpunit": "^10.5.45 || ^12.4",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is PHPUnit 10 not enough?

"rector/rector": "^2.0.11",
"roave/infection-static-analysis-plugin": "^1.35",
"spatie/phpunit-watcher": "^1.24",
Expand Down
2 changes: 1 addition & 1 deletion src/Debug/QueueDecorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function listen(): void
$this->queue->listen();
}

public function withAdapter(AdapterInterface $adapter): QueueInterface
public function withAdapter(AdapterInterface $adapter): static
{
return new self($this->queue->withAdapter($adapter), $this->collector);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Queue.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public function status(string|int $id): JobStatus
return $this->adapter->status($id);
}

public function withAdapter(AdapterInterface $adapter): self
public function withAdapter(AdapterInterface $adapter): static
{
$new = clone $this;
$new->adapter = $adapter;
Expand Down
2 changes: 1 addition & 1 deletion src/QueueInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public function listen(): void;
*/
public function status(string|int $id): JobStatus;

public function withAdapter(AdapterInterface $adapter): self;
public function withAdapter(AdapterInterface $adapter): static;

public function getChannel(): string;
}
2 changes: 1 addition & 1 deletion stubs/StubQueue.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function getAdapter(): ?AdapterInterface
return $this->adapter;
}

public function withAdapter(AdapterInterface $adapter): QueueInterface
public function withAdapter(AdapterInterface $adapter): static
{
$new = clone $this;
$new->adapter = $adapter;
Expand Down
2 changes: 1 addition & 1 deletion tests/App/DummyQueue.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function status(string|int $id): JobStatus
throw new Exception('`status()` method is not implemented yet.');
}

public function withAdapter(AdapterInterface $adapter): QueueInterface
public function withAdapter(AdapterInterface $adapter): static
{
throw new Exception('`withAdapter()` method is not implemented yet.');
}
Expand Down
116 changes: 116 additions & 0 deletions tests/Unit/Cli/SignalLoopTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Queue\Tests\Unit\Cli;

use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use Yiisoft\Queue\Cli\SignalLoop;

#[RequiresPhpExtension('pcntl')]
final class SignalLoopTest extends TestCase
{
public function setUp(): void
{
parent::setUp();
pcntl_async_signals(true);
}

public function testMemoryLimitReached(): void
{
$loop = new SignalLoop(1);
self::assertFalse($loop->canContinue());
}

public function testSuspendAndResume(): void
{
$loop = new SignalLoop(0);
pcntl_signal(\SIGALRM, static function (): void {
posix_kill(getmypid(), \SIGCONT);
});

posix_kill(getmypid(), \SIGTSTP);
pcntl_alarm(1);

$start = microtime(true);
$result = $loop->canContinue();
$elapsed = microtime(true) - $start;

self::assertTrue($result);
self::assertGreaterThan(0.5, $elapsed);
}

#[DataProvider('exitSignalProvider')]
public function testExitSignals(int $signal): void
{
$loop = new SignalLoop(0);

self::assertTrue($loop->canContinue(), 'Loop should continue');
posix_kill(getmypid(), $signal);

self::assertFalse($loop->canContinue(), "Loop should not continue after receiving signal {$signal}");
}

public static function exitSignalProvider(): iterable
{
yield 'SIGHUP' => [\SIGHUP];
yield 'SIGINT' => [\SIGINT];
yield 'SIGTERM' => [\SIGTERM];
}

public function testResumeSignal(): void
{
$loop = new SignalLoop(0);

// First suspend the loop
posix_kill(getmypid(), \SIGTSTP);

// Then immediately resume
posix_kill(getmypid(), \SIGCONT);

$start = microtime(true);
$result = $loop->canContinue();
$elapsed = microtime(true) - $start;

self::assertTrue($result);
self::assertLessThan(0.1, $elapsed, 'Loop should resume quickly without waiting');
}

public function testMultipleExitSignals(): void
{
$loop = new SignalLoop(0);

// Send multiple exit signals
posix_kill(getmypid(), \SIGINT);
posix_kill(getmypid(), \SIGTERM);

$result = $loop->canContinue();

self::assertFalse($result, 'Loop should not continue after receiving any exit signal');
}

public function testSuspendOverridesResume(): void
{
$loop = new SignalLoop(0);

// Resume first
posix_kill(getmypid(), \SIGCONT);
// Then suspend
posix_kill(getmypid(), \SIGTSTP);

// Set up alarm to resume after 1 second
pcntl_signal(\SIGALRM, static function (): void {
posix_kill(getmypid(), \SIGCONT);
});
pcntl_alarm(1);

$start = microtime(true);
$result = $loop->canContinue();
$elapsed = microtime(true) - $start;

self::assertTrue($result);
self::assertGreaterThan(0.5, $elapsed, 'Loop should wait for resume after suspend');
}
}
10 changes: 10 additions & 0 deletions tests/Unit/Debug/QueueProviderInterfaceProxyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,14 @@ public function testGet(): void

$this->assertInstanceOf(QueueDecorator::class, $factory->get('test'));
}

public function testHas(): void
{
$queueFactory = $this->createMock(QueueProviderInterface::class);
$queueFactory->expects($this->once())->method('has')->with('test')->willReturn(true);
$collector = new QueueCollector();
$factory = new QueueProviderInterfaceProxy($queueFactory, $collector);

$this->assertTrue($factory->has('test'));
}
}
33 changes: 33 additions & 0 deletions tests/Unit/Debug/QueueWorkerInterfaceProxyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Queue\Tests\Unit\Debug;

use PHPUnit\Framework\TestCase;
use Yiisoft\Queue\Debug\QueueCollector;
use Yiisoft\Queue\Debug\QueueWorkerInterfaceProxy;
use Yiisoft\Queue\Message\Message;
use Yiisoft\Queue\Tests\App\DummyQueue;
use Yiisoft\Queue\Stubs\StubWorker;

final class QueueWorkerInterfaceProxyTest extends TestCase
{
public function testProcessDelegatesToWorker(): void
{
$message = new Message('handler', 'data');
$collector = new QueueCollector();
$collector->startup();
$proxy = new QueueWorkerInterfaceProxy(new StubWorker(), $collector);

$result = $proxy->process($message, new DummyQueue('chan'));

self::assertSame($message, $result);

$collected = $collector->getCollected();
self::assertArrayHasKey('processingMessages', $collected);
self::assertArrayHasKey('chan', $collected['processingMessages']);
self::assertCount(1, $collected['processingMessages']['chan']);
self::assertSame($message, $collected['processingMessages']['chan'][0]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

use PHPUnit\Framework\TestCase;
use Yiisoft\Queue\Tests\App\DummyEnvelope;
use Yiisoft\Queue\Message\EnvelopeInterface;
use Yiisoft\Queue\Message\Message;

final class EnvelopeTraitTest extends TestCase
final class EnvelopeTest extends TestCase
{
public function testFromData(): void
{
Expand All @@ -23,4 +25,14 @@ public function testFromData(): void
$this->assertArrayHasKey('meta', $envelope->getMetadata());
$this->assertSame('data', $envelope->getMetadata()['meta']);
}

public function testNonArrayStackIsNormalized(): void
{
$base = new Message('handler', 'data', [EnvelopeInterface::ENVELOPE_STACK_KEY => 'oops']);
$wrapped = new DummyEnvelope($base, 'id-1');

$meta = $wrapped->getMetadata();
self::assertIsArray($meta[EnvelopeInterface::ENVELOPE_STACK_KEY]);
self::assertSame([DummyEnvelope::class], $meta[EnvelopeInterface::ENVELOPE_STACK_KEY]);
}
}
10 changes: 4 additions & 6 deletions tests/Unit/Message/JsonMessageSerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,7 @@ public function testDefaultMessageClassFallbackClassNotSet(): void
$this->assertInstanceOf(Message::class, $message);
}

/**
* @dataProvider dataUnsupportedPayloadFormat
*/
#[DataProvider('dataUnsupportedPayloadFormat')]
public function testPayloadFormat(mixed $payload): void
{
$serializer = $this->createSerializer();
Expand All @@ -87,9 +85,7 @@ public static function dataUnsupportedPayloadFormat(): iterable
yield 'null' => [null];
}

/**
* @dataProvider dataUnsupportedMetadataFormat
*/
#[DataProvider('dataUnsupportedMetadataFormat')]
public function testMetadataFormat(mixed $meta): void
{
$payload = ['name' => 'handler', 'data' => 'test', 'meta' => $meta];
Expand Down Expand Up @@ -142,6 +138,7 @@ public function testUnserializeEnvelopeStack(): void
];
$serializer = $this->createSerializer();

/** @var IdEnvelope $message */
$message = $serializer->unserialize(json_encode($payload));

$this->assertEquals($payload['data'], $message->getData());
Expand Down Expand Up @@ -185,6 +182,7 @@ public function testSerializeEnvelopeStack(): void
$json,
);

/** @var IdEnvelope $message */
$message = $serializer->unserialize($json);

$this->assertInstanceOf(IdEnvelope::class, $message);
Expand Down
78 changes: 78 additions & 0 deletions tests/Unit/Middleware/CallableFactoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Queue\Tests\Unit\Middleware;

use PHPUnit\Framework\TestCase;
use Yiisoft\Queue\Middleware\CallableFactory;
use Yiisoft\Queue\Middleware\InvalidCallableConfigurationException;
use Yiisoft\Test\Support\Container\SimpleContainer;

final class CallableFactoryTest extends TestCase
{
public function testCreateFromContainerStringInvokable(): void
{
$invokable = new class () {
public function __invoke(): string
{
return 'ok';
}
};
$container = new SimpleContainer([
'invokable' => $invokable,
]);

$factory = new CallableFactory($container);
$callable = $factory->create('invokable');

self::assertIsCallable($callable);
self::assertSame('ok', $callable());
}

public function testCreateFromStaticMethodArray(): void
{
$class = new class () {
public static function ping(): string
{
return 'pong';
}
};
$className = $class::class;
$container = new SimpleContainer();

$factory = new CallableFactory($container);
$callable = $factory->create([$className, 'ping']);

self::assertIsCallable($callable);
self::assertSame('pong', $callable());
}

public function testCreateFromContainerObjectMethod(): void
{
$service = new class () {
public function go(): string
{
return 'ok';
}
};
$className = $service::class;
$container = new SimpleContainer([
$className => $service,
]);

$factory = new CallableFactory($container);
$callable = $factory->create([$className, 'go']);

self::assertIsCallable($callable);
self::assertSame('ok', $callable());
}

public function testFriendlyException(): void
{
$e = new InvalidCallableConfigurationException();
self::assertSame('Invalid callable configuration.', $e->getName());
self::assertNotNull($e->getSolution());
self::assertStringContainsString('callable', (string)$e->getSolution());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,23 @@ final class FailureHandlingRequestTest extends TestCase
public function testImmutable(): void
{
$queue = $this->createMock(QueueInterface::class);
$failureHandlingRequest = new FailureHandlingRequest(
new Message('test', 'test'),
new Exception(),
$request1 = new FailureHandlingRequest(
new Message('test', null),
new Exception('exception 1'),
$queue
);
$request2 = $request1->withQueue($queue);
$request3 = $request1->withException(new Exception('exception 2'));
$request4 = $request1->withMessage(new Message('test2', null));

$this->assertNotSame($failureHandlingRequest, $failureHandlingRequest->withQueue($queue));
$this->assertNotSame($request1, $request2);

$this->assertNotSame($request1, $request3);
$this->assertEquals($request1->getException()->getMessage(), 'exception 1');
$this->assertEquals($request3->getException()->getMessage(), 'exception 2');

$this->assertNotSame($request1, $request4);
$this->assertEquals($request1->getMessage()->getHandlerName(), 'test');
$this->assertEquals($request4->getMessage()->getHandlerName(), 'test2');
}
}
Loading
Loading