- 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.
179 lines
5.5 KiB
PHP
179 lines
5.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/../../vendor/autoload.php';
|
|
|
|
use App\Framework\Http\Url\Rfc3986Url;
|
|
use App\Framework\Http\Url\UrlFactory;
|
|
use App\Framework\Http\Url\WhatwgUrl;
|
|
|
|
echo "=== Manual URL System Test ===\n\n";
|
|
|
|
$tests = 0;
|
|
$passed = 0;
|
|
|
|
function test(string $name, callable $fn): void
|
|
{
|
|
global $tests, $passed;
|
|
$tests++;
|
|
|
|
try {
|
|
$fn();
|
|
echo "✅ {$name}\n";
|
|
$passed++;
|
|
} catch (\Throwable $e) {
|
|
echo "❌ {$name}: {$e->getMessage()}\n";
|
|
}
|
|
}
|
|
|
|
// RFC 3986 Tests
|
|
echo "--- RFC 3986 Tests ---\n";
|
|
|
|
test('Parse basic URL', function () {
|
|
$url = Rfc3986Url::parse('https://example.com/path');
|
|
assert($url->getScheme() === 'https');
|
|
assert($url->getHost() === 'example.com');
|
|
assert($url->getPath() === '/path');
|
|
});
|
|
|
|
test('Parse URL with all components', function () {
|
|
$url = Rfc3986Url::parse('https://user:pass@example.com:8080/path?query=1#frag');
|
|
assert($url->getScheme() === 'https');
|
|
assert($url->getUserInfo() === 'user:pass');
|
|
assert($url->getHost() === 'example.com');
|
|
assert($url->getPort() === 8080);
|
|
assert($url->getPath() === '/path');
|
|
assert($url->getQuery() === 'query=1');
|
|
assert($url->getFragment() === 'frag');
|
|
});
|
|
|
|
test('Immutable withScheme', function () {
|
|
$original = Rfc3986Url::parse('https://example.com');
|
|
$modified = $original->withScheme('http');
|
|
assert($original->getScheme() === 'https');
|
|
assert($modified->getScheme() === 'http');
|
|
assert(spl_object_id($original) !== spl_object_id($modified));
|
|
});
|
|
|
|
test('Immutable withPath', function () {
|
|
$url = Rfc3986Url::parse('https://example.com/old');
|
|
$modified = $url->withPath('/new');
|
|
assert($url->getPath() === '/old');
|
|
assert($modified->getPath() === '/new');
|
|
});
|
|
|
|
test('URL resolution', function () {
|
|
$base = Rfc3986Url::parse('https://example.com/base/path');
|
|
$resolved = $base->resolve('../other');
|
|
assert($resolved->getHost() === 'example.com');
|
|
});
|
|
|
|
test('URL equality', function () {
|
|
$url1 = Rfc3986Url::parse('https://example.com/path');
|
|
$url2 = Rfc3986Url::parse('https://example.com/path');
|
|
assert($url1->equals($url2) === true);
|
|
});
|
|
|
|
test('URL equality ignores fragment by default', function () {
|
|
$url1 = Rfc3986Url::parse('https://example.com/path#frag1');
|
|
$url2 = Rfc3986Url::parse('https://example.com/path#frag2');
|
|
assert($url1->equals($url2) === true);
|
|
// Native PHP API always ignores fragments in equals()
|
|
// For our wrapper, we delegate to native behavior
|
|
});
|
|
|
|
test('URLs with different paths are not equal', function () {
|
|
$url1 = Rfc3986Url::parse('https://example.com/path1');
|
|
$url2 = Rfc3986Url::parse('https://example.com/path2');
|
|
assert($url1->equals($url2) === false);
|
|
});
|
|
|
|
// WHATWG Tests
|
|
echo "\n--- WHATWG Tests ---\n";
|
|
|
|
test('Parse WHATWG URL', function () {
|
|
$url = WhatwgUrl::parse('https://example.com/path');
|
|
assert($url->getScheme() === 'https');
|
|
assert($url->getHost() === 'example.com');
|
|
assert($url->getPath() === '/path');
|
|
});
|
|
|
|
test('WHATWG with all components', function () {
|
|
$url = WhatwgUrl::parse('https://user:pass@example.com:8080/path?query=1#frag');
|
|
assert($url->getScheme() === 'https');
|
|
assert($url->getUserInfo() === 'user:pass');
|
|
assert($url->getHost() === 'example.com');
|
|
assert($url->getPort() === 8080);
|
|
assert($url->getPath() === '/path');
|
|
assert($url->getQuery() === 'query=1');
|
|
assert($url->getFragment() === 'frag');
|
|
});
|
|
|
|
test('WHATWG immutable withers', function () {
|
|
$original = WhatwgUrl::parse('https://example.com');
|
|
$modified = $original->withScheme('http');
|
|
assert($original->getScheme() === 'https');
|
|
assert($modified->getScheme() === 'http');
|
|
});
|
|
|
|
test('WHATWG URL resolution', function () {
|
|
$base = WhatwgUrl::parse('https://example.com/base');
|
|
$resolved = $base->resolve('relative');
|
|
assert($resolved->getHost() === 'example.com');
|
|
});
|
|
|
|
// Factory Tests
|
|
echo "\n--- Factory Tests ---\n";
|
|
|
|
test('Factory auto-selects WHATWG for http', function () {
|
|
$url = UrlFactory::parse('https://example.com');
|
|
assert($url instanceof WhatwgUrl);
|
|
});
|
|
|
|
test('Factory forApiClient creates RFC3986', function () {
|
|
$url = UrlFactory::forApiClient('https://api.example.com');
|
|
assert($url instanceof Rfc3986Url);
|
|
});
|
|
|
|
test('Factory forBrowserRedirect creates WHATWG', function () {
|
|
$url = UrlFactory::forBrowserRedirect('https://example.com');
|
|
assert($url instanceof WhatwgUrl);
|
|
});
|
|
|
|
// Integration Tests
|
|
echo "\n--- Integration Tests ---\n";
|
|
|
|
test('API client with authentication', function () {
|
|
$url = UrlFactory::forApiClient('https://api.example.com/users');
|
|
$withAuth = $url->withUserInfo('api_key', 'secret');
|
|
$urlString = $withAuth->toString();
|
|
assert(str_contains($urlString, 'api_key'));
|
|
assert(str_contains($urlString, 'secret'));
|
|
});
|
|
|
|
test('Browser redirect with query', function () {
|
|
$url = UrlFactory::forBrowserRedirect('https://example.com/login');
|
|
$withQuery = $url->withQuery('return_url=/dashboard');
|
|
assert($withQuery->getQuery() === 'return_url=/dashboard');
|
|
});
|
|
|
|
test('URL signature generation', function () {
|
|
$url = UrlFactory::forSignature('https://api.example.com/resource');
|
|
$withParams = $url->withQuery('timestamp=123&user_id=42');
|
|
$urlString = $withParams->toString();
|
|
assert(str_contains($urlString, 'timestamp=123'));
|
|
});
|
|
|
|
// Summary
|
|
echo "\n=== Summary ===\n";
|
|
echo "Tests: {$passed}/{$tests} passed\n";
|
|
|
|
if ($passed === $tests) {
|
|
echo "✅ All tests passed!\n";
|
|
exit(0);
|
|
} else {
|
|
echo "❌ Some tests failed\n";
|
|
exit(1);
|
|
}
|