fix: DockerSecretsResolver - don't normalize absolute paths like /var/www/html/...
Some checks failed
Deploy Application / deploy (push) Has been cancelled
Some checks failed
Deploy Application / deploy (push) Has been cancelled
This commit is contained in:
348
tests/Framework/CommandBus/AttributeExecutionIntegrationTest.php
Normal file
348
tests/Framework/CommandBus/AttributeExecutionIntegrationTest.php
Normal file
@@ -0,0 +1,348 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\CommandBus;
|
||||
|
||||
use App\Framework\Attributes\AfterExecute;
|
||||
use App\Framework\Attributes\BeforeExecute;
|
||||
use App\Framework\Attributes\Execution\AttributeExecutionInitializer;
|
||||
use App\Framework\Attributes\Execution\AttributeRunner;
|
||||
use App\Framework\Attributes\Execution\CallbackExecutor;
|
||||
use App\Framework\Attributes\Execution\HandlerAttributeExecutor;
|
||||
use App\Framework\Attributes\OnError;
|
||||
use App\Framework\CommandBus\CommandBus;
|
||||
use App\Framework\CommandBus\CommandHandler;
|
||||
use App\Framework\CommandBus\CommandHandlersCollection;
|
||||
use App\Framework\CommandBus\CommandHandlerDescriptor;
|
||||
use App\Framework\CommandBus\DefaultCommandBus;
|
||||
use App\Framework\Context\ContextType;
|
||||
use App\Framework\Context\ExecutionContext;
|
||||
use App\Framework\DI\Container;
|
||||
use App\Framework\DI\DefaultContainer;
|
||||
use App\Framework\DI\MethodInvoker;
|
||||
use App\Framework\Discovery\Results\AttributeRegistry;
|
||||
use App\Framework\Discovery\Results\DiscoveryRegistry;
|
||||
use App\Framework\Discovery\ValueObjects\AttributeTarget;
|
||||
use App\Framework\Discovery\ValueObjects\DiscoveredAttribute;
|
||||
use App\Framework\Logging\Logger;
|
||||
use App\Framework\Performance\Contracts\PerformanceCollectorInterface;
|
||||
use App\Framework\Performance\PerformanceCategory;
|
||||
use App\Framework\Performance\PerformanceMetric;
|
||||
use App\Framework\Queue\Queue;
|
||||
use App\Framework\Reflection\SimpleReflectionService;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class AttributeExecutionIntegrationTest extends TestCase
|
||||
{
|
||||
private Container $container;
|
||||
private CommandBus $commandBus;
|
||||
private \ArrayObject $beforeExecuted;
|
||||
private \ArrayObject $afterExecuted;
|
||||
private \ArrayObject $onErrorExecuted;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->container = new DefaultContainer();
|
||||
$this->container->instance(MethodInvoker::class, new MethodInvoker(
|
||||
$this->container,
|
||||
new SimpleReflectionService()
|
||||
));
|
||||
|
||||
// Mock Logger
|
||||
$logger = $this->createMock(Logger::class);
|
||||
$this->container->instance(Logger::class, $logger);
|
||||
|
||||
// Mock Queue
|
||||
$queue = $this->createMock(Queue::class);
|
||||
$this->container->instance(Queue::class, $queue);
|
||||
|
||||
// Mock PerformanceCollectorInterface (optional - wird nur verwendet wenn verfügbar)
|
||||
// Wir registrieren es nicht, damit die Middleware es als optional behandelt
|
||||
|
||||
// Mock ExecutionContext
|
||||
$executionContext = new ExecutionContext(ContextType::TEST);
|
||||
$this->container->instance(ExecutionContext::class, $executionContext);
|
||||
|
||||
// Reset execution tracking
|
||||
$this->beforeExecuted = new \ArrayObject();
|
||||
$this->afterExecuted = new \ArrayObject();
|
||||
$this->onErrorExecuted = new \ArrayObject();
|
||||
}
|
||||
|
||||
public function testBeforeExecuteAttributeIsExecuted(): void
|
||||
{
|
||||
$command = new TestCommand('test');
|
||||
|
||||
$handler = new TestHandlerWithBeforeAttribute($this->beforeExecuted);
|
||||
|
||||
$this->setupCommandBus($handler::class, 'handle', TestCommand::class);
|
||||
|
||||
$this->commandBus->dispatch($command);
|
||||
|
||||
$this->assertContains('before', (array)$this->beforeExecuted, 'BeforeExecute should have been executed');
|
||||
}
|
||||
|
||||
public function testAfterExecuteAttributeIsExecuted(): void
|
||||
{
|
||||
$command = new TestCommand('test');
|
||||
|
||||
$handler = new TestHandlerWithAfterAttribute($this->afterExecuted);
|
||||
|
||||
$this->setupCommandBus($handler::class, 'handle', TestCommand::class);
|
||||
|
||||
$result = $this->commandBus->dispatch($command);
|
||||
|
||||
$this->assertContains('after', (array)$this->afterExecuted);
|
||||
$this->assertEquals('result', $result);
|
||||
}
|
||||
|
||||
public function testOnErrorAttributeIsExecuted(): void
|
||||
{
|
||||
$command = new TestCommand('test');
|
||||
|
||||
$handler = new TestHandlerWithOnErrorAttribute($this->onErrorExecuted);
|
||||
|
||||
$this->setupCommandBus($handler::class, 'handle', TestCommand::class);
|
||||
|
||||
try {
|
||||
$this->commandBus->dispatch($command);
|
||||
$this->fail('Expected exception was not thrown');
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->assertEquals('Test error', $e->getMessage());
|
||||
}
|
||||
|
||||
$this->assertContains('error', (array)$this->onErrorExecuted);
|
||||
}
|
||||
|
||||
private function setupCommandBus(string $handlerClass, string $handlerMethod, string $commandClass): void
|
||||
{
|
||||
// Erstelle Handler-Descriptor
|
||||
$handlerDescriptor = new CommandHandlerDescriptor(
|
||||
class: $handlerClass,
|
||||
method: $handlerMethod,
|
||||
command: $commandClass
|
||||
);
|
||||
|
||||
$handlersCollection = new CommandHandlersCollection($handlerDescriptor);
|
||||
$this->container->instance(CommandHandlersCollection::class, $handlersCollection);
|
||||
|
||||
// Erstelle DiscoveryRegistry mit Handler-Attribut
|
||||
$discoveryRegistry = new DiscoveryRegistry(
|
||||
attributes: new AttributeRegistry()
|
||||
);
|
||||
|
||||
// Füge CommandHandler-Attribut hinzu
|
||||
$commandHandlerAttribute = new DiscoveredAttribute(
|
||||
className: \App\Framework\Core\ValueObjects\ClassName::create($handlerClass),
|
||||
attributeClass: CommandHandler::class,
|
||||
target: AttributeTarget::METHOD,
|
||||
methodName: \App\Framework\Core\ValueObjects\MethodName::create($handlerMethod),
|
||||
arguments: [],
|
||||
additionalData: [
|
||||
'class' => $handlerClass,
|
||||
'method' => $handlerMethod,
|
||||
'command' => $commandClass,
|
||||
]
|
||||
);
|
||||
$discoveryRegistry->attributes->add(CommandHandler::class, $commandHandlerAttribute);
|
||||
|
||||
// Entdecke BeforeExecute, AfterExecute, OnError Attribute für den Handler
|
||||
$reflectionClass = new \ReflectionClass($handlerClass);
|
||||
$reflectionMethod = $reflectionClass->getMethod($handlerMethod);
|
||||
|
||||
foreach ($reflectionMethod->getAttributes(BeforeExecute::class) as $attribute) {
|
||||
$beforeAttribute = new DiscoveredAttribute(
|
||||
className: \App\Framework\Core\ValueObjects\ClassName::create($handlerClass),
|
||||
attributeClass: BeforeExecute::class,
|
||||
target: AttributeTarget::METHOD,
|
||||
methodName: \App\Framework\Core\ValueObjects\MethodName::create($handlerMethod),
|
||||
arguments: $attribute->getArguments(),
|
||||
additionalData: []
|
||||
);
|
||||
$discoveryRegistry->attributes->add(BeforeExecute::class, $beforeAttribute);
|
||||
}
|
||||
|
||||
foreach ($reflectionMethod->getAttributes(AfterExecute::class) as $attribute) {
|
||||
$afterAttribute = new DiscoveredAttribute(
|
||||
className: \App\Framework\Core\ValueObjects\ClassName::create($handlerClass),
|
||||
attributeClass: AfterExecute::class,
|
||||
target: AttributeTarget::METHOD,
|
||||
methodName: \App\Framework\Core\ValueObjects\MethodName::create($handlerMethod),
|
||||
arguments: $attribute->getArguments(),
|
||||
additionalData: []
|
||||
);
|
||||
$discoveryRegistry->attributes->add(AfterExecute::class, $afterAttribute);
|
||||
}
|
||||
|
||||
foreach ($reflectionMethod->getAttributes(OnError::class) as $attribute) {
|
||||
$onErrorAttribute = new DiscoveredAttribute(
|
||||
className: \App\Framework\Core\ValueObjects\ClassName::create($handlerClass),
|
||||
attributeClass: OnError::class,
|
||||
target: AttributeTarget::METHOD,
|
||||
methodName: \App\Framework\Core\ValueObjects\MethodName::create($handlerMethod),
|
||||
arguments: $attribute->getArguments(),
|
||||
additionalData: []
|
||||
);
|
||||
$discoveryRegistry->attributes->add(OnError::class, $onErrorAttribute);
|
||||
}
|
||||
|
||||
$this->container->instance(\App\Framework\Discovery\Results\DiscoveryRegistry::class, $discoveryRegistry);
|
||||
|
||||
// Initialisiere Attribute Execution System
|
||||
$callbackExecutor = new CallbackExecutor($this->container);
|
||||
$this->container->instance(CallbackExecutor::class, $callbackExecutor);
|
||||
|
||||
$attributeRunner = new AttributeRunner(
|
||||
discoveryRegistry: $discoveryRegistry,
|
||||
container: $this->container,
|
||||
callbackExecutor: $callbackExecutor
|
||||
);
|
||||
$this->container->instance(AttributeRunner::class, $attributeRunner);
|
||||
|
||||
// Registriere Test-Handler im Container
|
||||
$handlerInstance = new $handlerClass(...$this->getHandlerDependencies($handlerClass));
|
||||
$this->container->instance($handlerClass, $handlerInstance);
|
||||
|
||||
// Registriere Test-Attribute-Handler mit korrekten Referenzen
|
||||
// WICHTIG: Wir müssen die ArrayObjects direkt übergeben, nicht über Closures
|
||||
if (str_contains($handlerClass, 'Before')) {
|
||||
$this->container->instance(TestBeforeHandler::class, new TestBeforeHandler($this->beforeExecuted));
|
||||
}
|
||||
if (str_contains($handlerClass, 'After')) {
|
||||
$this->container->instance(TestAfterHandler::class, new TestAfterHandler($this->afterExecuted));
|
||||
}
|
||||
if (str_contains($handlerClass, 'OnError')) {
|
||||
$this->container->instance(TestOnErrorHandler::class, new TestOnErrorHandler($this->onErrorExecuted));
|
||||
}
|
||||
|
||||
$handlerAttributeExecutor = new HandlerAttributeExecutor(
|
||||
discoveryRegistry: $discoveryRegistry,
|
||||
container: $this->container,
|
||||
attributeRunner: $attributeRunner
|
||||
);
|
||||
$this->container->instance(HandlerAttributeExecutor::class, $handlerAttributeExecutor);
|
||||
|
||||
// Erstelle CommandBus
|
||||
$executionContext = $this->container->get(ExecutionContext::class);
|
||||
$queue = $this->container->get(Queue::class);
|
||||
$logger = $this->container->get(Logger::class);
|
||||
|
||||
$this->commandBus = new DefaultCommandBus(
|
||||
commandHandlers: $handlersCollection,
|
||||
container: $this->container,
|
||||
executionContext: $executionContext,
|
||||
queue: $queue,
|
||||
logger: $logger
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
*/
|
||||
private function getHandlerDependencies(string $handlerClass): array
|
||||
{
|
||||
if (str_contains($handlerClass, 'Before')) {
|
||||
return [$this->beforeExecuted];
|
||||
}
|
||||
if (str_contains($handlerClass, 'After')) {
|
||||
return [$this->afterExecuted];
|
||||
}
|
||||
if (str_contains($handlerClass, 'OnError')) {
|
||||
return [$this->onErrorExecuted];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Test Command
|
||||
final readonly class TestCommand
|
||||
{
|
||||
public function __construct(
|
||||
public string $data
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test Handler mit BeforeExecute Attribute
|
||||
final class TestHandlerWithBeforeAttribute
|
||||
{
|
||||
public function __construct(
|
||||
private \ArrayObject $beforeExecuted
|
||||
) {}
|
||||
|
||||
#[BeforeExecute(TestBeforeHandler::class)]
|
||||
#[CommandHandler]
|
||||
public function handle(TestCommand $command): void
|
||||
{
|
||||
// Handler logic
|
||||
}
|
||||
}
|
||||
|
||||
// Test Handler mit AfterExecute Attribute
|
||||
final class TestHandlerWithAfterAttribute
|
||||
{
|
||||
public function __construct(
|
||||
private \ArrayObject $afterExecuted
|
||||
) {}
|
||||
|
||||
#[AfterExecute(TestAfterHandler::class)]
|
||||
#[CommandHandler]
|
||||
public function handle(TestCommand $command): string
|
||||
{
|
||||
return 'result';
|
||||
}
|
||||
}
|
||||
|
||||
// Test Handler mit OnError Attribute
|
||||
final class TestHandlerWithOnErrorAttribute
|
||||
{
|
||||
public function __construct(
|
||||
private \ArrayObject $onErrorExecuted
|
||||
) {}
|
||||
|
||||
#[OnError(TestOnErrorHandler::class)]
|
||||
#[CommandHandler]
|
||||
public function handle(TestCommand $command): void
|
||||
{
|
||||
throw new \RuntimeException('Test error');
|
||||
}
|
||||
}
|
||||
|
||||
// Test Handler-Klassen für Attribute
|
||||
final class TestBeforeHandler
|
||||
{
|
||||
public function __construct(
|
||||
private \ArrayObject $beforeExecuted
|
||||
) {}
|
||||
|
||||
public function __invoke($ctx): void
|
||||
{
|
||||
$this->beforeExecuted[] = 'before';
|
||||
}
|
||||
}
|
||||
|
||||
final class TestAfterHandler
|
||||
{
|
||||
public function __construct(
|
||||
private \ArrayObject $afterExecuted
|
||||
) {}
|
||||
|
||||
public function __invoke($ctx): void
|
||||
{
|
||||
$this->afterExecuted[] = 'after';
|
||||
}
|
||||
}
|
||||
|
||||
final class TestOnErrorHandler
|
||||
{
|
||||
public function __construct(
|
||||
private \ArrayObject $onErrorExecuted
|
||||
) {}
|
||||
|
||||
public function __invoke($ctx): void
|
||||
{
|
||||
$this->onErrorExecuted[] = 'error';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user