Files
KnowledgeBase/tests/Feature/SwooleQueueCompatibilityTest.php

276 lines
8.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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);
}
}