- Move 12 markdown files from root to docs/ subdirectories - Organize documentation by category: • docs/troubleshooting/ (1 file) - Technical troubleshooting guides • docs/deployment/ (4 files) - Deployment and security documentation • docs/guides/ (3 files) - Feature-specific guides • docs/planning/ (4 files) - Planning and improvement proposals Root directory cleanup: - Reduced from 16 to 4 markdown files in root - Only essential project files remain: • CLAUDE.md (AI instructions) • README.md (Main project readme) • CLEANUP_PLAN.md (Current cleanup plan) • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements) This improves: ✅ Documentation discoverability ✅ Logical organization by purpose ✅ Clean root directory ✅ Better maintainability
181 lines
6.7 KiB
PHP
181 lines
6.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Framework\Health\ValueObjects;
|
|
|
|
use App\Framework\Health\ValueObjects\HealthDetails;
|
|
use InvalidArgumentException;
|
|
|
|
describe('HealthDetails Value Object', function () {
|
|
it('can be created empty', function () {
|
|
$details = HealthDetails::empty();
|
|
|
|
expect($details->isEmpty())->toBeTrue();
|
|
expect($details->count())->toBe(0);
|
|
expect($details->toArray())->toBe([]);
|
|
});
|
|
|
|
it('can be created from array', function () {
|
|
$data = ['host' => 'localhost', 'port' => 3306];
|
|
$details = HealthDetails::fromArray($data);
|
|
|
|
expect($details->isEmpty())->toBeFalse();
|
|
expect($details->count())->toBe(2);
|
|
expect($details->get('host'))->toBe('localhost');
|
|
expect($details->get('port'))->toBe(3306);
|
|
});
|
|
|
|
it('can add and remove details immutably', function () {
|
|
$details = HealthDetails::empty();
|
|
$newDetails = $details->with('key', 'value');
|
|
|
|
expect($details->has('key'))->toBeFalse(); // Original unchanged
|
|
expect($newDetails->has('key'))->toBeTrue();
|
|
expect($newDetails->get('key'))->toBe('value');
|
|
|
|
$withoutKey = $newDetails->without('key');
|
|
expect($withoutKey->has('key'))->toBeFalse();
|
|
expect($newDetails->has('key'))->toBeTrue(); // Original unchanged
|
|
});
|
|
|
|
it('gets values with defaults', function () {
|
|
$details = HealthDetails::fromArray(['existing' => 'value']);
|
|
|
|
expect($details->get('existing'))->toBe('value');
|
|
expect($details->get('missing'))->toBeNull();
|
|
expect($details->get('missing', 'default'))->toBe('default');
|
|
});
|
|
|
|
it('creates database details correctly', function () {
|
|
$details = HealthDetails::forDatabase('localhost', 3306, 'testdb', 25.5, 10);
|
|
|
|
expect($details->get('host'))->toBe('localhost');
|
|
expect($details->get('port'))->toBe(3306);
|
|
expect($details->get('database'))->toBe('testdb');
|
|
expect($details->get('connection_time_ms'))->toBe(25.5);
|
|
expect($details->get('active_connections'))->toBe(10);
|
|
});
|
|
|
|
it('creates cache details correctly', function () {
|
|
$details = HealthDetails::forCache('redis', 95, 1000, '128MB');
|
|
|
|
expect($details->get('driver'))->toBe('redis');
|
|
expect($details->get('hit_rate_percent'))->toBe(95);
|
|
expect($details->get('total_keys'))->toBe(1000);
|
|
expect($details->get('memory_usage'))->toBe('128MB');
|
|
});
|
|
|
|
it('creates disk details correctly', function () {
|
|
$details = HealthDetails::forDisk('/var/log', '100GB', '25GB', 75.0);
|
|
|
|
expect($details->get('path'))->toBe('/var/log');
|
|
expect($details->get('total_space'))->toBe('100GB');
|
|
expect($details->get('free_space'))->toBe('25GB');
|
|
expect($details->get('usage_percent'))->toBe(75.0);
|
|
});
|
|
|
|
it('creates system details correctly', function () {
|
|
$details = HealthDetails::forSystem(45.2, '8GB/16GB', 1.5, '5 days');
|
|
|
|
expect($details->get('cpu_usage_percent'))->toBe(45.2);
|
|
expect($details->get('memory_usage'))->toBe('8GB/16GB');
|
|
expect($details->get('load_average'))->toBe(1.5);
|
|
expect($details->get('uptime'))->toBe('5 days');
|
|
});
|
|
|
|
it('creates API details correctly', function () {
|
|
$details = HealthDetails::forApi('/health', 200, 150.5, 'v1.2.3');
|
|
|
|
expect($details->get('endpoint'))->toBe('/health');
|
|
expect($details->get('status_code'))->toBe(200);
|
|
expect($details->get('response_time_ms'))->toBe(150.5);
|
|
expect($details->get('version'))->toBe('v1.2.3');
|
|
});
|
|
|
|
it('creates error details correctly', function () {
|
|
$exception = new \RuntimeException('Test error', 500);
|
|
$details = HealthDetails::forError($exception);
|
|
|
|
expect($details->get('error_type'))->toBe('RuntimeException');
|
|
expect($details->get('error_message'))->toBe('Test error');
|
|
expect($details->get('error_code'))->toBe(500);
|
|
expect($details->get('error_file'))->toBeString();
|
|
expect($details->get('error_line'))->toBeInt();
|
|
});
|
|
|
|
it('can merge details', function () {
|
|
$details1 = HealthDetails::fromArray(['key1' => 'value1']);
|
|
$details2 = HealthDetails::fromArray(['key2' => 'value2']);
|
|
|
|
$merged = $details1->merge($details2);
|
|
|
|
expect($merged->get('key1'))->toBe('value1');
|
|
expect($merged->get('key2'))->toBe('value2');
|
|
expect($merged->count())->toBe(2);
|
|
});
|
|
|
|
it('identifies sensitive keys', function () {
|
|
$details = HealthDetails::fromArray([
|
|
'username' => 'john',
|
|
'password' => 'secret123',
|
|
'api_key' => 'abc123',
|
|
'database_token' => 'xyz789',
|
|
'normal_field' => 'value',
|
|
]);
|
|
|
|
$sensitiveKeys = $details->getSensitiveKeys();
|
|
|
|
expect($sensitiveKeys)->toContain('password');
|
|
expect($sensitiveKeys)->toContain('api_key');
|
|
expect($sensitiveKeys)->toContain('database_token');
|
|
expect($sensitiveKeys)->not->toContain('username');
|
|
expect($sensitiveKeys)->not->toContain('normal_field');
|
|
});
|
|
|
|
it('sanitizes sensitive data', function () {
|
|
$details = HealthDetails::fromArray([
|
|
'username' => 'john',
|
|
'password' => 'secret123',
|
|
'normal_field' => 'value',
|
|
]);
|
|
|
|
$sanitized = $details->toSanitizedArray();
|
|
|
|
expect($sanitized['username'])->toBe('john');
|
|
expect($sanitized['password'])->toBe('[REDACTED]');
|
|
expect($sanitized['normal_field'])->toBe('value');
|
|
});
|
|
|
|
it('throws exception for non-string keys', function () {
|
|
expect(fn () => HealthDetails::fromArray([123 => 'value']))->toThrow(InvalidArgumentException::class);
|
|
});
|
|
|
|
it('throws exception for empty keys', function () {
|
|
expect(fn () => HealthDetails::fromArray(['' => 'value']))->toThrow(InvalidArgumentException::class);
|
|
expect(fn () => HealthDetails::fromArray([' ' => 'value']))->toThrow(InvalidArgumentException::class);
|
|
});
|
|
|
|
it('throws exception for resource values', function () {
|
|
$resource = fopen('php://memory', 'r');
|
|
expect(fn () => HealthDetails::fromArray(['resource' => $resource]))->toThrow(InvalidArgumentException::class);
|
|
fclose($resource);
|
|
});
|
|
|
|
it('allows scalar and null values', function () {
|
|
$details = HealthDetails::fromArray([
|
|
'string' => 'text',
|
|
'int' => 123,
|
|
'float' => 12.34,
|
|
'bool' => true,
|
|
'null' => null,
|
|
]);
|
|
|
|
expect($details->get('string'))->toBe('text');
|
|
expect($details->get('int'))->toBe(123);
|
|
expect($details->get('float'))->toBe(12.34);
|
|
expect($details->get('bool'))->toBeTrue();
|
|
expect($details->get('null'))->toBeNull();
|
|
});
|
|
});
|