feat: 新增 Docker 部署支持、Swoole/Octane 集成及相关优化
- 添加 Dockerfile 与多套 docker-compose 配置(开发/生产环境) - 集成 Laravel Octane (Swoole) 提升性能 - 新增健康检查、监控脚本及部署文档 - 新增 Docker 镜像离线导入包(MySQL/Redis/Meilisearch) - 优化文档转换、预览服务及队列任务 - 添加 CreateAdminUser 命令与路由健康检查接口 - 新增 Swoole 队列兼容性测试套件 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
196
tests/Feature/QueueSystemValidationTest.php
Normal file
196
tests/Feature/QueueSystemValidationTest.php
Normal file
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Jobs\ConvertDocumentToMarkdown;
|
||||
use App\Models\Document;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* 队列系统验证测试
|
||||
*
|
||||
* 验证队列系统在 Swoole 环境下的基本功能
|
||||
*/
|
||||
class QueueSystemValidationTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// 禁用搜索功能以避免 Meilisearch 连接问题
|
||||
config(['scout.driver' => 'null']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试队列系统基本功能
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function test_queue_system_basic_functionality()
|
||||
{
|
||||
// 验证队列配置
|
||||
$this->assertNotEmpty(config('queue.default'), '队列默认连接未配置');
|
||||
|
||||
// 验证队列连接配置
|
||||
$defaultConnection = config('queue.default');
|
||||
$connectionConfig = config("queue.connections.{$defaultConnection}");
|
||||
$this->assertIsArray($connectionConfig, '队列连接配置无效');
|
||||
$this->assertArrayHasKey('driver', $connectionConfig, '队列驱动未配置');
|
||||
|
||||
// 验证队列命令可用性
|
||||
$exitCode = Artisan::call('queue:work', ['--help' => true]);
|
||||
$this->assertEquals(0, $exitCode, '队列工作命令不可用');
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试文档转换任务的基本功能
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function test_document_conversion_job_basic_functionality()
|
||||
{
|
||||
// 创建测试数据
|
||||
$user = User::factory()->create();
|
||||
$document = Document::factory()->create([
|
||||
'uploaded_by' => $user->id,
|
||||
'title' => '验证测试文档',
|
||||
]);
|
||||
|
||||
// 使用模拟队列
|
||||
Queue::fake();
|
||||
|
||||
// 分发任务
|
||||
ConvertDocumentToMarkdown::dispatch($document);
|
||||
|
||||
// 验证任务已分发
|
||||
Queue::assertPushed(ConvertDocumentToMarkdown::class);
|
||||
|
||||
// 验证任务配置
|
||||
$job = new ConvertDocumentToMarkdown($document);
|
||||
$this->assertIsNumeric($job->tries, '任务重试次数配置无效');
|
||||
$this->assertIsNumeric($job->timeout, '任务超时配置无效');
|
||||
$this->assertIsNumeric($job->backoff, '任务重试延迟配置无效');
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 Swoole 与队列的兼容性配置
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function test_swoole_queue_compatibility_configuration()
|
||||
{
|
||||
// 验证 Octane 配置
|
||||
$octaneServer = config('octane.server');
|
||||
$this->assertEquals('swoole', $octaneServer, 'Octane 服务器未配置为 Swoole');
|
||||
|
||||
// 验证 Octane 任务工作进程配置
|
||||
$taskWorkers = config('octane.task_workers', env('OCTANE_TASK_WORKERS'));
|
||||
$this->assertIsNumeric($taskWorkers, 'Octane 任务工作进程数量配置无效');
|
||||
$this->assertGreaterThan(0, $taskWorkers, 'Octane 任务工作进程数量必须大于 0');
|
||||
|
||||
// 验证队列与 Swoole 的兼容性
|
||||
$queueConnection = config('queue.default');
|
||||
$queueDriver = config("queue.connections.{$queueConnection}.driver");
|
||||
$supportedDrivers = ['database', 'redis', 'sync'];
|
||||
|
||||
$this->assertContains(
|
||||
$queueDriver,
|
||||
$supportedDrivers,
|
||||
"队列驱动 {$queueDriver} 可能与 Swoole 不兼容"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试队列任务的内存管理
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function test_queue_memory_management()
|
||||
{
|
||||
$initialMemory = memory_get_usage();
|
||||
|
||||
// 创建多个任务实例
|
||||
$user = User::factory()->create();
|
||||
$jobs = [];
|
||||
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$document = Document::factory()->create(['uploaded_by' => $user->id]);
|
||||
$jobs[] = new ConvertDocumentToMarkdown($document);
|
||||
}
|
||||
|
||||
// 清理任务实例
|
||||
unset($jobs);
|
||||
gc_collect_cycles();
|
||||
|
||||
$finalMemory = memory_get_usage();
|
||||
$memoryIncrease = $finalMemory - $initialMemory;
|
||||
|
||||
// 验证内存使用合理
|
||||
$this->assertLessThan(5 * 1024 * 1024, $memoryIncrease, '队列任务内存使用过多');
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试队列错误处理配置
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function test_queue_error_handling_configuration()
|
||||
{
|
||||
// 验证失败队列配置
|
||||
$failedDriver = config('queue.failed.driver');
|
||||
$this->assertNotEmpty($failedDriver, '失败队列驱动未配置');
|
||||
|
||||
// 验证文档转换相关配置
|
||||
$retryTimes = config('documents.conversion.retry_times', 3);
|
||||
$this->assertIsNumeric($retryTimes, '队列重试次数配置无效');
|
||||
$this->assertGreaterThan(0, $retryTimes, '队列重试次数必须大于 0');
|
||||
|
||||
$retryDelay = config('documents.conversion.retry_delay', 60);
|
||||
$this->assertIsNumeric($retryDelay, '队列重试延迟配置无效');
|
||||
$this->assertGreaterThanOrEqual(0, $retryDelay, '队列重试延迟不能为负数');
|
||||
|
||||
$timeout = config('documents.conversion.timeout', 300);
|
||||
$this->assertIsNumeric($timeout, '队列任务超时配置无效');
|
||||
$this->assertGreaterThan(0, $timeout, '队列任务超时时间必须大于 0');
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试队列系统的整体健康状态
|
||||
*
|
||||
* @test
|
||||
*/
|
||||
public function test_queue_system_health()
|
||||
{
|
||||
// 验证数据库表存在(如果使用数据库队列)
|
||||
if (config('queue.default') === 'database') {
|
||||
$this->assertTrue(\Schema::hasTable('jobs'), '队列任务表不存在');
|
||||
$this->assertTrue(\Schema::hasTable('failed_jobs'), '失败任务表不存在');
|
||||
}
|
||||
|
||||
// 验证队列重启命令
|
||||
$exitCode = Artisan::call('queue:restart');
|
||||
$this->assertEquals(0, $exitCode, '队列重启命令执行失败');
|
||||
|
||||
// 验证基本的队列操作
|
||||
Queue::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
$document = Document::factory()->create(['uploaded_by' => $user->id]);
|
||||
|
||||
// 测试任务分发
|
||||
ConvertDocumentToMarkdown::dispatch($document);
|
||||
Queue::assertPushed(ConvertDocumentToMarkdown::class);
|
||||
|
||||
// 测试任务序列化
|
||||
$job = new ConvertDocumentToMarkdown($document);
|
||||
$serialized = serialize($job);
|
||||
$unserialized = unserialize($serialized);
|
||||
$this->assertInstanceOf(ConvertDocumentToMarkdown::class, $unserialized);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user