Files
michaelschiemer/tests/Feature/NotificationSystemTest.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

192 lines
6.4 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\EventBus\EventBus;
use App\Framework\Notification\Notification;
use App\Framework\Notification\NotificationDispatcher;
use App\Framework\Notification\ValueObjects\NotificationChannel;
use App\Framework\Notification\ValueObjects\NotificationPriority;
use App\Framework\Notification\ValueObjects\NotificationType;
use App\Framework\Queue\InMemoryQueue;
// Mock EventBus for testing
class MockEventBus implements EventBus
{
public array $dispatchedEvents = [];
public function dispatch(object $event): void
{
$this->dispatchedEvents[] = $event;
}
}
describe('Notification System', function () {
beforeEach(function () {
// Setup test dependencies
$this->queue = new InMemoryQueue();
$this->eventBus = new MockEventBus();
});
it('can create a notification with required fields', function () {
$notification = Notification::create(
'user-123',
NotificationType::system(),
'System Update',
'Your system has been updated',
NotificationChannel::DATABASE,
NotificationChannel::EMAIL
);
expect($notification->recipientId)->toBe('user-123');
expect($notification->title)->toBe('System Update');
expect($notification->body)->toBe('Your system has been updated');
expect($notification->channels)->toHaveCount(2);
expect($notification->priority)->toBe(NotificationPriority::NORMAL);
});
it('can add action to notification', function () {
$notification = Notification::create(
'user-123',
NotificationType::system(),
'Action Required',
'Please review your settings',
NotificationChannel::DATABASE
)->withAction('/settings', 'Review Settings');
expect($notification->hasAction())->toBeTrue();
expect($notification->actionUrl)->toBe('/settings');
expect($notification->actionLabel)->toBe('Review Settings');
});
it('can set priority on notification', function () {
$notification = Notification::create(
'user-123',
NotificationType::security(),
'Security Alert',
'Unusual login detected',
NotificationChannel::DATABASE,
NotificationChannel::EMAIL
)->withPriority(NotificationPriority::URGENT);
expect($notification->priority)->toBe(NotificationPriority::URGENT);
expect($notification->priority->shouldInterruptUser())->toBeTrue();
});
it('can add custom data to notification', function () {
$notification = Notification::create(
'user-123',
NotificationType::social(),
'New Follower',
'John Doe started following you',
NotificationChannel::DATABASE
)->withData([
'follower_id' => 'user-456',
'follower_name' => 'John Doe',
'follower_avatar' => '/avatars/456.jpg',
]);
expect($notification->data)->toHaveKey('follower_id');
expect($notification->data['follower_name'])->toBe('John Doe');
});
it('validates required fields', function () {
try {
Notification::create(
'',
NotificationType::system(),
'Test',
'Test body',
NotificationChannel::DATABASE
);
expect(true)->toBeFalse('Should have thrown exception');
} catch (\InvalidArgumentException $e) {
expect($e->getMessage())->toContain('Recipient ID');
}
});
it('requires at least one channel', function () {
try {
new Notification(
id: \App\Framework\Notification\ValueObjects\NotificationId::generate(),
recipientId: 'user-123',
type: NotificationType::system(),
title: 'Test',
body: 'Test body',
data: [],
channels: [], // Empty channels
priority: NotificationPriority::NORMAL,
status: \App\Framework\Notification\ValueObjects\NotificationStatus::PENDING,
createdAt: \App\Framework\Core\ValueObjects\Timestamp::now()
);
expect(true)->toBeFalse('Should have thrown exception');
} catch (\InvalidArgumentException $e) {
expect($e->getMessage())->toContain('channel');
}
});
it('can mark notification as read', function () {
$notification = Notification::create(
'user-123',
NotificationType::system(),
'Test',
'Test body',
NotificationChannel::DATABASE
);
expect($notification->isRead())->toBeFalse();
$readNotification = $notification->markAsRead();
expect($readNotification->isRead())->toBeTrue();
expect($readNotification->readAt)->toBeInstanceOf(\App\Framework\Core\ValueObjects\Timestamp::class);
});
it('can convert notification to array', function () {
$notification = Notification::create(
'user-123',
NotificationType::transactional(),
'Payment Received',
'Your payment of $50 was processed',
NotificationChannel::DATABASE,
NotificationChannel::EMAIL
)->withData(['amount' => 50, 'currency' => 'USD']);
$array = $notification->toArray();
expect($array)->toHaveKey('id');
expect($array)->toHaveKey('recipient_id');
expect($array['title'])->toBe('Payment Received');
expect($array['data']['amount'])->toBe(50);
expect($array['channels'])->toContain('database');
expect($array['channels'])->toContain('email');
});
});
describe('Notification Dispatcher', function () {
it('can queue notification for async delivery', function () {
$queue = new InMemoryQueue();
$eventBus = new MockEventBus();
$dispatcher = new NotificationDispatcher(
channels: [],
queue: $queue,
eventBus: $eventBus
);
$notification = Notification::create(
'user-123',
NotificationType::system(),
'Test',
'Test body',
NotificationChannel::DATABASE
);
expect($queue->size())->toBe(0);
$dispatcher->sendLater($notification);
expect($queue->size())->toBe(1);
});
});