- 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.
130 lines
5.7 KiB
PHP
130 lines
5.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Framework\HttpClient\Curl\Handle;
|
|
use App\Framework\HttpClient\Curl\HandleOption;
|
|
use App\Framework\HttpClient\Curl\Pause;
|
|
use App\Framework\HttpClient\Curl\Exception\HandleException;
|
|
|
|
describe('Curl\HandleException', function () {
|
|
it('provides context for initialization failures', function () {
|
|
try {
|
|
// Simulate initialization failure (hard to test directly)
|
|
throw HandleException::initializationFailed('https://example.com');
|
|
} catch (HandleException $e) {
|
|
expect($e->getMessage())->toContain('Failed to initialize cURL handle');
|
|
expect($e->getData())->toHaveKey('url');
|
|
expect($e->getData()['url'])->toBe('https://example.com');
|
|
}
|
|
});
|
|
|
|
it('provides context for execution failures', function () {
|
|
$exception = HandleException::executionFailed('Connection timeout', 28);
|
|
|
|
expect($exception->getMessage())->toContain('cURL execution failed');
|
|
expect($exception->getData())->toHaveKey('curl_error_code');
|
|
expect($exception->getData())->toHaveKey('curl_error_message');
|
|
expect($exception->getData()['curl_error_code'])->toBe(28);
|
|
expect($exception->getData()['curl_error_message'])->toBe('Connection timeout');
|
|
});
|
|
|
|
it('provides context for invalid output target', function () {
|
|
$exception = HandleException::invalidOutputTarget('not-a-resource');
|
|
|
|
expect($exception->getMessage())->toContain('Invalid output target');
|
|
expect($exception->getData())->toHaveKey('output_type');
|
|
expect($exception->getData()['output_type'])->toBe('string');
|
|
});
|
|
|
|
it('provides context for setOption failures', function () {
|
|
$exception = HandleException::setOptionFailed(
|
|
HandleOption::Timeout,
|
|
'invalid',
|
|
'Invalid type'
|
|
);
|
|
|
|
expect($exception->getMessage())->toContain('Failed to set cURL option');
|
|
expect($exception->getData())->toHaveKey('option');
|
|
expect($exception->getData())->toHaveKey('value');
|
|
expect($exception->getData())->toHaveKey('error');
|
|
expect($exception->getData()['option'])->toBe('Timeout');
|
|
});
|
|
|
|
it('provides context for invalid option types', function () {
|
|
$exception = HandleException::invalidOptionType(HandleOption::Timeout, 'invalid');
|
|
|
|
expect($exception->getMessage())->toContain('Invalid type for option Timeout');
|
|
expect($exception->getMessage())->toContain('expected integer');
|
|
expect($exception->getMessage())->toContain('got string');
|
|
expect($exception->getData())->toHaveKey('option');
|
|
expect($exception->getData())->toHaveKey('expected_type');
|
|
expect($exception->getData())->toHaveKey('actual_type');
|
|
expect($exception->getData()['expected_type'])->toBe('integer');
|
|
expect($exception->getData()['actual_type'])->toBe('string');
|
|
});
|
|
|
|
it('provides context for pause failures', function () {
|
|
$exception = HandleException::pauseFailed(Pause::Recv, 'Pause operation failed');
|
|
|
|
expect($exception->getMessage())->toContain('Failed to pause cURL handle');
|
|
expect($exception->getData())->toHaveKey('pause_flag');
|
|
expect($exception->getData())->toHaveKey('pause_value');
|
|
expect($exception->getData()['pause_flag'])->toBe('Recv');
|
|
});
|
|
|
|
it('provides context for escape failures', function () {
|
|
$exception = HandleException::escapeFailed('some string');
|
|
|
|
expect($exception->getMessage())->toContain('Failed to URL-escape string');
|
|
expect($exception->getData())->toHaveKey('string_length');
|
|
expect($exception->getData()['string_length'])->toBe(strlen('some string'));
|
|
});
|
|
|
|
it('provides context for unescape failures', function () {
|
|
$exception = HandleException::unescapeFailed('some%20string');
|
|
|
|
expect($exception->getMessage())->toContain('Failed to URL-unescape string');
|
|
expect($exception->getData())->toHaveKey('string');
|
|
expect($exception->getData()['string'])->toBe('some%20string');
|
|
});
|
|
|
|
it('provides context for upkeep failures', function () {
|
|
$exception = HandleException::upkeepFailed('Connection check failed');
|
|
|
|
expect($exception->getMessage())->toContain('cURL upkeep failed');
|
|
expect($exception->getData())->toHaveKey('error');
|
|
expect($exception->getData()['error'])->toBe('Connection check failed');
|
|
});
|
|
|
|
it('includes error details in real execution failure', function () {
|
|
$handle = new Handle('https://invalid-domain-that-does-not-exist-99999.com');
|
|
$handle->setOption(HandleOption::Timeout, 3);
|
|
|
|
try {
|
|
$handle->fetch();
|
|
throw new Exception('Should have thrown HandleException');
|
|
} catch (HandleException $e) {
|
|
expect($e->getMessage())->toContain('cURL execution failed');
|
|
expect($e->getData())->toHaveKey('curl_error_code');
|
|
expect($e->getData())->toHaveKey('curl_error_message');
|
|
expect($e->getData()['curl_error_code'])->toBeGreaterThan(0);
|
|
expect($e->getData()['curl_error_message'])->not->toBeEmpty();
|
|
}
|
|
});
|
|
|
|
it('includes error details in type validation failure', function () {
|
|
$handle = new Handle();
|
|
|
|
try {
|
|
$handle->setOption(HandleOption::Timeout, 'not-an-integer');
|
|
throw new Exception('Should have thrown HandleException');
|
|
} catch (HandleException $e) {
|
|
expect($e->getMessage())->toContain('Invalid type');
|
|
expect($e->getData()['option'])->toBe('Timeout');
|
|
expect($e->getData()['expected_type'])->toBe('integer');
|
|
expect($e->getData()['actual_type'])->toBe('string');
|
|
}
|
|
});
|
|
});
|