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

157 lines
5.4 KiB
PHP

<?php
declare(strict_types=1);
use App\Application\GraphQL\NotificationSubscriptions;
use App\Framework\GraphQL\Attributes\GraphQLSubscription;
use App\Framework\GraphQL\Schema\SchemaBuilder;
use App\Framework\GraphQL\Subscriptions\SubscriptionId;
use App\Framework\GraphQL\Subscriptions\SubscriptionRegistry;
use App\Framework\Http\WebSocketConnectionInterface;
describe('GraphQL Subscriptions', function () {
beforeEach(function () {
$this->registry = new SubscriptionRegistry();
// Create mock WebSocket connection using Mockery
$this->connection = Mockery::mock(WebSocketConnectionInterface::class);
$this->connection->shouldReceive('getId')->andReturn('test-connection-1');
$this->connection->shouldReceive('isConnected')->andReturn(true);
$this->connection->shouldReceive('sendJson')->andReturnTrue();
$this->connection->shouldReceive('setAttribute')->andReturnNull();
$this->connection->shouldReceive('getAttribute')->andReturn(null);
$this->sentMessages = [];
});
it('can register and retrieve subscriptions', function () {
$id = SubscriptionId::generate();
$this->registry->register(
$id,
$this->connection,
'notificationReceived',
['userId' => '123']
);
$subscriptions = $this->registry->getByName('notificationReceived');
expect($subscriptions)->toHaveCount(1);
expect($subscriptions[0]['id']->toString())->toBe($id->toString());
expect($subscriptions[0]['variables']['userId'])->toBe('123');
});
it('can unregister subscriptions', function () {
$id = SubscriptionId::generate();
$this->registry->register(
$id,
$this->connection,
'notificationReceived',
['userId' => '123']
);
expect($this->registry->getByName('notificationReceived'))->toHaveCount(1);
$this->registry->unregister($id);
expect($this->registry->getByName('notificationReceived'))->toHaveCount(0);
});
it('can cleanup subscriptions by connection', function () {
$id1 = SubscriptionId::generate();
$id2 = SubscriptionId::generate();
$this->registry->register(
$id1,
$this->connection,
'notificationReceived',
['userId' => '123']
);
$this->registry->register(
$id2,
$this->connection,
'orderStatusChanged',
['orderId' => 'order-1']
);
expect($this->registry->getByName('notificationReceived'))->toHaveCount(1);
expect($this->registry->getByName('orderStatusChanged'))->toHaveCount(1);
$this->registry->removeByConnection($this->connection);
expect($this->registry->getByName('notificationReceived'))->toHaveCount(0);
expect($this->registry->getByName('orderStatusChanged'))->toHaveCount(0);
});
it('provides subscription statistics', function () {
$this->registry->register(
SubscriptionId::generate(),
$this->connection,
'notificationReceived',
['userId' => '123']
);
$this->registry->register(
SubscriptionId::generate(),
$this->connection,
'orderStatusChanged',
['orderId' => 'order-1']
);
$stats = $this->registry->getStats();
expect($stats['total_subscriptions'])->toBe(2);
expect($stats['unique_connections'])->toBe(1);
expect($stats['subscriptions_by_type']['notificationReceived'])->toBe(1);
expect($stats['subscriptions_by_type']['orderStatusChanged'])->toBe(1);
});
it('discovers GraphQLSubscription classes', function () {
$reflection = new ReflectionClass(NotificationSubscriptions::class);
$attribute = $reflection->getAttributes(GraphQLSubscription::class)[0] ?? null;
expect($attribute)->not->toBeNull();
$instance = $attribute->newInstance();
expect($instance->description)->toBe('Real-time notification subscriptions');
});
it('builds subscription fields in schema', function () {
// Create simple container for testing
$container = new \App\Framework\DI\DefaultContainer();
$typeResolver = new \App\Framework\GraphQL\Schema\TypeResolver();
$schemaBuilder = new SchemaBuilder($container, $typeResolver);
$schema = $schemaBuilder->build([
NotificationSubscriptions::class,
]);
expect($schema->subscriptions)->toHaveCount(3);
expect($schema->getSubscription('notificationReceived'))->not->toBeNull();
expect($schema->getSubscription('orderStatusChanged'))->not->toBeNull();
expect($schema->getSubscription('systemAnnouncement'))->not->toBeNull();
});
it('generates correct SDL for subscriptions', function () {
// Create simple container for testing
$container = new \App\Framework\DI\DefaultContainer();
$typeResolver = new \App\Framework\GraphQL\Schema\TypeResolver();
$schemaBuilder = new SchemaBuilder($container, $typeResolver);
$schema = $schemaBuilder->build([
NotificationSubscriptions::class,
]);
$sdl = $schema->toSDL();
expect($sdl)->toContain('type Subscription {');
expect($sdl)->toContain('notificationReceived');
expect($sdl)->toContain('orderStatusChanged');
expect($sdl)->toContain('systemAnnouncement');
});
});