Some checks failed
Deploy Application / deploy (push) Has been cancelled
104 lines
4.0 KiB
PHP
104 lines
4.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Unit\Framework\LiveComponents\Security;
|
|
|
|
require_once __DIR__ . '/TestComponents.php';
|
|
|
|
use App\Application\LiveComponents\Counter\CounterState;
|
|
use App\Framework\Attributes\Execution\AttributeExecutionContext;
|
|
use App\Framework\Core\ValueObjects\ClassName;
|
|
use App\Framework\Core\ValueObjects\ClientIdentifier;
|
|
use App\Framework\Core\ValueObjects\MethodName;
|
|
use App\Framework\DI\DefaultContainer;
|
|
use App\Framework\LiveComponents\Attributes\Action;
|
|
use App\Framework\LiveComponents\Contracts\LiveComponentContract;
|
|
use App\Framework\LiveComponents\Exceptions\RateLimitExceededException;
|
|
use App\Framework\LiveComponents\Security\Guards\LiveComponentRateLimitGuard;
|
|
use App\Framework\LiveComponents\Security\LiveComponentContextHelper;
|
|
use App\Framework\LiveComponents\Services\LiveComponentRateLimiter;
|
|
use App\Framework\LiveComponents\Services\RateLimitResult;
|
|
use App\Framework\LiveComponents\ValueObjects\ActionParameters;
|
|
use App\Framework\LiveComponents\ValueObjects\ComponentId;
|
|
use App\Framework\Cache\Driver\InMemoryCache;
|
|
use App\Framework\Cache\GeneralCache;
|
|
use App\Framework\Serializer\Php\PhpSerializer;
|
|
use App\Framework\Serializer\Php\PhpSerializerConfig;
|
|
use App\Framework\RateLimit\RateLimiter;
|
|
use App\Framework\RateLimit\Storage\CacheStorage;
|
|
use Tests\Unit\Framework\LiveComponents\Security\TestComponent;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class LiveComponentRateLimitGuardTest extends TestCase
|
|
{
|
|
private LiveComponentRateLimitGuard $guard;
|
|
private LiveComponentRateLimiter $rateLimiter;
|
|
private DefaultContainer $container;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
// Use real instance since LiveComponentRateLimiter is final
|
|
$this->container = new DefaultContainer();
|
|
$cacheDriver = new InMemoryCache();
|
|
$serializer = new PhpSerializer(PhpSerializerConfig::safe());
|
|
$cache = new GeneralCache($cacheDriver, $serializer);
|
|
$storage = new CacheStorage($cache);
|
|
$baseRateLimiter = new RateLimiter($storage);
|
|
$this->container->instance(\App\Framework\RateLimit\RateLimiter::class, $baseRateLimiter);
|
|
$this->rateLimiter = new LiveComponentRateLimiter($baseRateLimiter);
|
|
|
|
$this->guard = new LiveComponentRateLimitGuard($this->rateLimiter);
|
|
}
|
|
|
|
public function test_skips_check_when_no_client_identifier(): void
|
|
{
|
|
$component = $this->createComponent();
|
|
$params = ActionParameters::fromArray([]);
|
|
$context = $this->createContext($component, $params);
|
|
$actionAttribute = new Action(rateLimit: 10);
|
|
|
|
// Should not throw and not call rate limiter (no client identifier)
|
|
$this->guard->check($context, $actionAttribute);
|
|
$this->assertTrue(true);
|
|
}
|
|
|
|
public function test_rejects_context_without_live_component_data(): void
|
|
{
|
|
$context = AttributeExecutionContext::forMethod(
|
|
container: $this->container,
|
|
className: ClassName::create('TestComponent'),
|
|
methodName: MethodName::create('testMethod')
|
|
);
|
|
$actionAttribute = new Action();
|
|
|
|
$this->expectException(\RuntimeException::class);
|
|
$this->expectExceptionMessage('LiveComponentContextData');
|
|
|
|
$this->guard->check($context, $actionAttribute);
|
|
}
|
|
|
|
private function createComponent(): LiveComponentContract
|
|
{
|
|
return new TestComponent(
|
|
ComponentId::create('test', 'demo'),
|
|
CounterState::empty()
|
|
);
|
|
}
|
|
|
|
private function createContext(LiveComponentContract $component, ActionParameters $params): AttributeExecutionContext
|
|
{
|
|
return LiveComponentContextHelper::createForAction(
|
|
container: $this->container,
|
|
componentClass: ClassName::create($component::class),
|
|
actionMethod: MethodName::create('testAction'),
|
|
componentId: $component->id,
|
|
actionParameters: $params,
|
|
component: $component
|
|
);
|
|
}
|
|
}
|
|
|