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:
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user