Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve test coverage #241

Merged
merged 3 commits into from
Feb 14, 2025
Merged
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
48 changes: 0 additions & 48 deletions src/Exception/InvalidStatusException.php

This file was deleted.

6 changes: 3 additions & 3 deletions src/Message/EnvelopeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ abstract public static function fromMessage(MessageInterface $message): self;

public static function fromData(string $handlerName, mixed $data, array $metadata = []): MessageInterface
{
return self::fromMessage(Message::fromData($handlerName, $data, $metadata));
return static::fromMessage(Message::fromData($handlerName, $data, $metadata));
}

public function getMessage(): MessageInterface
Expand Down Expand Up @@ -46,8 +46,8 @@ public function getMetadata(): array
return array_merge(
$this->message->getMetadata(),
[
self::ENVELOPE_STACK_KEY => array_merge(
$this->message->getMetadata()[self::ENVELOPE_STACK_KEY] ?? [],
EnvelopeInterface::ENVELOPE_STACK_KEY => array_merge(
$this->message->getMetadata()[EnvelopeInterface::ENVELOPE_STACK_KEY] ?? [],
[self::class],
),
],
Expand Down
22 changes: 22 additions & 0 deletions tests/App/DummyEnvelope.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Queue\Tests\App;

use Yiisoft\Queue\Message\EnvelopeInterface;
use Yiisoft\Queue\Message\EnvelopeTrait;
use Yiisoft\Queue\Message\MessageInterface;

final class DummyEnvelope implements EnvelopeInterface
{
use EnvelopeTrait;

public static function fromMessage(MessageInterface $message): self
{
$instance = new self();
$instance->message = $message;

return $instance;
}
}
15 changes: 15 additions & 0 deletions tests/App/StaticMessageHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Queue\Tests\App;

class StaticMessageHandler
{
public static bool $wasHandled = false;

public static function handle(): void
{
self::$wasHandled = true;
}
}
100 changes: 100 additions & 0 deletions tests/Unit/Command/SoftLimitTraitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Queue\Tests\Unit\Command;

use PHPUnit\Framework\TestCase;
use Yiisoft\Queue\Cli\SoftLimitTrait;

final class SoftLimitTraitTest extends TestCase
{
public function testMemoryLimitNotReachedWhenLimitIsZero(): void
{
$instance = new class () {
use SoftLimitTrait {
memoryLimitReached as public;
}

protected function getMemoryLimit(): int
{
return 0;
}
};

$this->assertFalse($instance->memoryLimitReached());
}

public function testMemoryLimitNotReachedWhenUsageIsLower(): void
{
$currentMemoryUsage = memory_get_usage(true);
$instance = new class ($currentMemoryUsage + 1024 * 1024) { // 1MB higher than current usage
use SoftLimitTrait {
memoryLimitReached as public;
}

public function __construct(private int $limit)
{
}

protected function getMemoryLimit(): int
{
return $this->limit;
}
};

$this->assertFalse($instance->memoryLimitReached());
}

public function testMemoryLimitReachedWhenUsageIsHigher(): void
{
$currentMemoryUsage = memory_get_usage(true);
$instance = new class ($currentMemoryUsage - 1024) { // 1KB lower than current usage
use SoftLimitTrait {
memoryLimitReached as public;
}

public function __construct(private int $limit)
{
}

protected function getMemoryLimit(): int
{
return $this->limit;
}
};

$this->assertTrue($instance->memoryLimitReached());
}

public function testMemoryLimitExceededWhenUsageIncreases(): void
{
$currentMemoryUsage = memory_get_usage(true);
$instance = new class ($currentMemoryUsage + 5 * 1024 * 1024) { // Set limit 5MB higher than current usage
use SoftLimitTrait {
memoryLimitReached as public;
}

public function __construct(private int $limit)
{
}

protected function getMemoryLimit(): int
{
return $this->limit;
}
};

// Initially memory limit is not reached
$this->assertFalse($instance->memoryLimitReached());

// Create a large string to increase memory usage
$largeString = str_repeat('x', 5 * 1024 * 1024 + 1); // 5MB and 1 byte string

// Now memory limit should be exceeded
$this->assertTrue($instance->memoryLimitReached());

// Clean up to free memory
unset($largeString);
}
}
49 changes: 49 additions & 0 deletions tests/Unit/Message/EnvelopeTraitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Queue\Tests\Unit\Message;

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

final class EnvelopeTraitTest extends TestCase
{
private function createTestEnvelope(): DummyEnvelope
{
return new DummyEnvelope();
}

public function testFromData(): void
{
$handlerName = 'test-handler';
$data = ['key' => 'value'];
$metadata = ['meta' => 'data'];

$envelope = DummyEnvelope::fromData($handlerName, $data, $metadata);

$this->assertInstanceOf(DummyEnvelope::class, $envelope);
$this->assertSame($handlerName, $envelope->getHandlerName());
$this->assertSame($data, $envelope->getData());
$this->assertArrayHasKey('meta', $envelope->getMetadata());
$this->assertSame('data', $envelope->getMetadata()['meta']);
}

public function testWithMessage(): void
{
$originalMessage = new Message('original-handler', 'original-data');
$newMessage = new Message('new-handler', 'new-data');

$envelope = $this->createTestEnvelope();
$envelope = $envelope->withMessage($originalMessage);

$this->assertSame($originalMessage, $envelope->getMessage());

$newEnvelope = $envelope->withMessage($newMessage);

$this->assertNotSame($envelope, $newEnvelope);
$this->assertSame($newMessage, $newEnvelope->getMessage());
$this->assertSame($originalMessage, $envelope->getMessage());
}
}
50 changes: 50 additions & 0 deletions tests/Unit/Message/JsonMessageSerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Yiisoft\Queue\Tests\Unit\Message;

use InvalidArgumentException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Yiisoft\Queue\Message\EnvelopeInterface;
use Yiisoft\Queue\Message\IdEnvelope;
Expand All @@ -18,6 +19,55 @@
*/
final class JsonMessageSerializerTest extends TestCase
{
/**
* @dataProvider dataUnsupportedHandlerNameFormat
*/
#[DataProvider('dataUnsupportedHandlerNameFormat')]
public function testHandlerNameFormat(mixed $name): void
{
$payload = ['name' => $name, 'data' => 'test'];
$serializer = $this->createSerializer();

$this->expectExceptionMessage(sprintf('Handler name must be a string. Got %s.', get_debug_type($name)));
$this->expectException(InvalidArgumentException::class);
$serializer->unserialize(json_encode($payload));
}

public static function dataUnsupportedHandlerNameFormat(): iterable
{
yield 'number' => [1];
yield 'boolean' => [true];
yield 'null' => [null];
yield 'array' => [[]];
}

public function testDefaultMessageClassFallbackWrongClass(): void
{
$serializer = $this->createSerializer();
$payload = [
'name' => 'handler',
'data' => 'test',
'meta' => [
'message-class' => 'NonExistentClass',
],
];

$message = $serializer->unserialize(json_encode($payload));
$this->assertInstanceOf(Message::class, $message);
}

public function testDefaultMessageClassFallbackClassNotSet(): void
{
$serializer = $this->createSerializer();
$payload = [
'name' => 'handler',
'data' => 'test',
'meta' => [],
];
$message = $serializer->unserialize(json_encode($payload));
$this->assertInstanceOf(Message::class, $message);
}

/**
* @dataProvider dataUnsupportedPayloadFormat
*/
Expand Down
54 changes: 54 additions & 0 deletions tests/Unit/WorkerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Yiisoft\Queue\Middleware\FailureHandling\MiddlewareFactoryFailureInterface;
use Yiisoft\Queue\QueueInterface;
use Yiisoft\Queue\Tests\App\FakeHandler;
use Yiisoft\Queue\Tests\App\StaticMessageHandler;
use Yiisoft\Queue\Tests\TestCase;
use Yiisoft\Queue\Worker\Worker;

Expand Down Expand Up @@ -199,4 +200,57 @@ private function createWorkerByParams(
new FailureMiddlewareDispatcher($this->createMock(MiddlewareFactoryFailureInterface::class), []),
);
}

public function testHandlerNotFoundInContainer(): void
{
$message = new Message('nonexistent', ['test-data']);
$logger = new SimpleLogger();
$container = new SimpleContainer();
$handlers = [];

$queue = $this->createMock(QueueInterface::class);
$worker = $this->createWorkerByParams($handlers, $logger, $container);

$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Queue handler with name "nonexistent" does not exist');
$worker->process($message, $queue);
}

public function testHandlerInContainerNotImplementingInterface(): void
{
$message = new Message('invalid', ['test-data']);
$logger = new SimpleLogger();
$container = new SimpleContainer([
'invalid' => new class () {
public function handle(): void
{
}
},
]);
$handlers = [];

$queue = $this->createMock(QueueInterface::class);
$worker = $this->createWorkerByParams($handlers, $logger, $container);

$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Queue handler with name "invalid" does not exist');
$worker->process($message, $queue);
}

public function testStaticMethodHandler(): void
{
$message = new Message('static-handler', ['test-data']);
$logger = new SimpleLogger();
$container = new SimpleContainer();
$handlers = [
'static-handler' => StaticMessageHandler::handle(...),
];

$queue = $this->createMock(QueueInterface::class);
$worker = $this->createWorkerByParams($handlers, $logger, $container);

StaticMessageHandler::$wasHandled = false;
$worker->process($message, $queue);
$this->assertTrue(StaticMessageHandler::$wasHandled);
}
}
Loading