- 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.
252 lines
9.1 KiB
PHP
252 lines
9.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/../../vendor/autoload.php';
|
|
|
|
use App\Application\LiveComponents\Counter\CounterComponent;
|
|
use App\Application\LiveComponents\NotificationBell\NotificationBellComponent;
|
|
use App\Application\LiveComponents\Stats\StatsComponent;
|
|
use App\Framework\LiveComponents\ValueObjects\ActionParameters;
|
|
use App\Framework\LiveComponents\ValueObjects\ComponentData;
|
|
use App\Framework\LiveComponents\ValueObjects\ComponentId;
|
|
|
|
echo "=== LiveComponents Strict Type Integration Test ===\n\n";
|
|
|
|
// Note: We test components directly without the full DI container
|
|
// This tests the strict typing at the component level
|
|
echo "Testing components with strict Value Object types only...\n";
|
|
|
|
$testsPassed = 0;
|
|
$testsFailed = 0;
|
|
|
|
// Test 1: CounterComponent constructor with strict types
|
|
echo "\nTest 1: CounterComponent constructor with strict types\n";
|
|
|
|
try {
|
|
$id = ComponentId::create('counter', 'test-strict');
|
|
$data = ComponentData::fromArray(['count' => 5]);
|
|
|
|
$component = new CounterComponent($id, $data);
|
|
|
|
assert($component instanceof CounterComponent, 'Component should be CounterComponent');
|
|
assert($component->getId() instanceof ComponentId, 'getId() should return ComponentId');
|
|
assert($component->getData() instanceof ComponentData, 'getData() should return ComponentData');
|
|
assert($component->getData()->get('count') === 5, 'Initial count should be 5');
|
|
|
|
echo "✅ CounterComponent constructor accepts strict types\n";
|
|
$testsPassed++;
|
|
} catch (\Throwable $e) {
|
|
echo "❌ CounterComponent constructor test failed: {$e->getMessage()}\n";
|
|
$testsFailed++;
|
|
}
|
|
|
|
// Test 2: CounterComponent increment action returns ComponentData
|
|
echo "\nTest 2: CounterComponent increment action returns ComponentData\n";
|
|
|
|
try {
|
|
$id = ComponentId::create('counter', 'test-action');
|
|
$data = ComponentData::fromArray(['count' => 10]);
|
|
|
|
$component = new CounterComponent($id, $data);
|
|
$params = ActionParameters::empty();
|
|
|
|
$result = $component->increment($params);
|
|
|
|
assert($result instanceof ComponentData, 'increment() should return ComponentData');
|
|
assert($result->get('count') === 11, 'Count should be incremented to 11');
|
|
|
|
echo "✅ CounterComponent increment returns ComponentData\n";
|
|
$testsPassed++;
|
|
} catch (\Throwable $e) {
|
|
echo "❌ CounterComponent action test failed: {$e->getMessage()}\n";
|
|
$testsFailed++;
|
|
}
|
|
|
|
// Test 3: NotificationBellComponent constructor with strict types
|
|
echo "\nTest 3: NotificationBellComponent constructor with strict types\n";
|
|
|
|
try {
|
|
$id = ComponentId::create('notification-bell', 'user-123');
|
|
$data = ComponentData::fromArray([
|
|
'user_id' => '123',
|
|
'unread_count' => 3,
|
|
]);
|
|
|
|
$component = new NotificationBellComponent($id, $data);
|
|
|
|
assert($component instanceof NotificationBellComponent, 'Component should be NotificationBellComponent');
|
|
assert($component->getId() instanceof ComponentId, 'getId() should return ComponentId');
|
|
assert($component->getData() instanceof ComponentData, 'getData() should return ComponentData');
|
|
assert($component->getData()->get('unread_count') === 3, 'Initial unread_count should be 3');
|
|
|
|
echo "✅ NotificationBellComponent constructor accepts strict types\n";
|
|
$testsPassed++;
|
|
} catch (\Throwable $e) {
|
|
echo "❌ NotificationBellComponent test failed: {$e->getMessage()}\n";
|
|
$testsFailed++;
|
|
}
|
|
|
|
// Test 4: NotificationBellComponent poll returns ComponentData
|
|
echo "\nTest 4: NotificationBellComponent poll returns ComponentData\n";
|
|
|
|
try {
|
|
$id = ComponentId::create('notification-bell', 'user-poll');
|
|
$data = ComponentData::fromArray(['user_id' => '456']);
|
|
|
|
$component = new NotificationBellComponent($id, $data);
|
|
$params = ActionParameters::empty();
|
|
|
|
$result = $component->poll($params);
|
|
|
|
assert($result instanceof ComponentData, 'poll() should return ComponentData');
|
|
assert($result->has('unread_count'), 'Result should have unread_count');
|
|
assert($result->has('notifications'), 'Result should have notifications');
|
|
|
|
echo "✅ NotificationBellComponent poll returns ComponentData\n";
|
|
$testsPassed++;
|
|
} catch (\Throwable $e) {
|
|
echo "❌ NotificationBellComponent poll test failed: {$e->getMessage()}\n";
|
|
$testsFailed++;
|
|
}
|
|
|
|
// Test 5: StatsComponent constructor with strict types
|
|
echo "\nTest 5: StatsComponent constructor with strict types\n";
|
|
|
|
try {
|
|
$id = ComponentId::create('stats', 'dashboard');
|
|
$data = ComponentData::fromArray(['cache_enabled' => true]);
|
|
|
|
$component = new StatsComponent($id, $data);
|
|
|
|
assert($component instanceof StatsComponent, 'Component should be StatsComponent');
|
|
assert($component->getId() instanceof ComponentId, 'getId() should return ComponentId');
|
|
assert($component->getData() instanceof ComponentData, 'getData() should return ComponentData');
|
|
assert($component->getData()->get('cache_enabled') === true, 'cache_enabled should be true');
|
|
|
|
echo "✅ StatsComponent constructor accepts strict types\n";
|
|
$testsPassed++;
|
|
} catch (\Throwable $e) {
|
|
echo "❌ StatsComponent test failed: {$e->getMessage()}\n";
|
|
$testsFailed++;
|
|
}
|
|
|
|
// Test 6: StatsComponent toggleCache returns ComponentData
|
|
echo "\nTest 6: StatsComponent toggleCache returns ComponentData\n";
|
|
|
|
try {
|
|
$id = ComponentId::create('stats', 'toggle-test');
|
|
$data = ComponentData::fromArray(['cache_enabled' => true]);
|
|
|
|
$component = new StatsComponent($id, $data);
|
|
$params = ActionParameters::empty();
|
|
|
|
$result = $component->toggleCache($params);
|
|
|
|
assert($result instanceof ComponentData, 'toggleCache() should return ComponentData');
|
|
assert($result->get('cache_enabled') === false, 'cache_enabled should be toggled to false');
|
|
|
|
echo "✅ StatsComponent toggleCache returns ComponentData\n";
|
|
$testsPassed++;
|
|
} catch (\Throwable $e) {
|
|
echo "❌ StatsComponent toggle test failed: {$e->getMessage()}\n";
|
|
$testsFailed++;
|
|
}
|
|
|
|
// Test 7: Component constructor with null ComponentData
|
|
echo "\nTest 7: Component constructor with null ComponentData\n";
|
|
|
|
try {
|
|
$id = ComponentId::create('counter', 'null-data-test');
|
|
|
|
// Pass null, should use ComponentData::empty()
|
|
$component = new CounterComponent($id, null);
|
|
|
|
assert($component instanceof CounterComponent, 'Component should be CounterComponent');
|
|
assert($component->getData() instanceof ComponentData, 'getData() should return ComponentData');
|
|
assert($component->getData()->get('count', 0) === 0, 'Default count should be 0');
|
|
|
|
echo "✅ Component constructor handles null ComponentData correctly\n";
|
|
$testsPassed++;
|
|
} catch (\Throwable $e) {
|
|
echo "❌ Component null data test failed: {$e->getMessage()}\n";
|
|
$testsFailed++;
|
|
}
|
|
|
|
// Test 8: ComponentData immutability
|
|
echo "\nTest 8: ComponentData immutability\n";
|
|
|
|
try {
|
|
$id = ComponentId::create('counter', 'immutability-test');
|
|
$originalData = ComponentData::fromArray(['count' => 10]);
|
|
|
|
$component = new CounterComponent($id, $originalData);
|
|
$params = ActionParameters::empty();
|
|
|
|
$newData = $component->increment($params);
|
|
|
|
assert($originalData->get('count') === 10, 'Original data should be unchanged');
|
|
assert($newData->get('count') === 11, 'New data should be incremented');
|
|
assert($originalData !== $newData, 'Should be different instances');
|
|
|
|
echo "✅ ComponentData immutability preserved\n";
|
|
$testsPassed++;
|
|
} catch (\Throwable $e) {
|
|
echo "❌ Immutability test failed: {$e->getMessage()}\n";
|
|
$testsFailed++;
|
|
}
|
|
|
|
// Test 9: ComponentId toString consistency
|
|
echo "\nTest 9: ComponentId toString consistency\n";
|
|
|
|
try {
|
|
$id = ComponentId::create('counter', 'id-test');
|
|
|
|
$idString = $id->toString();
|
|
assert($idString === 'counter:id-test', 'ComponentId toString should match expected format');
|
|
|
|
$parsedId = ComponentId::fromString($idString);
|
|
assert($parsedId->toString() === $idString, 'Parsed ID should match original');
|
|
|
|
echo "✅ ComponentId toString/fromString working correctly\n";
|
|
$testsPassed++;
|
|
} catch (\Throwable $e) {
|
|
echo "❌ ComponentId test failed: {$e->getMessage()}\n";
|
|
$testsFailed++;
|
|
}
|
|
|
|
// Test 10: ActionParameters type coercion
|
|
echo "\nTest 10: ActionParameters type coercion\n";
|
|
|
|
try {
|
|
$params = ActionParameters::fromArray([
|
|
'amount' => '5', // String
|
|
'enabled' => 'true', // String boolean
|
|
'data' => ['key' => 'value'],
|
|
]);
|
|
|
|
assert($params->getInt('amount') === 5, 'getString should coerce to int');
|
|
assert($params->getBool('enabled') === true, 'getBool should coerce string to bool');
|
|
assert($params->getArray('data') === ['key' => 'value'], 'getArray should return array');
|
|
|
|
echo "✅ ActionParameters type coercion working\n";
|
|
$testsPassed++;
|
|
} catch (\Throwable $e) {
|
|
echo "❌ ActionParameters test failed: {$e->getMessage()}\n";
|
|
$testsFailed++;
|
|
}
|
|
|
|
// Summary
|
|
echo "\n=== Test Summary ===\n";
|
|
echo "✅ Passed: {$testsPassed}\n";
|
|
echo "❌ Failed: {$testsFailed}\n";
|
|
echo "Total: " . ($testsPassed + $testsFailed) . "\n";
|
|
|
|
if ($testsFailed === 0) {
|
|
echo "\n🎉 All strict type migration tests passed!\n";
|
|
exit(0);
|
|
} else {
|
|
echo "\n⚠️ Some tests failed. Please review the output above.\n";
|
|
exit(1);
|
|
}
|