refactor(config): add EnumResolver for cache-backed enum resolution and extend DockerSecretsResolver with caching

- Introduce `EnumResolver` to centralize and cache enum value conversions.
- Enhance `DockerSecretsResolver` with result caching to avoid redundant file reads and improve performance.
- Update `Environment` to integrate `EnumResolver` for enriched enum resolution support and improved maintainability.
- Adjust unit tests to validate caching mechanisms and error handling improvements.
This commit is contained in:
2025-11-03 23:47:08 +01:00
parent 2a0c797051
commit a1242f776e
6 changed files with 332 additions and 25 deletions

View File

@@ -583,6 +583,89 @@ describe('Environment', function () {
unlink($dbPasswordPath);
unlink($apiKeyPath);
});
it('uses Docker secret when variable is set to empty string', function () {
// Create temporary Docker secret file
$secretPath = '/tmp/docker_secret_test';
file_put_contents($secretPath, 'secret_from_file');
$env = new Environment([
'REDIS_PASSWORD' => '', // Empty string
'REDIS_PASSWORD_FILE' => $secretPath,
], $this->dockerSecretsResolver);
$value = $env->get('REDIS_PASSWORD');
// Docker Secret should override empty string
expect($value)->toBe('secret_from_file');
// Cleanup
unlink($secretPath);
});
it('returns empty string when variable is empty and no Docker secret exists', function () {
$env = new Environment([
'REDIS_PASSWORD' => '', // Empty string, no FILE
], $this->dockerSecretsResolver);
$value = $env->get('REDIS_PASSWORD');
// Empty string should be returned when explicitly set
expect($value)->toBe('');
});
it('caches Docker secret resolution results', function () {
// Create temporary Docker secret file
$secretPath = '/tmp/docker_secret_test_caching';
file_put_contents($secretPath, 'cached_secret_value');
$env = new Environment([
'DB_PASSWORD_FILE' => $secretPath,
], $this->dockerSecretsResolver);
// First call - should read from file
$value1 = $env->get('DB_PASSWORD');
expect($value1)->toBe('cached_secret_value');
// Modify file content (should not affect cached value)
file_put_contents($secretPath, 'modified_secret_value');
// Second call - should use cache, not re-read file
$value2 = $env->get('DB_PASSWORD');
expect($value2)->toBe('cached_secret_value');
// Cleanup
unlink($secretPath);
});
it('caches enum conversion results', function () {
// Create a test enum
if (!enum_exists('TestEnum')) {
eval('enum TestEnum: string { case FOO = "foo"; case BAR = "bar"; }');
}
$env = new Environment([
'APP_ENV' => 'foo',
], $this->dockerSecretsResolver);
$default = TestEnum::BAR;
// First call - should convert
$enum1 = $env->getEnum('APP_ENV', TestEnum::class, $default);
expect($enum1)->toBe(TestEnum::FOO);
// Second call to same instance should use cache
$enum2 = $env->getEnum('APP_ENV', TestEnum::class, $default);
expect($enum2)->toBe(TestEnum::FOO);
expect($enum1)->toBe($enum2);
// Different enum class should have different cache entry
if (!enum_exists('AnotherTestEnum')) {
eval('enum AnotherTestEnum: string { case FOO = "foo"; case BAR = "bar"; }');
}
$enum3 = $env->getEnum('APP_ENV', AnotherTestEnum::class, AnotherTestEnum::BAR);
expect($enum3)->toBe(AnotherTestEnum::FOO);
});
});
describe('Edge Cases', function () {