set('storage-monitor.queue_health.thresholds', [ 'media-storage' => ['warning' => 10, 'critical' => 20], ]); config()->set('storage-monitor.queue_health.stalled_minutes', 5); config()->set('storage-monitor.queue_health.cache_minutes', 5); config()->set('storage-monitor.queue_health.pending_event_threshold', 1); config()->set('storage-monitor.queue_health.pending_event_minutes', 5); config()->set('storage-monitor.queue_health.failed_event_threshold', 1); config()->set('storage-monitor.queue_health.failed_event_minutes', 5); $manager = Mockery::mock(QueueManager::class); $connection = Mockery::mock(\Illuminate\Contracts\Queue\Queue::class); $manager->shouldReceive('connection')->with(config('queue.default'))->andReturn($connection); $connection->shouldReceive('size')->with('media-storage')->andReturn(25); $this->app->instance(QueueManager::class, $manager); DB::table('failed_jobs')->insert([ 'uuid' => (string) Str::uuid(), 'connection' => 'sync', 'queue' => 'media-storage', 'payload' => '{}', 'exception' => 'Test failure', 'failed_at' => now(), ]); $target = MediaStorageTarget::create([ 'key' => 'local-hot', 'name' => 'Local Hot', 'driver' => 'local', 'config' => ['monitor_path' => storage_path('app')], 'is_hot' => true, 'is_default' => true, 'is_active' => true, 'priority' => 100, ]); $tenant = Tenant::factory()->create(); $event = Event::factory()->for($tenant)->create(['status' => 'published']); $asset = EventMediaAsset::create([ 'event_id' => $event->id, 'media_storage_target_id' => $target->id, 'variant' => 'original', 'disk' => 'local-hot', 'path' => 'events/'.$event->id.'/pending.jpg', 'size_bytes' => 512, 'status' => 'pending', ]); EventMediaAsset::whereKey($asset->id)->update([ 'created_at' => now()->subMinutes(10), 'updated_at' => now()->subMinutes(10), ]); EventMediaAsset::create([ 'event_id' => $event->id, 'media_storage_target_id' => $target->id, 'variant' => 'original', 'disk' => 'local-hot', 'path' => 'events/'.$event->id.'/failed.jpg', 'size_bytes' => 256, 'status' => 'failed', ]); $this->artisan('storage:check-upload-queues') ->expectsOutput('Checked 1 queue(s); 3 alert(s).') ->assertExitCode(0); $snapshot = Cache::get('storage:queue-health:last'); $this->assertNotNull($snapshot); $this->assertSame('critical', $snapshot['queues'][0]['severity']); $this->assertGreaterThanOrEqual(1, count($snapshot['alerts'])); $this->assertDatabaseHas('guest_notifications', [ 'event_id' => $event->id, 'type' => GuestNotificationType::UPLOAD_ALERT->value, ]); $this->assertDatabaseHas('guest_notifications', [ 'event_id' => $event->id, 'type' => GuestNotificationType::SUPPORT_TIP->value, ]); } }