fix: DockerSecretsResolver - don't normalize absolute paths like /var/www/html/...
Some checks failed
Deploy Application / deploy (push) Has been cancelled

This commit is contained in:
2025-11-24 21:28:25 +01:00
parent 4eb7134853
commit 77abc65cd7
1327 changed files with 91915 additions and 9909 deletions

View File

@@ -0,0 +1,172 @@
<?php
declare(strict_types=1);
namespace Tests\Unit\Framework\LiveComponents\Middleware;
use App\Framework\DI\Container;
use App\Framework\DI\DefaultContainer;
use App\Framework\LiveComponents\Contracts\LiveComponentContract;
use App\Framework\LiveComponents\Middleware\ComponentMiddlewarePipeline;
use App\Framework\LiveComponents\Middleware\MiddlewareRegistration;
use App\Framework\LiveComponents\ValueObjects\ActionParameters;
use App\Framework\LiveComponents\ValueObjects\ComponentId;
use App\Framework\LiveComponents\ValueObjects\ComponentState;
use App\Framework\LiveComponents\ValueObjects\ComponentUpdate;
use App\Framework\LiveComponents\ValueObjects\LiveComponentState;
use Tests\Unit\Framework\LiveComponents\Middleware\TestMiddleware1;
use Tests\Unit\Framework\LiveComponents\Middleware\TestMiddleware2;
use Tests\Unit\Framework\LiveComponents\Middleware\TestPassThroughMiddleware;
use Tests\Unit\Framework\LiveComponents\Middleware\TestCaptureMiddleware;
// Ensure test middleware classes are loaded
require_once __DIR__ . '/TestMiddleware.php';
describe('ComponentMiddlewarePipeline', function () {
beforeEach(function () {
$this->container = new DefaultContainer();
});
it('executes middleware in priority order', function () {
$executionOrder = [];
// Register middleware in container
$this->container->instance(TestMiddleware1::class, new TestMiddleware1($executionOrder));
$this->container->instance(TestMiddleware2::class, new TestMiddleware2($executionOrder));
// Create pipeline with middleware (higher priority first)
$middlewares = [
new MiddlewareRegistration(TestMiddleware1::class, priority: 200),
new MiddlewareRegistration(TestMiddleware2::class, priority: 100),
];
$pipeline = new ComponentMiddlewarePipeline($middlewares, $this->container);
// Create test component
$component = new class(ComponentId::create('test', 'demo'), ComponentState::empty()) implements LiveComponentContract {
public function __construct(public ComponentId $id, public ComponentState $state) {}
public function getRenderData() {
return new \App\Framework\LiveComponents\ValueObjects\ComponentRenderData('test', []);
}
};
// Execute pipeline
$result = $pipeline->process(
$component,
'testAction',
ActionParameters::fromArray([]),
fn($c, $a, $p) => new ComponentUpdate(
component: $c,
state: LiveComponentState::fromArray([]),
events: []
)
);
// Middleware should execute in priority order (higher first)
expect($executionOrder)->toBe(['middleware1', 'middleware2']);
});
it('passes component, action, and params through middleware chain', function () {
$receivedComponent = null;
$receivedAction = null;
$receivedParams = null;
$middleware = new TestCaptureMiddleware($receivedComponent, $receivedAction, $receivedParams);
$this->container->instance(TestCaptureMiddleware::class, $middleware);
$middlewares = [
new MiddlewareRegistration(TestCaptureMiddleware::class, priority: 100),
];
$pipeline = new ComponentMiddlewarePipeline($middlewares, $this->container);
$component = new class(ComponentId::create('test', 'demo'), ComponentState::empty()) implements LiveComponentContract {
public function __construct(public ComponentId $id, public ComponentState $state) {}
public function getRenderData() {
return new \App\Framework\LiveComponents\ValueObjects\ComponentRenderData('test', []);
}
};
$params = ActionParameters::fromArray(['test' => 'value']);
$pipeline->process(
$component,
'testAction',
$params,
fn($c, $a, $p) => new ComponentUpdate(
component: $c,
state: LiveComponentState::fromArray([]),
events: []
)
);
expect($receivedComponent)->toBe($component);
expect($receivedAction)->toBe('testAction');
expect($receivedParams)->toBe($params);
});
it('returns action handler result', function () {
$expectedResult = new ComponentUpdate(
component: new class(ComponentId::create('test', 'demo'), ComponentState::empty()) implements LiveComponentContract {
public function __construct(public ComponentId $id, public ComponentState $state) {}
public function getRenderData() {
return new \App\Framework\LiveComponents\ValueObjects\ComponentRenderData('test', []);
}
},
state: LiveComponentState::fromArray(['result' => 'success']),
events: []
);
$middleware = new TestPassThroughMiddleware();
$this->container->instance(TestPassThroughMiddleware::class, $middleware);
$middlewares = [
new MiddlewareRegistration(TestPassThroughMiddleware::class, priority: 100),
];
$pipeline = new ComponentMiddlewarePipeline($middlewares, $this->container);
$component = new class(ComponentId::create('test', 'demo'), ComponentState::empty()) implements LiveComponentContract {
public function __construct(public ComponentId $id, public ComponentState $state) {}
public function getRenderData() {
return new \App\Framework\LiveComponents\ValueObjects\ComponentRenderData('test', []);
}
};
$result = $pipeline->process(
$component,
'testAction',
ActionParameters::fromArray([]),
fn($c, $a, $p) => $expectedResult
);
expect($result)->toBe($expectedResult);
});
it('handles empty middleware array', function () {
$pipeline = new ComponentMiddlewarePipeline([], $this->container);
$component = new class(ComponentId::create('test', 'demo'), ComponentState::empty()) implements LiveComponentContract {
public function __construct(public ComponentId $id, public ComponentState $state) {}
public function getRenderData() {
return new \App\Framework\LiveComponents\ValueObjects\ComponentRenderData('test', []);
}
};
$expectedResult = new ComponentUpdate(
component: $component,
state: LiveComponentState::fromArray([]),
events: []
);
$result = $pipeline->process(
$component,
'testAction',
ActionParameters::fromArray([]),
fn($c, $a, $p) => $expectedResult
);
expect($result)->toBe($expectedResult);
});
});

View File

@@ -0,0 +1,165 @@
<?php
declare(strict_types=1);
namespace Tests\Unit\Framework\LiveComponents\Middleware;
use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\Core\ValueObjects\MethodName;
use App\Framework\Discovery\Results\AttributeRegistry;
use App\Framework\Discovery\Results\DiscoveryRegistry;
use App\Framework\Discovery\Results\InterfaceRegistry;
use App\Framework\Discovery\Results\TemplateRegistry;
use App\Framework\Discovery\ValueObjects\AttributeTarget;
use App\Framework\Discovery\ValueObjects\DiscoveredAttribute;
use App\Framework\LiveComponents\Attributes\Middleware as MiddlewareAttribute;
use App\Framework\LiveComponents\Middleware\MiddlewareCollector;
use App\Framework\LiveComponents\Middleware\LoggingMiddleware;
describe('MiddlewareCollector', function () {
beforeEach(function () {
$this->attributeRegistry = new AttributeRegistry();
$this->discoveryRegistry = new DiscoveryRegistry(
attributes: $this->attributeRegistry,
interfaces: new InterfaceRegistry([]),
templates: new TemplateRegistry([])
);
$this->collector = new MiddlewareCollector($this->discoveryRegistry);
});
it('collects component-level middleware', function () {
$componentClass = ClassName::create('Test\\Component');
// Add component-level middleware attribute
$discovered = new DiscoveredAttribute(
className: $componentClass,
attributeClass: MiddlewareAttribute::class,
target: AttributeTarget::TARGET_CLASS,
arguments: [LoggingMiddleware::class, 100]
);
$this->attributeRegistry->add(MiddlewareAttribute::class, $discovered);
$middlewares = $this->collector->collectForAction(
$componentClass,
MethodName::create('testAction')
);
expect($middlewares)->toHaveCount(1);
expect($middlewares[0]->middlewareClass)->toBe(LoggingMiddleware::class);
expect($middlewares[0]->priority)->toBe(100);
});
it('collects action-level middleware', function () {
$componentClass = ClassName::create('Test\\Component');
$actionMethod = MethodName::create('testAction');
// Add action-level middleware attribute
$discovered = new DiscoveredAttribute(
className: $componentClass,
attributeClass: MiddlewareAttribute::class,
target: AttributeTarget::TARGET_METHOD,
methodName: $actionMethod,
arguments: [LoggingMiddleware::class, 200]
);
$this->attributeRegistry->add(MiddlewareAttribute::class, $discovered);
$middlewares = $this->collector->collectForAction(
$componentClass,
$actionMethod
);
expect($middlewares)->toHaveCount(1);
expect($middlewares[0]->middlewareClass)->toBe(LoggingMiddleware::class);
expect($middlewares[0]->priority)->toBe(200);
});
it('combines component and action-level middleware', function () {
$componentClass = ClassName::create('Test\\Component');
$actionMethod = MethodName::create('testAction');
// Add component-level middleware
$componentMiddleware = new DiscoveredAttribute(
className: $componentClass,
attributeClass: MiddlewareAttribute::class,
target: AttributeTarget::TARGET_CLASS,
arguments: [LoggingMiddleware::class, 100]
);
// Add action-level middleware
$actionMiddleware = new DiscoveredAttribute(
className: $componentClass,
attributeClass: MiddlewareAttribute::class,
target: AttributeTarget::TARGET_METHOD,
methodName: $actionMethod,
arguments: [\App\Framework\LiveComponents\Middleware\CachingMiddleware::class, 200]
);
$this->attributeRegistry->add(MiddlewareAttribute::class, $componentMiddleware);
$this->attributeRegistry->add(MiddlewareAttribute::class, $actionMiddleware);
$middlewares = $this->collector->collectForAction(
$componentClass,
$actionMethod
);
expect($middlewares)->toHaveCount(2);
// Should be sorted by priority (higher first)
expect($middlewares[0]->priority)->toBe(200);
expect($middlewares[1]->priority)->toBe(100);
});
it('sorts middleware by priority descending', function () {
$componentClass = ClassName::create('Test\\Component');
// Add multiple middleware with different priorities
$middleware1 = new DiscoveredAttribute(
className: $componentClass,
attributeClass: MiddlewareAttribute::class,
target: AttributeTarget::TARGET_CLASS,
arguments: [LoggingMiddleware::class, 50]
);
$middleware2 = new DiscoveredAttribute(
className: $componentClass,
attributeClass: MiddlewareAttribute::class,
target: AttributeTarget::TARGET_CLASS,
arguments: [\App\Framework\LiveComponents\Middleware\CachingMiddleware::class, 150]
);
$middleware3 = new DiscoveredAttribute(
className: $componentClass,
attributeClass: MiddlewareAttribute::class,
target: AttributeTarget::TARGET_CLASS,
arguments: [\App\Framework\LiveComponents\Middleware\RateLimitMiddleware::class, 100]
);
$this->attributeRegistry->add(MiddlewareAttribute::class, $middleware1);
$this->attributeRegistry->add(MiddlewareAttribute::class, $middleware2);
$this->attributeRegistry->add(MiddlewareAttribute::class, $middleware3);
$middlewares = $this->collector->collectForAction(
$componentClass,
MethodName::create('testAction')
);
expect($middlewares)->toHaveCount(3);
// Should be sorted by priority descending
expect($middlewares[0]->priority)->toBe(150);
expect($middlewares[1]->priority)->toBe(100);
expect($middlewares[2]->priority)->toBe(50);
});
it('returns empty array when no middleware found', function () {
$componentClass = ClassName::create('Test\\Component');
$middlewares = $this->collector->collectForAction(
$componentClass,
MethodName::create('testAction')
);
expect($middlewares)->toBeEmpty();
});
});

View File

@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Tests\Unit\Framework\LiveComponents\Middleware;
use App\Framework\LiveComponents\Middleware\ComponentMiddlewareInterface;
use App\Framework\LiveComponents\ValueObjects\ComponentUpdate;
use App\Framework\LiveComponents\ValueObjects\LiveComponentState;
use Tests\Unit\Framework\LiveComponents\Middleware\TestMiddleware1;
it('can create middleware', function () {
$order = [];
$middleware = new TestMiddleware1($order);
expect($middleware)->toBeInstanceOf(ComponentMiddlewareInterface::class);
});

View File

@@ -0,0 +1,97 @@
<?php
declare(strict_types=1);
namespace Tests\Unit\Framework\LiveComponents\Middleware;
use App\Framework\LiveComponents\Contracts\LiveComponentContract;
use App\Framework\LiveComponents\Middleware\ComponentMiddlewareInterface;
use App\Framework\LiveComponents\ValueObjects\ActionParameters;
use App\Framework\LiveComponents\ValueObjects\ComponentUpdate;
/**
* Test Middleware for unit tests
*/
final class TestMiddleware1 implements ComponentMiddlewareInterface
{
private array $executionOrder;
public function __construct(
array &$executionOrder
) {
$this->executionOrder = &$executionOrder;
}
public function handle(
LiveComponentContract $component,
string $action,
ActionParameters $params,
callable $next
): ComponentUpdate {
$this->executionOrder[] = 'middleware1';
return $next($component, $action, $params);
}
}
final class TestMiddleware2 implements ComponentMiddlewareInterface
{
private array $executionOrder;
public function __construct(
array &$executionOrder
) {
$this->executionOrder = &$executionOrder;
}
public function handle(
LiveComponentContract $component,
string $action,
ActionParameters $params,
callable $next
): ComponentUpdate {
$this->executionOrder[] = 'middleware2';
return $next($component, $action, $params);
}
}
final class TestPassThroughMiddleware implements ComponentMiddlewareInterface
{
public function handle(
LiveComponentContract $component,
string $action,
ActionParameters $params,
callable $next
): ComponentUpdate {
return $next($component, $action, $params);
}
}
final class TestCaptureMiddleware implements ComponentMiddlewareInterface
{
private ?LiveComponentContract $capturedComponent;
private ?string $capturedAction;
private ?ActionParameters $capturedParams;
public function __construct(
?LiveComponentContract &$capturedComponent,
?string &$capturedAction,
?ActionParameters &$capturedParams
) {
$this->capturedComponent = &$capturedComponent;
$this->capturedAction = &$capturedAction;
$this->capturedParams = &$capturedParams;
}
public function handle(
LiveComponentContract $component,
string $action,
ActionParameters $params,
callable $next
): ComponentUpdate {
$this->capturedComponent = $component;
$this->capturedAction = $action;
$this->capturedParams = $params;
return $next($component, $action, $params);
}
}