- 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.
287 lines
10 KiB
PHP
287 lines
10 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/../../vendor/autoload.php';
|
|
|
|
use App\Domain\PreSave\PreSaveCampaign;
|
|
use App\Domain\PreSave\PreSaveCampaignRepository;
|
|
use App\Domain\PreSave\PreSaveProcessor;
|
|
use App\Domain\PreSave\PreSaveRegistration;
|
|
use App\Domain\PreSave\PreSaveRegistrationRepository;
|
|
use App\Domain\PreSave\ValueObjects\CampaignStatus;
|
|
use App\Domain\PreSave\ValueObjects\StreamingPlatform;
|
|
use App\Framework\Core\AppBootstrapper;
|
|
use App\Framework\DateTime\SystemClock;
|
|
use App\Framework\DateTime\SystemHighResolutionClock;
|
|
use App\Framework\OAuth\Providers\AppleMusicProvider;
|
|
use App\Framework\OAuth\Providers\SpotifyProvider;
|
|
use App\Framework\OAuth\Providers\TidalProvider;
|
|
use App\Framework\OAuth\Storage\OAuthTokenRepository;
|
|
use App\Framework\OAuth\Storage\StoredOAuthToken;
|
|
use App\Framework\Performance\EnhancedPerformanceCollector;
|
|
use App\Framework\Performance\MemoryMonitor;
|
|
|
|
echo "=== Complete Pre-Save System Test ===" . PHP_EOL . PHP_EOL;
|
|
|
|
// Bootstrap application
|
|
$basePath = dirname(__DIR__, 2);
|
|
$clock = new SystemClock();
|
|
$highResClock = new SystemHighResolutionClock();
|
|
$memoryMonitor = new MemoryMonitor();
|
|
$collector = new EnhancedPerformanceCollector($clock, $highResClock, $memoryMonitor, enabled: false);
|
|
|
|
// Bootstrap application
|
|
$bootstrapper = new AppBootstrapper($basePath, $collector, $memoryMonitor);
|
|
$app = $bootstrapper->bootstrapWeb();
|
|
|
|
// Get container via reflection (no public getter exists)
|
|
$reflection = new \ReflectionClass($bootstrapper);
|
|
$containerProperty = $reflection->getProperty('container');
|
|
$containerProperty->setAccessible(true);
|
|
$container = $containerProperty->getValue($bootstrapper);
|
|
|
|
// Get repositories and services
|
|
$campaignRepo = $container->get(PreSaveCampaignRepository::class);
|
|
$registrationRepo = $container->get(PreSaveRegistrationRepository::class);
|
|
$tokenRepo = $container->get(OAuthTokenRepository::class);
|
|
$processor = $container->get(PreSaveProcessor::class);
|
|
|
|
// Get OAuth providers
|
|
$spotifyProvider = $container->get(SpotifyProvider::class);
|
|
$appleMusicProvider = $container->get(AppleMusicProvider::class);
|
|
$tidalProvider = $container->get(TidalProvider::class);
|
|
|
|
echo "✓ Application bootstrapped successfully" . PHP_EOL;
|
|
echo "✓ All services loaded from DI container" . PHP_EOL . PHP_EOL;
|
|
|
|
// Test 1: Create a Pre-Save Campaign
|
|
echo "Test 1: Creating a Pre-Save Campaign..." . PHP_EOL;
|
|
|
|
$campaign = PreSaveCampaign::create(
|
|
title: 'Summer Vibes 2025',
|
|
artistName: 'The Cool Artists',
|
|
coverImageUrl: 'https://example.com/cover.jpg',
|
|
description: 'An amazing summer album with 12 tracks of pure vibes',
|
|
releaseDate: time() + (7 * 24 * 60 * 60), // Release in 7 days
|
|
trackUrls: [
|
|
'spotify' => 'https://open.spotify.com/album/test123',
|
|
'apple_music' => 'https://music.apple.com/album/test123',
|
|
'tidal' => 'https://tidal.com/browse/album/test123',
|
|
],
|
|
startDate: time() // Start now
|
|
);
|
|
|
|
$campaignRepo->save($campaign);
|
|
echo "✓ Campaign created with ID: {$campaign->id}" . PHP_EOL;
|
|
echo " Title: {$campaign->title}" . PHP_EOL;
|
|
echo " Artist: {$campaign->artistName}" . PHP_EOL;
|
|
echo " Status: {$campaign->status->value}" . PHP_EOL . PHP_EOL;
|
|
|
|
// Test 2: Activate the campaign
|
|
echo "Test 2: Activating campaign..." . PHP_EOL;
|
|
|
|
$activeCampaign = $campaign->updateStatus(CampaignStatus::ACTIVE);
|
|
$campaignRepo->save($activeCampaign);
|
|
echo "✓ Campaign activated" . PHP_EOL;
|
|
echo " Status: {$activeCampaign->status->value}" . PHP_EOL . PHP_EOL;
|
|
|
|
// Test 3: Create mock OAuth tokens for test user
|
|
echo "Test 3: Creating OAuth tokens for test user..." . PHP_EOL;
|
|
|
|
$userId = 'test_user_123';
|
|
|
|
// Spotify token
|
|
$spotifyToken = StoredOAuthToken::create(
|
|
userId: $userId,
|
|
provider: 'spotify',
|
|
accessToken: 'test_spotify_access_token',
|
|
refreshToken: 'test_spotify_refresh_token',
|
|
tokenType: 'Bearer',
|
|
scope: 'user-library-modify user-library-read',
|
|
expiresAt: time() + 3600
|
|
);
|
|
$tokenRepo->save($spotifyToken);
|
|
echo "✓ Spotify token created" . PHP_EOL;
|
|
|
|
// Apple Music token
|
|
$appleMusicToken = StoredOAuthToken::create(
|
|
userId: $userId,
|
|
provider: 'apple_music',
|
|
accessToken: 'test_apple_music_access_token',
|
|
refreshToken: 'test_apple_music_refresh_token',
|
|
tokenType: 'Bearer',
|
|
scope: 'music-user-library-modify music-user-library-read',
|
|
expiresAt: time() + 3600
|
|
);
|
|
$tokenRepo->save($appleMusicToken);
|
|
echo "✓ Apple Music token created" . PHP_EOL;
|
|
|
|
// Tidal token
|
|
$tidalToken = StoredOAuthToken::create(
|
|
userId: $userId,
|
|
provider: 'tidal',
|
|
accessToken: 'test_tidal_access_token',
|
|
refreshToken: 'test_tidal_refresh_token',
|
|
tokenType: 'Bearer',
|
|
scope: 'r_usr w_usr',
|
|
expiresAt: time() + 3600
|
|
);
|
|
$tokenRepo->save($tidalToken);
|
|
echo "✓ Tidal token created" . PHP_EOL . PHP_EOL;
|
|
|
|
// Test 4: Create registrations for all platforms
|
|
echo "Test 4: Creating Pre-Save Registrations..." . PHP_EOL;
|
|
|
|
$platforms = [
|
|
StreamingPlatform::SPOTIFY,
|
|
StreamingPlatform::APPLE_MUSIC,
|
|
StreamingPlatform::TIDAL,
|
|
];
|
|
|
|
$registrations = [];
|
|
foreach ($platforms as $platform) {
|
|
$registration = PreSaveRegistration::create(
|
|
campaignId: $campaign->id,
|
|
userId: $userId,
|
|
platform: $platform,
|
|
registeredAt: time()
|
|
);
|
|
|
|
$registrationRepo->save($registration);
|
|
$registrations[] = $registration;
|
|
|
|
echo "✓ Registration created for {$platform->value}" . PHP_EOL;
|
|
echo " ID: {$registration->id}" . PHP_EOL;
|
|
echo " Status: {$registration->status->value}" . PHP_EOL;
|
|
}
|
|
|
|
echo PHP_EOL;
|
|
|
|
// Test 5: Verify registration lookup
|
|
echo "Test 5: Verifying registration lookup..." . PHP_EOL;
|
|
|
|
$foundRegistrations = $registrationRepo->findByCampaign($campaign->id);
|
|
echo "✓ Found " . count($foundRegistrations) . " registrations for campaign" . PHP_EOL;
|
|
|
|
foreach ($foundRegistrations as $reg) {
|
|
$hasToken = $tokenRepo->findForUser($reg->userId, $reg->platform->value) !== null;
|
|
echo " - {$reg->platform->value}: {$reg->status->value} (OAuth: " . ($hasToken ? 'YES' : 'NO') . ")" . PHP_EOL;
|
|
}
|
|
|
|
echo PHP_EOL;
|
|
|
|
// Test 6: Test provider functionality (without actually calling APIs)
|
|
echo "Test 6: OAuth Provider Configuration Test..." . PHP_EOL;
|
|
|
|
echo "✓ Spotify Provider: " . $spotifyProvider->getName() . PHP_EOL;
|
|
echo " Scopes: " . implode(', ', $spotifyProvider->getDefaultScopes()) . PHP_EOL;
|
|
|
|
echo "✓ Apple Music Provider: " . $appleMusicProvider->getName() . PHP_EOL;
|
|
echo " Scopes: " . implode(', ', $appleMusicProvider->getDefaultScopes()) . PHP_EOL;
|
|
|
|
echo "✓ Tidal Provider: " . $tidalProvider->getName() . PHP_EOL;
|
|
echo " Scopes: " . implode(', ', $tidalProvider->getDefaultScopes()) . PHP_EOL;
|
|
|
|
echo PHP_EOL;
|
|
|
|
// Test 7: Test campaign status transitions
|
|
echo "Test 7: Testing campaign status transitions..." . PHP_EOL;
|
|
|
|
$pausedCampaign = $activeCampaign->updateStatus(CampaignStatus::PAUSED);
|
|
$campaignRepo->save($pausedCampaign);
|
|
echo "✓ Campaign paused: {$pausedCampaign->status->value}" . PHP_EOL;
|
|
|
|
$resumedCampaign = $pausedCampaign->updateStatus(CampaignStatus::ACTIVE);
|
|
$campaignRepo->save($resumedCampaign);
|
|
echo "✓ Campaign resumed: {$resumedCampaign->status->value}" . PHP_EOL;
|
|
|
|
echo PHP_EOL;
|
|
|
|
// Test 8: Test registration status updates
|
|
echo "Test 8: Testing registration status updates..." . PHP_EOL;
|
|
|
|
foreach ($registrations as $index => $registration) {
|
|
// Simulate processing
|
|
$processed = $registration->process(time());
|
|
$registrationRepo->save($processed);
|
|
|
|
$num = $index + 1;
|
|
echo "✓ Registration {$num} processed" . PHP_EOL;
|
|
echo " Status: {$processed->status->value}" . PHP_EOL;
|
|
echo " Processed at: " . date('Y-m-d H:i:s', $processed->processedAt ?? time()) . PHP_EOL;
|
|
}
|
|
|
|
echo PHP_EOL;
|
|
|
|
// Test 9: Statistics and reporting
|
|
echo "Test 9: Campaign Statistics..." . PHP_EOL;
|
|
|
|
$allRegistrations = $registrationRepo->findByCampaign($campaign->id);
|
|
$stats = [
|
|
'total' => count($allRegistrations),
|
|
'by_status' => [],
|
|
'by_platform' => [],
|
|
];
|
|
|
|
foreach ($allRegistrations as $reg) {
|
|
$statusKey = $reg->status->value;
|
|
$platformKey = $reg->platform->value;
|
|
|
|
$stats['by_status'][$statusKey] = ($stats['by_status'][$statusKey] ?? 0) + 1;
|
|
$stats['by_platform'][$platformKey] = ($stats['by_platform'][$platformKey] ?? 0) + 1;
|
|
}
|
|
|
|
echo "Total Registrations: {$stats['total']}" . PHP_EOL;
|
|
echo "By Status:" . PHP_EOL;
|
|
foreach ($stats['by_status'] as $status => $count) {
|
|
echo " - {$status}: {$count}" . PHP_EOL;
|
|
}
|
|
echo "By Platform:" . PHP_EOL;
|
|
foreach ($stats['by_platform'] as $platform => $count) {
|
|
echo " - {$platform}: {$count}" . PHP_EOL;
|
|
}
|
|
|
|
echo PHP_EOL;
|
|
|
|
// Test 10: Cleanup (optional - comment out to keep test data)
|
|
echo "Test 10: Cleanup..." . PHP_EOL;
|
|
|
|
// Delete registrations (CASCADE will handle this automatically)
|
|
// Delete OAuth tokens
|
|
$tokenRepo->delete($spotifyToken);
|
|
$tokenRepo->delete($appleMusicToken);
|
|
$tokenRepo->delete($tidalToken);
|
|
echo "✓ OAuth tokens deleted" . PHP_EOL;
|
|
|
|
// Delete campaign (will CASCADE delete registrations)
|
|
$campaignRepo->delete($campaign->id);
|
|
echo "✓ Campaign deleted (registrations auto-deleted via CASCADE)" . PHP_EOL;
|
|
|
|
// Verify cleanup
|
|
$remainingRegistrations = $registrationRepo->findByCampaign($campaign->id);
|
|
echo "✓ Remaining registrations: " . count($remainingRegistrations) . " (should be 0)" . PHP_EOL;
|
|
|
|
echo PHP_EOL;
|
|
|
|
echo "=== All tests completed successfully! ===" . PHP_EOL;
|
|
echo PHP_EOL;
|
|
|
|
echo "Summary:" . PHP_EOL;
|
|
echo "✓ Campaign creation and management" . PHP_EOL;
|
|
echo "✓ OAuth token storage and retrieval" . PHP_EOL;
|
|
echo "✓ Pre-Save registration workflow" . PHP_EOL;
|
|
echo "✓ Multi-platform support (Spotify, Apple Music, Tidal)" . PHP_EOL;
|
|
echo "✓ Status transitions and updates" . PHP_EOL;
|
|
echo "✓ Statistics and reporting" . PHP_EOL;
|
|
echo "✓ Foreign key CASCADE cleanup" . PHP_EOL;
|
|
echo "✓ OAuth provider configuration" . PHP_EOL;
|
|
echo PHP_EOL;
|
|
|
|
echo "Next Steps:" . PHP_EOL;
|
|
echo "1. Configure OAuth credentials in .env file" . PHP_EOL;
|
|
echo "2. Test OAuth callback flows manually" . PHP_EOL;
|
|
echo "3. Test API endpoints via Postman/curl" . PHP_EOL;
|
|
echo "4. Test admin UI in browser" . PHP_EOL;
|
|
echo "5. Deploy Pre-Save Processor background jobs" . PHP_EOL;
|