- 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
216 lines
7.3 KiB
PHP
216 lines
7.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Framework\Logging\ValueObjects;
|
|
|
|
use App\Framework\Logging\ValueObjects\LogContext;
|
|
use App\Framework\Logging\ValueObjects\RequestContext;
|
|
use App\Framework\Logging\ValueObjects\UserContext;
|
|
use App\Framework\Random\SecureRandomGenerator;
|
|
use App\Framework\Tracing\TraceContext;
|
|
|
|
describe('LogContext', function () {
|
|
it('can be created empty', function () {
|
|
$context = LogContext::empty();
|
|
|
|
expect($context->structured)->toBe([]);
|
|
expect($context->tags)->toBe([]);
|
|
expect($context->trace)->toBeNull();
|
|
expect($context->user)->toBeNull();
|
|
expect($context->request)->toBeNull();
|
|
expect($context->metadata)->toBe([]);
|
|
});
|
|
|
|
it('can be created with structured data', function () {
|
|
$data = ['user_id' => 123, 'action' => 'login'];
|
|
$context = LogContext::withData($data);
|
|
|
|
expect($context->structured)->toBe($data);
|
|
expect($context->hasStructuredData())->toBeTrue();
|
|
});
|
|
|
|
it('can be created with tags', function () {
|
|
$context = LogContext::withTags('auth', 'user-action');
|
|
|
|
expect($context->tags)->toBe(['auth', 'user-action']);
|
|
expect($context->hasTags())->toBeTrue();
|
|
expect($context->hasTag('auth'))->toBeTrue();
|
|
expect($context->hasTag('missing'))->toBeFalse();
|
|
});
|
|
|
|
it('can add structured data immutably', function () {
|
|
$original = LogContext::withData(['key1' => 'value1']);
|
|
$modified = $original->addData('key2', 'value2');
|
|
|
|
expect($original->structured)->toBe(['key1' => 'value1']);
|
|
expect($modified->structured)->toBe(['key1' => 'value1', 'key2' => 'value2']);
|
|
});
|
|
|
|
it('can merge structured data immutably', function () {
|
|
$original = LogContext::withData(['key1' => 'value1']);
|
|
$modified = $original->mergeData(['key2' => 'value2', 'key3' => 'value3']);
|
|
|
|
expect($original->structured)->toBe(['key1' => 'value1']);
|
|
expect($modified->structured)->toBe([
|
|
'key1' => 'value1',
|
|
'key2' => 'value2',
|
|
'key3' => 'value3',
|
|
]);
|
|
});
|
|
|
|
it('can add tags immutably', function () {
|
|
$original = LogContext::withTags('tag1');
|
|
$modified = $original->addTags('tag2', 'tag3');
|
|
|
|
expect($original->tags)->toBe(['tag1']);
|
|
expect($modified->tags)->toBe(['tag1', 'tag2', 'tag3']);
|
|
});
|
|
|
|
it('removes duplicate tags when adding', function () {
|
|
$original = LogContext::withTags('tag1', 'tag2');
|
|
$modified = $original->addTags('tag2', 'tag3');
|
|
|
|
expect($modified->tags)->toBe(['tag1', 'tag2', 'tag3']);
|
|
});
|
|
|
|
it('can add user context immutably', function () {
|
|
$userContext = UserContext::authenticated('123', 'john');
|
|
$original = LogContext::empty();
|
|
$modified = $original->withUser($userContext);
|
|
|
|
expect($original->user)->toBeNull();
|
|
expect($modified->user)->toBe($userContext);
|
|
});
|
|
|
|
it('can add request context immutably', function () {
|
|
$requestContext = RequestContext::empty();
|
|
$original = LogContext::empty();
|
|
$modified = $original->withRequest($requestContext);
|
|
|
|
expect($original->request)->toBeNull();
|
|
expect($modified->request)->toBe($requestContext);
|
|
});
|
|
|
|
it('can add trace context immutably', function () {
|
|
$traceContext = TraceContext::start(new SecureRandomGenerator());
|
|
$original = LogContext::empty();
|
|
$modified = $original->withTrace($traceContext);
|
|
|
|
expect($original->trace)->toBeNull();
|
|
expect($modified->trace)->toBe($traceContext);
|
|
});
|
|
|
|
it('can add metadata immutably', function () {
|
|
$original = LogContext::empty();
|
|
$modified = $original->addMetadata('source', 'test');
|
|
|
|
expect($original->metadata)->toBe([]);
|
|
expect($modified->metadata)->toBe(['source' => 'test']);
|
|
});
|
|
|
|
it('can merge two contexts', function () {
|
|
$context1 = LogContext::withData(['key1' => 'value1'])
|
|
->addTags('tag1')
|
|
->addMetadata('meta1', 'value1');
|
|
|
|
$context2 = LogContext::withData(['key2' => 'value2'])
|
|
->addTags('tag2')
|
|
->addMetadata('meta2', 'value2');
|
|
|
|
$merged = $context1->merge($context2);
|
|
|
|
expect($merged->structured)->toBe(['key1' => 'value1', 'key2' => 'value2']);
|
|
expect($merged->tags)->toBe(['tag1', 'tag2']);
|
|
expect($merged->metadata)->toBe(['meta1' => 'value1', 'meta2' => 'value2']);
|
|
});
|
|
|
|
it('prioritizes second context in merge for trace, user, request', function () {
|
|
$user1 = UserContext::authenticated('123');
|
|
$user2 = UserContext::authenticated('456');
|
|
$request1 = RequestContext::empty();
|
|
$request2 = RequestContext::empty();
|
|
$trace1 = TraceContext::start(new SecureRandomGenerator());
|
|
$trace2 = TraceContext::start(new SecureRandomGenerator());
|
|
|
|
$context1 = LogContext::empty()
|
|
->withUser($user1)
|
|
->withRequest($request1)
|
|
->withTrace($trace1);
|
|
|
|
$context2 = LogContext::empty()
|
|
->withUser($user2)
|
|
->withRequest($request2)
|
|
->withTrace($trace2);
|
|
|
|
$merged = $context1->merge($context2);
|
|
|
|
expect($merged->user)->toBe($user2);
|
|
expect($merged->request)->toBe($request2);
|
|
expect($merged->trace)->toBe($trace2);
|
|
});
|
|
|
|
it('can convert to array', function () {
|
|
$userContext = UserContext::authenticated('123', 'john');
|
|
$requestContext = RequestContext::empty();
|
|
$traceContext = TraceContext::start(new SecureRandomGenerator());
|
|
|
|
$context = LogContext::withData(['key' => 'value'])
|
|
->addTags('tag1', 'tag2')
|
|
->withUser($userContext)
|
|
->withRequest($requestContext)
|
|
->withTrace($traceContext)
|
|
->addMetadata('source', 'test');
|
|
|
|
$array = $context->toArray();
|
|
|
|
expect($array)->toHaveKeys([
|
|
'structured',
|
|
'tags',
|
|
'trace',
|
|
'user',
|
|
'request',
|
|
'metadata',
|
|
]);
|
|
|
|
expect($array['structured'])->toBe(['key' => 'value']);
|
|
expect($array['tags'])->toBe(['tag1', 'tag2']);
|
|
expect($array['metadata'])->toBe(['source' => 'test']);
|
|
});
|
|
|
|
it('only includes non-empty sections in toArray', function () {
|
|
$context = LogContext::withData(['key' => 'value']);
|
|
$array = $context->toArray();
|
|
|
|
expect($array)->toHaveKey('structured');
|
|
expect($array)->not->toHaveKey('tags');
|
|
expect($array)->not->toHaveKey('trace');
|
|
expect($array)->not->toHaveKey('user');
|
|
expect($array)->not->toHaveKey('request');
|
|
expect($array)->not->toHaveKey('metadata');
|
|
});
|
|
|
|
it('can create context with current trace', function () {
|
|
// Clear any existing trace
|
|
TraceContext::clear();
|
|
|
|
// Start a new trace
|
|
$trace = TraceContext::start(new SecureRandomGenerator());
|
|
|
|
$context = LogContext::withCurrentTrace();
|
|
|
|
expect($context->trace)->toBe($trace);
|
|
|
|
// Cleanup
|
|
TraceContext::clear();
|
|
});
|
|
|
|
it('creates context with null trace when no current trace', function () {
|
|
TraceContext::clear();
|
|
|
|
$context = LogContext::withCurrentTrace();
|
|
|
|
expect($context->trace)->toBeNull();
|
|
});
|
|
});
|