null, 'post_id' => null, 'attachment_extension_id' => null, 'attachment_group_id' => null, 'user_id' => null, 'disk' => 'local', 'path' => 'attachments/test.txt', 'original_name' => 'test.txt', 'extension' => 'txt', 'mime_type' => 'text/plain', 'size_bytes' => 10, ]); $exitCode = Artisan::call('speedbb:cron'); expect($exitCode)->toBe(0); }); it('counts missing files for images', function (): void { Attachment::create([ 'thread_id' => null, 'post_id' => null, 'attachment_extension_id' => null, 'attachment_group_id' => null, 'user_id' => null, 'disk' => 'local', 'path' => 'attachments/missing.jpg', 'original_name' => 'missing.jpg', 'extension' => 'jpg', 'mime_type' => 'image/jpeg', 'size_bytes' => 10, ]); $exitCode = Artisan::call('speedbb:cron'); expect($exitCode)->toBe(0); }); it('skips when thumbnail already exists', function (): void { Storage::disk('local')->put('attachments/photo.jpg', 'image'); Storage::disk('local')->put('attachments/thumb.jpg', 'thumb'); Attachment::create([ 'thread_id' => null, 'post_id' => null, 'attachment_extension_id' => null, 'attachment_group_id' => null, 'user_id' => null, 'disk' => 'local', 'path' => 'attachments/photo.jpg', 'thumbnail_path' => 'attachments/thumb.jpg', 'original_name' => 'photo.jpg', 'extension' => 'jpg', 'mime_type' => 'image/jpeg', 'size_bytes' => 10, ]); $exitCode = Artisan::call('speedbb:cron'); expect($exitCode)->toBe(0); }); it('creates thumbnails in dry run mode', function (): void { Storage::disk('local')->put('attachments/photo.jpg', 'image'); Attachment::create([ 'thread_id' => null, 'post_id' => null, 'attachment_extension_id' => null, 'attachment_group_id' => null, 'user_id' => null, 'disk' => 'local', 'path' => 'attachments/photo.jpg', 'original_name' => 'photo.jpg', 'extension' => 'jpg', 'mime_type' => 'image/jpeg', 'size_bytes' => 10, ]); $exitCode = Artisan::call('speedbb:cron', ['--dry-run' => true]); expect($exitCode)->toBe(0); }); it('forces thumbnail regeneration and updates attachment when created', function (): void { Storage::disk('local')->put('attachments/photo.jpg', 'image'); Storage::disk('local')->put('attachments/thumb-old.jpg', 'old'); $attachment = Attachment::create([ 'thread_id' => null, 'post_id' => null, 'attachment_extension_id' => null, 'attachment_group_id' => null, 'user_id' => null, 'disk' => 'local', 'path' => 'attachments/photo.jpg', 'thumbnail_path' => 'attachments/thumb-old.jpg', 'original_name' => 'photo.jpg', 'extension' => 'jpg', 'mime_type' => 'image/jpeg', 'size_bytes' => 10, ]); $service = Mockery::mock(AttachmentThumbnailService::class); $service->shouldReceive('createForAttachment') ->once() ->andReturn([ 'path' => 'attachments/thumb-new.jpg', 'mime' => 'image/jpeg', 'size' => 123, ]); app()->instance(AttachmentThumbnailService::class, $service); $exitCode = Artisan::call('speedbb:cron', ['--force' => true]); expect($exitCode)->toBe(0); $attachment->refresh(); expect($attachment->thumbnail_path)->toBe('attachments/thumb-new.jpg'); expect($attachment->thumbnail_size_bytes)->toBe(123); }); it('skips when thumbnail creation fails', function (): void { Storage::disk('local')->put('attachments/photo.jpg', 'image'); Attachment::create([ 'thread_id' => null, 'post_id' => null, 'attachment_extension_id' => null, 'attachment_group_id' => null, 'user_id' => null, 'disk' => 'local', 'path' => 'attachments/photo.jpg', 'original_name' => 'photo.jpg', 'extension' => 'jpg', 'mime_type' => 'image/jpeg', 'size_bytes' => 10, ]); $service = Mockery::mock(AttachmentThumbnailService::class); $service->shouldReceive('createForAttachment')->once()->andReturnNull(); app()->instance(AttachmentThumbnailService::class, $service); $exitCode = Artisan::call('speedbb:cron'); expect($exitCode)->toBe(0); }); afterEach(function (): void { Mockery::close(); });