Enable Discovery debug logging for production troubleshooting

- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -0,0 +1,281 @@
<?php
declare(strict_types=1);
use App\Framework\DI\ContainerCompiler;
use App\Framework\DI\DefaultContainer;
use App\Framework\DI\DependencyResolver;
use App\Framework\Reflection\CachedReflectionProvider;
beforeEach(function () {
$this->tempDir = sys_get_temp_dir() . '/container-compiler-test-' . uniqid();
mkdir($this->tempDir, 0755, true);
$this->container = new DefaultContainer();
$this->reflectionProvider = new CachedReflectionProvider();
$this->dependencyResolver = new DependencyResolver($this->reflectionProvider, $this->container);
$this->compiler = new ContainerCompiler($this->reflectionProvider, $this->dependencyResolver);
$this->compiledPath = $this->tempDir . '/compiled-container.php';
});
afterEach(function () {
// Clean up test directory
if (is_dir($this->tempDir)) {
array_map('unlink', glob($this->tempDir . '/*'));
rmdir($this->tempDir);
}
});
// Test classes
class ContainerCompilerTestSimpleService
{
public function getName(): string
{
return 'simple';
}
}
class ContainerCompilerTestServiceWithDependency
{
public function __construct(private ContainerCompilerTestSimpleService $service)
{
}
public function getServiceName(): string
{
return $this->service->getName();
}
}
interface ContainerCompilerTestServiceInterface
{
public function getValue(): string;
}
class ContainerCompilerTestConcreteService implements ContainerCompilerTestServiceInterface
{
public function getValue(): string
{
return 'concrete';
}
}
test('compiles container with simple binding', function () {
// Arrange
$this->container->bind(ContainerCompilerTestSimpleService::class, ContainerCompilerTestSimpleService::class);
// Act
$this->compiler->compile($this->container, $this->compiledPath);
// Assert
expect(file_exists($this->compiledPath))->toBeTrue();
$content = file_get_contents($this->compiledPath);
expect($content)->toContain('class CompiledContainer implements Container');
expect($content)->toContain('createContainerCompilerTestSimpleService()');
});
test('compiles container with dependency injection', function () {
// Arrange
$this->container->bind(ContainerCompilerTestSimpleService::class, ContainerCompilerTestSimpleService::class);
$this->container->bind(ContainerCompilerTestServiceWithDependency::class, ContainerCompilerTestServiceWithDependency::class);
// Act
$this->compiler->compile($this->container, $this->compiledPath);
// Assert
expect(file_exists($this->compiledPath))->toBeTrue();
$content = file_get_contents($this->compiledPath);
expect($content)->toContain('$this->get(\'ContainerCompilerTestSimpleService\')');
});
test('compiles container with singletons', function () {
// Arrange
$this->container->singleton(ContainerCompilerTestSimpleService::class, ContainerCompilerTestSimpleService::class);
// Act
$this->compiler->compile($this->container, $this->compiledPath);
// Assert
expect(file_exists($this->compiledPath))->toBeTrue();
$content = file_get_contents($this->compiledPath);
expect($content)->toContain('$this->singletons[\'ContainerCompilerTestSimpleService\'] = true');
});
test('loads compiled container successfully', function () {
// Arrange
$this->container->bind(ContainerCompilerTestSimpleService::class, ContainerCompilerTestSimpleService::class);
$this->compiler->compile($this->container, $this->compiledPath);
// Act
$compiledContainer = ContainerCompiler::load($this->compiledPath);
// Assert
expect($compiledContainer)->toBeInstanceOf(\App\Framework\DI\Container::class);
expect($compiledContainer->has(ContainerCompilerTestSimpleService::class))->toBeTrue();
$instance = $compiledContainer->get(ContainerCompilerTestSimpleService::class);
expect($instance)->toBeInstanceOf(ContainerCompilerTestSimpleService::class);
expect($instance->getName())->toBe('simple');
});
test('compiled container resolves dependencies correctly', function () {
// Arrange
$this->container->bind(ContainerCompilerTestSimpleService::class, ContainerCompilerTestSimpleService::class);
$this->container->bind(ContainerCompilerTestServiceWithDependency::class, ContainerCompilerTestServiceWithDependency::class);
$this->compiler->compile($this->container, $this->compiledPath);
// Act
$compiledContainer = ContainerCompiler::load($this->compiledPath);
$instance = $compiledContainer->get(ContainerCompilerTestServiceWithDependency::class);
// Assert
expect($instance)->toBeInstanceOf(ContainerCompilerTestServiceWithDependency::class);
expect($instance->getServiceName())->toBe('simple');
});
test('compiled container handles singletons correctly', function () {
// Arrange
$this->container->singleton(ContainerCompilerTestSimpleService::class, ContainerCompilerTestSimpleService::class);
$this->compiler->compile($this->container, $this->compiledPath);
// Act
$compiledContainer = ContainerCompiler::load($this->compiledPath);
$instance1 = $compiledContainer->get(ContainerCompilerTestSimpleService::class);
$instance2 = $compiledContainer->get(ContainerCompilerTestSimpleService::class);
// Assert
expect($instance1)->toBe($instance2);
});
test('validates compiled container hash correctly', function () {
// Arrange
$this->container->bind(ContainerCompilerTestSimpleService::class, ContainerCompilerTestSimpleService::class);
$this->compiler->compile($this->container, $this->compiledPath);
// Act & Assert - should be valid initially
expect($this->compiler->isCompiledContainerValid($this->container, $this->compiledPath))->toBeTrue();
// Add new binding to change container state
$this->container->bind(ContainerCompilerTestServiceWithDependency::class, ContainerCompilerTestServiceWithDependency::class);
// Should now be invalid due to hash mismatch
expect($this->compiler->isCompiledContainerValid($this->container, $this->compiledPath))->toBeFalse();
});
test('returns false for non-existent compiled container', function () {
// Arrange
$nonExistentPath = $this->tempDir . '/non-existent.php';
// Act & Assert
expect($this->compiler->isCompiledContainerValid($this->container, $nonExistentPath))->toBeFalse();
});
test('creates directory if it does not exist', function () {
// Arrange
$nestedPath = $this->tempDir . '/nested/deep/compiled-container.php';
$this->container->bind(ContainerCompilerTestSimpleService::class, ContainerCompilerTestSimpleService::class);
// Act
$this->compiler->compile($this->container, $nestedPath);
// Assert
expect(file_exists($nestedPath))->toBeTrue();
expect(is_dir(dirname($nestedPath)))->toBeTrue();
});
test('throws exception when loading non-existent compiled container', function () {
// Arrange
$nonExistentPath = $this->tempDir . '/non-existent.php';
// Act & Assert
expect(fn () => ContainerCompiler::load($nonExistentPath))
->toThrow(RuntimeException::class, 'Compiled container not found');
});
test('compiled container throws exception for runtime binding', function () {
// Arrange
$this->container->bind(ContainerCompilerTestSimpleService::class, ContainerCompilerTestSimpleService::class);
$this->compiler->compile($this->container, $this->compiledPath);
$compiledContainer = ContainerCompiler::load($this->compiledPath);
// Act & Assert
expect(fn () => $compiledContainer->bind('NewClass', 'AnotherClass'))
->toThrow(RuntimeException::class, 'Cannot bind to compiled container');
});
test('compiled container throws exception for runtime singleton registration', function () {
// Arrange
$this->container->bind(ContainerCompilerTestSimpleService::class, ContainerCompilerTestSimpleService::class);
$this->compiler->compile($this->container, $this->compiledPath);
$compiledContainer = ContainerCompiler::load($this->compiledPath);
// Act & Assert
expect(fn () => $compiledContainer->singleton('NewClass', 'AnotherClass'))
->toThrow(RuntimeException::class, 'Cannot add singletons to compiled container');
});
test('compiled container allows runtime instance registration', function () {
// Arrange
$this->container->bind(ContainerCompilerTestSimpleService::class, ContainerCompilerTestSimpleService::class);
$this->compiler->compile($this->container, $this->compiledPath);
$compiledContainer = ContainerCompiler::load($this->compiledPath);
$customInstance = new ContainerCompilerTestSimpleService();
// Act
$compiledContainer->instance(ContainerCompilerTestSimpleService::class, $customInstance);
$retrievedInstance = $compiledContainer->get(ContainerCompilerTestSimpleService::class);
// Assert
expect($retrievedInstance)->toBe($customInstance);
});
test('gets default compiled container path', function () {
// Act
$path = ContainerCompiler::getCompiledContainerPath();
// Assert
expect($path)->toContain('compiled-container.php');
expect(is_dir(dirname($path)))->toBeTrue();
});
test('gets custom compiled container path', function () {
// Arrange
$customCacheDir = $this->tempDir . '/custom-cache';
// Act
$path = ContainerCompiler::getCompiledContainerPath($customCacheDir);
// Assert
expect($path)->toBe($customCacheDir . '/compiled-container.php');
expect(is_dir($customCacheDir))->toBeTrue();
});
test('compiled container handles unknown class gracefully', function () {
// Arrange
$this->container->bind(ContainerCompilerTestSimpleService::class, ContainerCompilerTestSimpleService::class);
$this->compiler->compile($this->container, $this->compiledPath);
$compiledContainer = ContainerCompiler::load($this->compiledPath);
// Act & Assert
expect(fn () => $compiledContainer->get('UnknownClass'))
->toThrow(InvalidArgumentException::class, 'Class UnknownClass is not bound in the container');
});
test('generated code contains proper metadata', function () {
// Arrange
$this->container->bind(ContainerCompilerTestSimpleService::class, ContainerCompilerTestSimpleService::class);
// Act
$this->compiler->compile($this->container, $this->compiledPath);
// Assert
$content = file_get_contents($this->compiledPath);
expect($content)->toContain('Generated:');
expect($content)->toContain('Hash:');
expect($content)->toContain('WARNING: This file is auto-generated');
expect($content)->toMatch('/Hash: [a-f0-9]{64}/');
});