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

@@ -2,18 +2,144 @@
declare(strict_types=1);
use App\Framework\Admin\AdminApiHandler;
use App\Framework\Admin\AdminPageRenderer;
use App\Framework\Admin\Factories\AdminFormFactory;
use App\Framework\Admin\Factories\AdminTableFactory;
use App\Framework\Admin\Factories\RepositoryAdapterFactory;
use App\Framework\Admin\Services\CrudService;
use App\Framework\Admin\ValueObjects\CrudConfig;
use App\Framework\Http\HttpRequest;
use App\Framework\Core\PathProvider;
use App\Framework\DI\DefaultContainer;
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\Http\Request;
use App\Framework\Http\Responses\Redirect;
use App\Framework\Http\Responses\ViewResult;
use App\Framework\View\TemplateRenderer;
use App\Framework\LiveComponents\ComponentCacheManager;
use App\Framework\LiveComponents\ComponentMetadataCache;
use App\Framework\LiveComponents\ComponentRegistry;
use App\Framework\LiveComponents\LiveComponentHandler;
use App\Framework\LiveComponents\Performance\NestedPerformanceTracker;
use App\Framework\Router\Result\ViewResult;
use App\Framework\View\Dom\Renderer\HtmlRenderer;
use App\Framework\View\LiveComponentRenderer;
use App\Framework\View\Loading\TemplateLoader;
use App\Framework\View\Table\Table;
use App\Framework\View\TemplateProcessor;
use App\Framework\Cache\Driver\NullCache;
use App\Framework\Cache\GeneralCache;
use App\Framework\Serializer\Serializer;
use App\Framework\DateTime\SystemClock;
use App\Framework\Http\Session\Session;
use App\Framework\Http\Session\SessionId;
use App\Framework\Random\SecureRandomGenerator;
use App\Framework\Security\CsrfTokenGenerator;
beforeEach(function () {
$this->renderer = Mockery::mock(TemplateRenderer::class);
// Create minimal real instances for final classes
// Since many classes are final, we create real instances with minimal dependencies
$container = new DefaultContainer();
// Create DiscoveryRegistry
$discoveryRegistry = new DiscoveryRegistry(
attributes: new AttributeRegistry(),
interfaces: new InterfaceRegistry([]),
templates: new TemplateRegistry([])
);
// Create TemplateLoader for LiveComponentRenderer
$pathProvider = new PathProvider(__DIR__ . '/../../../../');
$nullCacheDriver = new NullCache();
$serializer = Mockery::mock(Serializer::class);
$serializer->shouldReceive('serialize')->andReturnUsing(fn($data) => serialize($data));
$serializer->shouldReceive('unserialize')->andReturnUsing(fn($data) => unserialize($data));
$cache = new GeneralCache($nullCacheDriver, $serializer);
$templateLoader = new TemplateLoader(
pathProvider: $pathProvider,
cache: $cache,
discoveryRegistry: null,
templates: [],
templatePath: '/src/Framework/View/templates',
cacheEnabled: false
);
// Create TemplateProcessor
$templateProcessor = new TemplateProcessor(
astTransformers: [],
stringProcessors: [],
container: $container,
chainOptimizer: null,
compiledTemplateCache: null,
performanceTracker: null
);
// Create real Session instance
$session = Session::fromArray(
SessionId::fromString(str_repeat('a', 32)),
new SystemClock(),
new CsrfTokenGenerator(new SecureRandomGenerator()),
[]
);
// Create LiveComponentRenderer
$liveComponentRenderer = new LiveComponentRenderer(
templateLoader: $templateLoader,
templateProcessor: $templateProcessor,
session: $session
);
// Create real instances for final classes with minimal dependencies
$cacheKeyBuilder = new \App\Framework\LiveComponents\Caching\CacheKeyBuilder();
$cacheManager = new ComponentCacheManager(
cache: $cache,
cacheKeyBuilder: $cacheKeyBuilder
);
$eventDispatcher = new \App\Framework\LiveComponents\ComponentEventDispatcher();
$handler = new LiveComponentHandler(
eventDispatcher: $eventDispatcher,
session: $session
);
$metadataCompiler = new \App\Framework\LiveComponents\Performance\ComponentMetadataCompiler();
$metadataCache = new ComponentMetadataCache(
cache: $cache,
compiler: $metadataCompiler
);
$highResClock = new \App\Framework\DateTime\HighResolutionClock();
$memoryMonitor = new \App\Framework\Performance\MemoryMonitor();
$performanceTracker = new NestedPerformanceTracker(
clock: new SystemClock(),
highResClock: $highResClock,
memoryMonitor: $memoryMonitor
);
// Create real ComponentRegistry
$componentRegistry = new ComponentRegistry(
container: $container,
discoveryRegistry: $discoveryRegistry,
renderer: $liveComponentRenderer,
cacheManager: $cacheManager,
handler: $handler,
metadataCache: $metadataCache,
performanceTracker: $performanceTracker
);
$this->pageRenderer = new AdminPageRenderer($componentRegistry);
$this->formFactory = Mockery::mock(AdminFormFactory::class);
$this->service = new CrudService($this->renderer, $this->formFactory);
$this->tableFactory = Mockery::mock(AdminTableFactory::class);
$apiHandler = new AdminApiHandler();
$adapterFactory = new RepositoryAdapterFactory();
$this->service = new CrudService(
$this->pageRenderer,
$this->formFactory,
$this->tableFactory,
$apiHandler,
$adapterFactory
);
$this->config = CrudConfig::forResource(
resource: 'campaigns',
@@ -31,41 +157,54 @@ afterEach(function () {
describe('CrudService', function () {
describe('renderIndex', function () {
it('renders index view with items and pagination', function () {
it('renders index view with items using AdminPageRenderer', function () {
$items = [
['id' => '1', 'name' => 'Campaign 1', 'status' => 'active'],
['id' => '2', 'name' => 'Campaign 2', 'status' => 'draft'],
];
$pagination = [
'current_page' => 1,
'total_pages' => 5,
'per_page' => 10,
];
$request = Mockery::mock(HttpRequest::class);
$request = Mockery::mock(Request::class);
$request->shouldReceive('uri')->andReturn('/admin/campaigns');
$mockTable = Mockery::mock(Table::class);
$mockTable->shouldReceive('render')->andReturn('<table>...</table>');
$this->tableFactory->shouldReceive('create')
->once()
->andReturn($mockTable);
$result = $this->service->renderIndex(
$this->config,
$items,
$request,
$pagination
$request
);
expect($result)->toBeInstanceOf(ViewResult::class);
expect($result->template)->toBe('crud-index');
expect($result->data['items'])->toBe($items);
expect($result->data['pagination'])->toBe($pagination);
expect($result->data['resource'])->toBe('campaigns');
expect($result->data['createUrl'])->toBe('/admin/campaigns/create');
expect($result->template)->toBe('admin-index');
});
it('includes create action when canCreate is true', function () {
$items = [];
$request = Mockery::mock(Request::class);
$request->shouldReceive('uri')->andReturn('/admin/campaigns');
$mockTable = Mockery::mock(Table::class);
$mockTable->shouldReceive('render')->andReturn('');
$this->tableFactory->shouldReceive('create')->andReturn($mockTable);
$result = $this->service->renderIndex($this->config, $items, $request);
expect($result)->toBeInstanceOf(ViewResult::class);
expect($result->data['actions'])->toBeArray();
expect($result->data['actions'][0]['label'])->toBe('Create Campaign');
});
});
describe('renderCreate', function () {
it('renders create form with default configuration', function () {
it('renders create form using AdminPageRenderer', function () {
$formFields = [
['type' => 'text', 'name' => 'name', 'label' => 'Name'],
'name' => ['type' => 'text', 'label' => 'Name'],
];
$mockForm = Mockery::mock();
@@ -82,13 +221,11 @@ describe('CrudService', function () {
);
expect($result)->toBeInstanceOf(ViewResult::class);
expect($result->template)->toBe('crud-create');
expect($result->template)->toBe('admin-form');
expect($result->data['title'])->toBe('Create Campaign');
expect($result->data['formId'])->toBe('campaign-form');
expect($result->data['backUrl'])->toBe('/admin/campaigns');
});
it('renders create form with help text', function () {
it('renders create form with help text as subtitle', function () {
$formFields = [];
$helpText = 'Fill in the campaign details carefully.';
@@ -105,14 +242,15 @@ describe('CrudService', function () {
$helpText
);
expect($result->data['helpText'])->toBe($helpText);
expect($result)->toBeInstanceOf(ViewResult::class);
expect($result->data['subtitle'])->toBe($helpText);
});
});
describe('renderEdit', function () {
it('renders edit form with item data and metadata', function () {
it('renders edit form using AdminPageRenderer', function () {
$formFields = [
['type' => 'text', 'name' => 'name', 'label' => 'Name'],
'name' => ['type' => 'text', 'label' => 'Name'],
];
$itemData = [
@@ -144,15 +282,13 @@ describe('CrudService', function () {
);
expect($result)->toBeInstanceOf(ViewResult::class);
expect($result->template)->toBe('crud-edit');
expect($result->template)->toBe('admin-form');
expect($result->data['title'])->toBe('Edit Campaign');
expect($result->data['metadata'])->toBe($metadata);
expect($result->data['deleteUrl'])->toBe('/admin/campaigns/delete/123');
});
});
describe('renderShow', function () {
it('renders show view with fields and metadata', function () {
it('renders show view using AdminPageRenderer', function () {
$fields = [
['label' => 'Name', 'value' => 'Test Campaign', 'type' => 'text'],
['label' => 'Status', 'value' => 'Active', 'type' => 'badge', 'color' => 'success'],
@@ -171,7 +307,7 @@ describe('CrudService', function () {
);
expect($result)->toBeInstanceOf(ViewResult::class);
expect($result->template)->toBe('crud-show');
expect($result->template)->toBe('admin-show');
expect($result->data['fields'])->toBe($fields);
expect($result->data['metadata'])->toBe($metadata);
expect($result->data['editUrl'])->toBe('/admin/campaigns/edit/123');
@@ -180,7 +316,7 @@ describe('CrudService', function () {
describe('redirectAfterCreate', function () {
it('redirects to index after successful create', function () {
$request = Mockery::mock(HttpRequest::class);
$request = Mockery::mock(Request::class);
$request->parsedBody = Mockery::mock();
$request->parsedBody->shouldReceive('get')
->with('action')
@@ -197,7 +333,7 @@ describe('CrudService', function () {
});
it('redirects to create form when save-and-continue is requested', function () {
$request = Mockery::mock(HttpRequest::class);
$request = Mockery::mock(Request::class);
$request->parsedBody = Mockery::mock();
$request->parsedBody->shouldReceive('get')
->with('action')
@@ -215,7 +351,7 @@ describe('CrudService', function () {
describe('redirectAfterUpdate', function () {
it('redirects to index after successful update', function () {
$request = Mockery::mock(HttpRequest::class);
$request = Mockery::mock(Request::class);
$request->parsedBody = Mockery::mock();
$request->parsedBody->shouldReceive('get')
->with('action')
@@ -231,7 +367,7 @@ describe('CrudService', function () {
});
it('redirects to show view when save-and-view is requested', function () {
$request = Mockery::mock(HttpRequest::class);
$request = Mockery::mock(Request::class);
$request->parsedBody = Mockery::mock();
$request->parsedBody->shouldReceive('get')
->with('action')