Files
fotospiel-app/tests/Feature/Console/CheckUploadQueuesCommandTest.php
2025-11-12 20:42:46 +01:00

106 lines
3.9 KiB
PHP

<?php
namespace Tests\Feature\Console;
use App\Enums\GuestNotificationType;
use App\Models\Event;
use App\Models\EventMediaAsset;
use App\Models\MediaStorageTarget;
use App\Models\Tenant;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Queue\QueueManager;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Mockery;
use Tests\TestCase;
class CheckUploadQueuesCommandTest extends TestCase
{
use RefreshDatabase;
public function test_queue_health_snapshot_detects_alerts(): void
{
config()->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,
]);
}
}