276 lines
8.6 KiB
PHP
276 lines
8.6 KiB
PHP
<?php
|
||
|
||
namespace Tests\Feature;
|
||
|
||
use App\Jobs\ConvertDocumentToMarkdown;
|
||
use App\Models\Document;
|
||
use App\Models\User;
|
||
use App\Services\DocumentConversionService;
|
||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||
use Illuminate\Support\Facades\Queue;
|
||
use Illuminate\Support\Facades\Storage;
|
||
use Tests\TestCase;
|
||
|
||
/**
|
||
* Swoole 队列系统兼容性测试
|
||
*
|
||
* 验证现有队列任务在 Swoole 环境下的正常运行
|
||
*/
|
||
class SwooleQueueCompatibilityTest extends TestCase
|
||
{
|
||
use RefreshDatabase;
|
||
|
||
protected function setUp(): void
|
||
{
|
||
parent::setUp();
|
||
|
||
// 设置测试存储磁盘
|
||
Storage::fake('documents');
|
||
Storage::fake('markdown');
|
||
|
||
// 禁用搜索功能以避免 Meilisearch 连接问题
|
||
config(['scout.driver' => 'null']);
|
||
}
|
||
|
||
/**
|
||
* 测试文档转换队列任务可以正常分发
|
||
*
|
||
* @test
|
||
*/
|
||
public function test_document_conversion_job_can_be_dispatched()
|
||
{
|
||
// 创建测试用户和文档
|
||
$user = User::factory()->create();
|
||
$document = Document::factory()->create([
|
||
'uploaded_by' => $user->id,
|
||
'title' => '测试文档',
|
||
'file_path' => 'test-document.docx',
|
||
]);
|
||
|
||
// 模拟队列
|
||
Queue::fake();
|
||
|
||
// 分发队列任务
|
||
ConvertDocumentToMarkdown::dispatch($document);
|
||
|
||
// 验证任务已被分发
|
||
Queue::assertPushed(ConvertDocumentToMarkdown::class, function ($job) use ($document) {
|
||
// 使用反射来访问受保护的属性
|
||
$reflection = new \ReflectionClass($job);
|
||
$documentProperty = $reflection->getProperty('document');
|
||
$documentProperty->setAccessible(true);
|
||
$jobDocument = $documentProperty->getValue($job);
|
||
return $jobDocument->id === $document->id;
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 测试队列任务在 Swoole 环境下的执行
|
||
*
|
||
* @test
|
||
*/
|
||
public function test_queue_job_execution_in_swoole_environment()
|
||
{
|
||
// 创建测试用户和文档
|
||
$user = User::factory()->create();
|
||
$document = Document::factory()->create([
|
||
'uploaded_by' => $user->id,
|
||
'title' => '测试文档转换',
|
||
'file_path' => 'test-conversion.docx',
|
||
]);
|
||
|
||
// 创建模拟的文档文件
|
||
Storage::disk('documents')->put($document->file_path, 'test content');
|
||
|
||
// 模拟转换服务
|
||
$conversionService = $this->createMock(DocumentConversionService::class);
|
||
$conversionService->expects($this->once())
|
||
->method('convertToMarkdown')
|
||
->with($document)
|
||
->willReturn([
|
||
'markdown' => '# 测试文档\n\n这是测试内容',
|
||
'tempDir' => '/tmp/test',
|
||
]);
|
||
|
||
$conversionService->expects($this->once())
|
||
->method('saveMarkdownToFile')
|
||
->willReturn('markdown/test-document.md');
|
||
|
||
$conversionService->expects($this->once())
|
||
->method('updateDocumentMarkdown');
|
||
|
||
$this->app->instance(DocumentConversionService::class, $conversionService);
|
||
|
||
// 执行队列任务
|
||
$job = new ConvertDocumentToMarkdown($document);
|
||
$job->handle($conversionService);
|
||
|
||
// 验证任务执行成功(没有抛出异常)
|
||
$this->assertTrue(true);
|
||
}
|
||
|
||
/**
|
||
* 测试队列任务失败处理
|
||
*
|
||
* @test
|
||
*/
|
||
public function test_queue_job_failure_handling()
|
||
{
|
||
// 创建测试用户和文档
|
||
$user = User::factory()->create();
|
||
$document = Document::factory()->create([
|
||
'uploaded_by' => $user->id,
|
||
'title' => '失败测试文档',
|
||
'file_path' => 'fail-test.docx',
|
||
]);
|
||
|
||
// 模拟转换服务抛出异常
|
||
$conversionService = $this->createMock(DocumentConversionService::class);
|
||
$conversionService->expects($this->once())
|
||
->method('convertToMarkdown')
|
||
->willThrowException(new \Exception('转换失败'));
|
||
|
||
$this->app->instance(DocumentConversionService::class, $conversionService);
|
||
|
||
// 执行队列任务并期望异常
|
||
$job = new ConvertDocumentToMarkdown($document);
|
||
|
||
$this->expectException(\Exception::class);
|
||
$this->expectExceptionMessage('转换失败');
|
||
|
||
$job->handle($conversionService);
|
||
}
|
||
|
||
/**
|
||
* 测试队列任务可以包装底层 Throwable
|
||
*
|
||
* @test
|
||
*/
|
||
public function test_queue_job_wraps_throwables_from_conversion_service()
|
||
{
|
||
$user = User::factory()->create();
|
||
$document = Document::factory()->create([
|
||
'uploaded_by' => $user->id,
|
||
'title' => 'Throwable 测试文档',
|
||
'file_path' => 'throwable-test.docx',
|
||
]);
|
||
|
||
$conversionService = $this->createMock(DocumentConversionService::class);
|
||
$conversionService->expects($this->once())
|
||
->method('convertToMarkdown')
|
||
->willThrowException(new \Error('底层转换错误'));
|
||
|
||
$this->app->instance(DocumentConversionService::class, $conversionService);
|
||
|
||
$job = new ConvertDocumentToMarkdown($document);
|
||
|
||
$this->expectException(\RuntimeException::class);
|
||
$this->expectExceptionMessage('底层转换错误');
|
||
|
||
$job->handle($conversionService);
|
||
}
|
||
|
||
/**
|
||
* 测试队列任务的重试机制
|
||
*
|
||
* @test
|
||
*/
|
||
public function test_queue_job_retry_mechanism()
|
||
{
|
||
// 创建测试文档
|
||
$user = User::factory()->create();
|
||
$document = Document::factory()->create([
|
||
'uploaded_by' => $user->id,
|
||
'title' => '重试测试文档',
|
||
]);
|
||
|
||
// 创建队列任务实例
|
||
$job = new ConvertDocumentToMarkdown($document);
|
||
|
||
// 验证重试配置
|
||
$this->assertEquals(config('documents.conversion.retry_times', 3), $job->tries);
|
||
$this->assertEquals(config('documents.conversion.timeout', 300), $job->timeout);
|
||
$this->assertEquals(config('documents.conversion.retry_delay', 60), $job->backoff);
|
||
}
|
||
|
||
/**
|
||
* 测试队列连接配置
|
||
*
|
||
* @test
|
||
*/
|
||
public function test_queue_connection_configuration()
|
||
{
|
||
// 验证队列连接配置
|
||
$defaultConnection = config('queue.default');
|
||
$this->assertNotEmpty($defaultConnection);
|
||
|
||
// 验证数据库队列连接配置
|
||
$databaseConfig = config('queue.connections.database');
|
||
$this->assertIsArray($databaseConfig);
|
||
$this->assertEquals('database', $databaseConfig['driver']);
|
||
$this->assertEquals('jobs', $databaseConfig['table']);
|
||
}
|
||
|
||
/**
|
||
* 测试队列在 Swoole 环境下的内存管理
|
||
*
|
||
* @test
|
||
*/
|
||
public function test_queue_memory_management_in_swoole()
|
||
{
|
||
// 获取初始内存使用量
|
||
$initialMemory = memory_get_usage();
|
||
|
||
// 创建多个队列任务
|
||
$user = User::factory()->create();
|
||
$documents = Document::factory()->count(5)->create(['uploaded_by' => $user->id]);
|
||
|
||
Queue::fake();
|
||
|
||
// 分发多个任务
|
||
foreach ($documents as $document) {
|
||
ConvertDocumentToMarkdown::dispatch($document);
|
||
}
|
||
|
||
// 验证任务都被分发
|
||
Queue::assertPushed(ConvertDocumentToMarkdown::class, 5);
|
||
|
||
// 检查内存使用是否在合理范围内
|
||
$currentMemory = memory_get_usage();
|
||
$memoryIncrease = $currentMemory - $initialMemory;
|
||
|
||
// 内存增长应该在合理范围内(小于 10MB)
|
||
$this->assertLessThan(10 * 1024 * 1024, $memoryIncrease, '队列任务内存使用过多');
|
||
}
|
||
|
||
/**
|
||
* 测试队列任务的序列化和反序列化
|
||
*
|
||
* @test
|
||
*/
|
||
public function test_queue_job_serialization()
|
||
{
|
||
// 创建测试文档
|
||
$user = User::factory()->create();
|
||
$document = Document::factory()->create(['uploaded_by' => $user->id]);
|
||
|
||
// 创建队列任务
|
||
$job = new ConvertDocumentToMarkdown($document);
|
||
|
||
// 序列化任务
|
||
$serialized = serialize($job);
|
||
$this->assertIsString($serialized);
|
||
|
||
// 反序列化任务
|
||
$unserialized = unserialize($serialized);
|
||
$this->assertInstanceOf(ConvertDocumentToMarkdown::class, $unserialized);
|
||
|
||
// 使用反射来访问受保护的属性
|
||
$reflection = new \ReflectionClass($unserialized);
|
||
$documentProperty = $reflection->getProperty('document');
|
||
$documentProperty->setAccessible(true);
|
||
$jobDocument = $documentProperty->getValue($unserialized);
|
||
$this->assertEquals($document->id, $jobDocument->id);
|
||
}
|
||
}
|