Files
michaelschiemer/tests/Unit/Framework/Exception/ExceptionMetadataTest.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

248 lines
8.8 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\Exception\ExceptionMetadata;
describe('ExceptionMetadata', function () {
describe('Factory Methods', function () {
it('creates default metadata', function () {
$metadata = ExceptionMetadata::default();
expect($metadata->skipAggregation)->toBeFalse();
expect($metadata->skipReporting)->toBeFalse();
expect($metadata->reported)->toBeFalse();
expect($metadata->retryAfter)->toBeNull();
});
it('creates metadata with retry', function () {
$metadata = ExceptionMetadata::withRetry(60);
expect($metadata->retryAfter)->toBe(60);
expect($metadata->skipAggregation)->toBeFalse();
});
});
describe('Immutability', function () {
it('withSkipAggregation creates new instance', function () {
$original = ExceptionMetadata::default();
$modified = $original->withSkipAggregation();
expect($original)->not->toBe($modified);
expect($original->skipAggregation)->toBeFalse();
expect($modified->skipAggregation)->toBeTrue();
});
it('withSkipReporting creates new instance', function () {
$original = ExceptionMetadata::default();
$modified = $original->withSkipReporting();
expect($original->skipReporting)->toBeFalse();
expect($modified->skipReporting)->toBeTrue();
});
it('withSkipAll creates new instance', function () {
$original = ExceptionMetadata::default();
$modified = $original->withSkipAll();
expect($modified->skipAggregation)->toBeTrue();
expect($modified->skipReporting)->toBeTrue();
});
it('markAsReported creates new instance', function () {
$original = ExceptionMetadata::default();
$modified = $original->markAsReported();
expect($original->reported)->toBeFalse();
expect($modified->reported)->toBeTrue();
});
it('withRetryAfter creates new instance', function () {
$original = ExceptionMetadata::default();
$modified = $original->withRetryAfter(30);
expect($original->retryAfter)->toBeNull();
expect($modified->retryAfter)->toBe(30);
});
});
describe('Behavior Control', function () {
it('shouldAggregate returns correct value', function () {
$default = ExceptionMetadata::default();
$skipped = $default->withSkipAggregation();
expect($default->shouldAggregate())->toBeTrue();
expect($skipped->shouldAggregate())->toBeFalse();
});
it('shouldReport considers both flags', function () {
$default = ExceptionMetadata::default();
$skipReporting = $default->withSkipReporting();
$reported = $default->markAsReported();
expect($default->shouldReport())->toBeTrue();
expect($skipReporting->shouldReport())->toBeFalse();
expect($reported->shouldReport())->toBeFalse();
});
it('wasReported returns correct value', function () {
$notReported = ExceptionMetadata::default();
$reported = $notReported->markAsReported();
expect($notReported->wasReported())->toBeFalse();
expect($reported->wasReported())->toBeTrue();
});
});
describe('Chaining', function () {
it('chains multiple modifications', function () {
$metadata = ExceptionMetadata::default()
->withSkipAggregation()
->withRetryAfter(60);
expect($metadata->skipAggregation)->toBeTrue();
expect($metadata->retryAfter)->toBe(60);
expect($metadata->skipReporting)->toBeFalse();
});
it('preserves existing values when chaining', function () {
$metadata = ExceptionMetadata::withRetry(30)
->withSkipReporting();
expect($metadata->retryAfter)->toBe(30);
expect($metadata->skipReporting)->toBeTrue();
expect($metadata->skipAggregation)->toBeFalse();
});
});
describe('Serialization', function () {
it('converts to array', function () {
$metadata = ExceptionMetadata::default()
->withSkipAggregation()
->withRetryAfter(60);
$array = $metadata->toArray();
expect($array)->toBe([
'skip_aggregation' => true,
'skip_reporting' => false,
'reported' => false,
'retry_after' => 60,
]);
});
it('creates from array', function () {
$array = [
'skip_aggregation' => true,
'skip_reporting' => true,
'reported' => false,
'retry_after' => 30,
];
$metadata = ExceptionMetadata::fromArray($array);
expect($metadata->skipAggregation)->toBeTrue();
expect($metadata->skipReporting)->toBeTrue();
expect($metadata->reported)->toBeFalse();
expect($metadata->retryAfter)->toBe(30);
});
it('handles missing array keys with defaults', function () {
$metadata = ExceptionMetadata::fromArray([]);
expect($metadata->skipAggregation)->toBeFalse();
expect($metadata->skipReporting)->toBeFalse();
expect($metadata->reported)->toBeFalse();
expect($metadata->retryAfter)->toBeNull();
});
it('roundtrips through array', function () {
$original = ExceptionMetadata::default()
->withSkipAll()
->withRetryAfter(120)
->markAsReported();
$array = $original->toArray();
$restored = ExceptionMetadata::fromArray($array);
expect($restored->skipAggregation)->toBe($original->skipAggregation);
expect($restored->skipReporting)->toBe($original->skipReporting);
expect($restored->reported)->toBe($original->reported);
expect($restored->retryAfter)->toBe($original->retryAfter);
});
});
describe('Edge Cases', function () {
it('handles null retry after', function () {
$metadata = ExceptionMetadata::default()
->withRetryAfter(60)
->withRetryAfter(null);
expect($metadata->retryAfter)->toBeNull();
});
it('handles zero retry after', function () {
$metadata = ExceptionMetadata::withRetry(0);
expect($metadata->retryAfter)->toBe(0);
});
it('handles negative retry after', function () {
$metadata = ExceptionMetadata::withRetry(-1);
expect($metadata->retryAfter)->toBe(-1);
});
it('marking as reported multiple times is idempotent', function () {
$metadata = ExceptionMetadata::default()
->markAsReported()
->markAsReported();
expect($metadata->reported)->toBeTrue();
expect($metadata->shouldReport())->toBeFalse();
});
});
describe('Integration Scenarios', function () {
it('supports typical exception lifecycle', function () {
// 1. Create exception with default metadata
$metadata = ExceptionMetadata::default();
expect($metadata->shouldReport())->toBeTrue();
expect($metadata->shouldAggregate())->toBeTrue();
// 2. Skip aggregation for specific case
$metadata = $metadata->withSkipAggregation();
expect($metadata->shouldAggregate())->toBeFalse();
expect($metadata->shouldReport())->toBeTrue();
// 3. Mark as reported after logging
$metadata = $metadata->markAsReported();
expect($metadata->wasReported())->toBeTrue();
expect($metadata->shouldReport())->toBeFalse();
});
it('supports retry scenario', function () {
// 1. Create with retry hint
$metadata = ExceptionMetadata::withRetry(60);
expect($metadata->retryAfter)->toBe(60);
// 2. Update retry time
$metadata = $metadata->withRetryAfter(30);
expect($metadata->retryAfter)->toBe(30);
// 3. Clear retry
$metadata = $metadata->withRetryAfter(null);
expect($metadata->retryAfter)->toBeNull();
});
it('supports skip all for internal exceptions', function () {
$metadata = ExceptionMetadata::default()
->withSkipAll();
expect($metadata->shouldAggregate())->toBeFalse();
expect($metadata->shouldReport())->toBeFalse();
expect($metadata->wasReported())->toBeFalse();
});
});
});