Files
michaelschiemer/tests/Framework/CommandBus/DefaultCommandBusTest.php
Michael Schiemer 55a330b223 Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
2025-08-11 20:13:26 +02:00

207 lines
5.4 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\CommandBus\CommandHandlerDescriptor;
use App\Framework\CommandBus\CommandHandlersCollection;
use App\Framework\CommandBus\DefaultCommandBus;
use App\Framework\CommandBus\Exceptions\NoHandlerFound;
use App\Framework\CommandBus\ShouldQueue;
use App\Framework\Context\ContextType;
use App\Framework\Context\ExecutionContext;
use App\Framework\DI\DefaultContainer;
use App\Framework\Logging\Logger;
use App\Framework\Queue\Queue;
beforeEach(function () {
$this->container = new DefaultContainer();
$this->executionContext = createTestExecutionContext();
$this->queue = new TestQueue();
$this->logger = new TestLogger();
});
test('command handlers collection returns correct handler', function () {
$descriptor = new CommandHandlerDescriptor(TestCommandHandler::class, 'handle', TestCommand::class);
$collection = new CommandHandlersCollection($descriptor);
$retrieved = $collection->get(TestCommand::class);
expect($retrieved)->toBe($descriptor)
->and($retrieved->class)->toBe(TestCommandHandler::class)
->and($retrieved->method)->toBe('handle')
->and($retrieved->command)->toBe(TestCommand::class);
});
test('command handlers collection returns null for non-existent command', function () {
$collection = new CommandHandlersCollection();
$result = $collection->get('NonExistentCommand');
expect($result)->toBeNull();
});
test('command handler descriptor stores class and method', function () {
$descriptor = new CommandHandlerDescriptor('TestClass', 'testMethod', 'TestCommand');
expect($descriptor->class)->toBe('TestClass')
->and($descriptor->method)->toBe('testMethod')
->and($descriptor->command)->toBe('TestCommand');
});
test('no handler found exception contains command class', function () {
$commandClass = 'TestCommand';
$exception = NoHandlerFound::forCommand($commandClass);
expect($exception->getMessage())
->toContain($commandClass);
});
test('dispatch executes command handler directly', function () {
$command = new TestCommand('test-data');
$handler = new TestCommandHandler();
$handlerDescriptor = new CommandHandlerDescriptor(TestCommandHandler::class, 'handle', TestCommand::class);
$commandHandlers = new CommandHandlersCollection($handlerDescriptor);
$commandBus = new DefaultCommandBus(
$commandHandlers,
$this->container,
$this->executionContext,
$this->queue,
$this->logger,
[] // No middlewares for basic tests
);
$this->container->instance(TestCommandHandler::class, $handler);
$result = $commandBus->dispatch($command);
expect($result)->toBe('Handled: test-data');
});
test('dispatch throws exception when no handler found', function () {
$command = new TestCommand('test-data');
$commandHandlers = new CommandHandlersCollection(); // Empty collection
$commandBus = new DefaultCommandBus(
$commandHandlers,
$this->container,
$this->executionContext,
$this->queue,
$this->logger,
[] // No middlewares for basic tests
);
expect(fn () => $commandBus->dispatch($command))
->toThrow(NoHandlerFound::class);
});
test('should queue attribute is recognized', function () {
$command = new QueueableTestCommand('queue-data');
$commandHandlers = new CommandHandlersCollection(); // Empty collection to test queueing
$commandBus = new DefaultCommandBus(
$commandHandlers,
$this->container,
$this->executionContext,
$this->queue,
$this->logger,
[] // No middlewares for basic tests
);
// For queued commands, the result should be null
$result = $commandBus->dispatch($command);
expect($result)->toBeNull()
->and($this->queue->wasUsed())->toBeTrue();
});
// Test fixtures
class TestCommand
{
public function __construct(
public readonly string $data
) {
}
}
#[ShouldQueue]
class QueueableTestCommand
{
public function __construct(
public readonly string $data
) {
}
}
class TestCommandHandler
{
public function handle(TestCommand $command): string
{
return 'Handled: ' . $command->data;
}
}
// ExecutionContext is final, so we create a simple instance
function createTestExecutionContext(): ExecutionContext
{
return new ExecutionContext(ContextType::WEB);
}
class TestQueue implements Queue
{
private bool $used = false;
private array $jobs = [];
public function push(object $job): void
{
$this->used = true;
$this->jobs[] = $job;
}
public function pop(): ?object
{
return array_shift($this->jobs);
}
public function wasUsed(): bool
{
return $this->used;
}
}
class TestLogger implements Logger
{
public function emergency(string $message, array $context = []): void
{
}
public function alert(string $message, array $context = []): void
{
}
public function critical(string $message, array $context = []): void
{
}
public function error(string $message, array $context = []): void
{
}
public function warning(string $message, array $context = []): void
{
}
public function notice(string $message, array $context = []): void
{
}
public function info(string $message, array $context = []): void
{
}
public function debug(string $message, array $context = []): void
{
}
}