feat: 实现TCP Server

This commit is contained in:
zimoyin
2026-03-02 21:59:43 +08:00
parent 043306819b
commit a79dfae57d
144 changed files with 15785 additions and 140 deletions
+330
View File
@@ -0,0 +1,330 @@
<?php
namespace tests\flow;
use app\flow\ProcessEngine;
use app\flow\config\ProcessConfig;
/**
* 批次号一致性测试 - 跨机器部署场景
*/
class BatchConsistencyTest extends TestCase
{
/**
* 测试单机流程批次号一致性
*/
public function testSingleMachineBatchConsistency(): void
{
$engine = ProcessEngine::createStandard();
// 1. 开始清洗
$context1 = $this->createContext([
'readerType' => '清洗',
'currentStep' => '',
'endoscopeId' => '',
'morningWashed' => true,
]);
$result1 = $engine->execute($context1);
$this->assertSuccess($result1);
$batchNo = $result1->batchNo;
$this->assertNotEmpty($batchNo);
// 2. 漂洗 - 批次号应该一致
$context2 = $this->createContext([
'readerType' => '漂洗',
'currentStep' => '清洗',
'endoscopeId' => '',
'batchNo' => $batchNo,
'morningWashed' => true,
]);
$this->setStepTime($context2, '清洗', 400);
$result2 = $engine->execute($context2);
$this->assertSuccess($result2);
$this->assertEquals($batchNo, $result2->batchNo);
// 3. 消毒 - 批次号应该一致
$context3 = $this->createContext([
'readerType' => '消毒',
'currentStep' => '漂洗',
'endoscopeId' => '',
'batchNo' => $batchNo,
'morningWashed' => true,
]);
$this->setStepTime($context3, '漂洗', 200);
$result3 = $engine->execute($context3);
$this->assertSuccess($result3);
$this->assertEquals($batchNo, $result3->batchNo);
// 4. 终末漂洗 - 批次号应该一致
$context4 = $this->createContext([
'readerType' => '终末漂洗',
'currentStep' => '消毒',
'endoscopeId' => '',
'batchNo' => $batchNo,
'morningWashed' => true,
]);
$this->setStepTime($context4, '消毒', 400);
$result4 = $engine->execute($context4);
$this->assertSuccess($result4);
$this->assertEquals($batchNo, $result4->batchNo);
// 5. 干燥 - 批次号应该一致
$context5 = $this->createContext([
'readerType' => '干燥',
'currentStep' => '终末漂洗',
'endoscopeId' => '',
'batchNo' => $batchNo,
'morningWashed' => true,
]);
$this->setStepTime($context5, '终末漂洗', 200);
$result5 = $engine->execute($context5);
$this->assertSuccess($result5);
$this->assertEquals($batchNo, $result5->batchNo);
// 6. 结束 - 批次号应该一致
$context6 = $this->createContext([
'readerType' => '结束',
'currentStep' => '干燥',
'endoscopeId' => '',
'batchNo' => $batchNo,
'morningWashed' => true,
]);
$this->setStepTime($context6, '干燥', 300);
$result6 = $engine->execute($context6);
$this->assertSuccess($result6);
$this->assertEquals($batchNo, $result6->batchNo);
}
/**
* 测试多内镜批次号唯一性
*/
public function testMultiEndoscopeBatchUniqueness(): void
{
$engine = ProcessEngine::createStandard();
$batchNos = [];
// 模拟5个不同内镜同时开始清洗
for ($i = 1; $i <= 5; $i++) {
$context = $this->createContext([
'readerType' => '清洗',
'currentStep' => '',
'endoscopeId' => '',
'morningWashed' => true,
]);
$result = $engine->execute($context);
$this->assertSuccess($result);
$batchNos[] = $result->batchNo;
}
// 所有批次号应该唯一
$uniqueBatchNos = array_unique($batchNos);
$this->assertCount(5, $uniqueBatchNos);
}
/**
* 测试批次号格式正确性
*/
public function testBatchNoFormat(): void
{
$context = $this->createContext([
'endoscopeId' => '123',
]);
$batchNo = $context->generateBatchNo();
// 验证格式:YYYYMMDDHHMMSS + 内镜ID(6位) + 随机数(4位)
$this->assertEquals(24, strlen($batchNo));
$this->assertMatchesRegularExpression('/^\d{14}\d{6}\d{4}$/', $batchNo);
// 验证日期部分
$datePart = substr($batchNo, 0, 8);
$this->assertEquals(date('Ymd'), $datePart);
// 验证内镜ID部分
$endoscopePart = substr($batchNo, 14, 6);
$this->assertEquals('000123', $endoscopePart);
}
/**
* 测试批次号不随时间变化(同一流程内)
*/
public function testBatchNoStability(): void
{
$engine = ProcessEngine::createStandard();
$context1 = $this->createContext([
'readerType' => '清洗',
'currentStep' => '',
'endoscopeId' => '',
'morningWashed' => true,
]);
$result1 = $engine->execute($context1);
$batchNo1 = $result1->batchNo;
// 模拟时间流逝(实际测试中无法真正等待,所以直接验证)
$context2 = $this->createContext([
'readerType' => '漂洗',
'currentStep' => '清洗',
'endoscopeId' => '',
'batchNo' => $batchNo1,
'morningWashed' => true,
]);
$this->setStepTime($context2, '清洗', 400);
$result2 = $engine->execute($context2);
// 批次号应该保持不变
$this->assertEquals($batchNo1, $result2->batchNo);
}
/**
* 测试新流程生成新批次号
*/
public function testNewProcessGeneratesNewBatchNo(): void
{
$engine = ProcessEngine::createStandard();
// 第一个流程
$context1 = $this->createContext([
'readerType' => '清洗',
'currentStep' => '',
'endoscopeId' => '',
'morningWashed' => true,
]);
$result1 = $engine->execute($context1);
$batchNo1 = $result1->batchNo;
// 完成第一个流程
$contextEnd = $this->createContext([
'readerType' => '结束',
'currentStep' => '清洗',
'endoscopeId' => '',
'batchNo' => $batchNo1,
'morningWashed' => true,
]);
$engine->execute($contextEnd);
// 第二个流程(新流程)
$context2 = $this->createContext([
'readerType' => '清洗',
'currentStep' => '结束', // 上一步已结束
'endoscopeId' => '',
'morningWashed' => true,
]);
$result2 = $engine->execute($context2);
$batchNo2 = $result2->batchNo;
// 新流程应该有新的批次号
$this->assertNotEquals($batchNo1, $batchNo2);
}
/**
* 测试分布式场景下的批次号一致性(模拟)
*/
public function testDistributedBatchConsistency(): void
{
// 模拟机器A(清洗)
$engineA = ProcessEngine::createStandard();
$contextA = $this->createContext([
'readerType' => '清洗',
'currentStep' => '',
'endoscopeId' => '',
'morningWashed' => true,
]);
$resultA = $engineA->execute($contextA);
$batchNo = $resultA->batchNo;
// 模拟机器B(消毒)- 从数据库获取批次号
$engineB = ProcessEngine::createStandard();
$contextB = $this->createContext([
'readerType' => '消毒',
'currentStep' => '漂洗',
'endoscopeId' => '',
'batchNo' => $batchNo, // 从数据库获取的批次号
'morningWashed' => true,
]);
$resultB = $engineB->execute($contextB);
// 批次号应该一致
$this->assertEquals($batchNo, $resultB->batchNo);
}
/**
* 测试批次号在错误情况下的保持
*/
public function testBatchNoPreservedOnError(): void
{
$engine = ProcessEngine::createStandard();
// 开始清洗
$context1 = $this->createContext([
'readerType' => '清洗',
'currentStep' => '',
'endoscopeId' => '',
'morningWashed' => true,
]);
$result1 = $engine->execute($context1);
$batchNo = $result1->batchNo;
// 完成漂洗
$contextRinse = $this->createContext([
'readerType' => '漂洗',
'currentStep' => '清洗',
'endoscopeId' => '',
'batchNo' => $batchNo,
'morningWashed' => true,
]);
$this->setStepTime($contextRinse, '清洗', 400); // 清洗时间足够
$resultRinse = $engine->execute($contextRinse);
$this->assertSuccess($resultRinse);
// 尝试再次漂洗(重复刷漂洗读卡器,时间验证会失败)
$context2 = $this->createContext([
'readerType' => '漂洗',
'currentStep' => '漂洗', // 当前已经是漂洗
'endoscopeId' => '',
'batchNo' => $batchNo,
'morningWashed' => true,
]);
// 设置漂洗步骤的上次时间为刚刚(时间不足)
$context2->setStepLastTime('漂洗', date('Y-m-d H:i:s', time() - 30));
$result2 = $engine->execute($context2);
// 执行失败(重复步骤或时间不足),但批次号应该保持不变
$this->assertEquals($batchNo, $result2->batchNo);
}
/**
* 测试不同流程类型的批次号
*/
public function testBatchNoWithDifferentProcessTypes(): void
{
$engine = ProcessEngine::createStandard();
// 手工洗流程
$context1 = $this->createContext([
'readerType' => '清洗',
'currentStep' => '',
'endoscopeId' => '',
'morningWashed' => true,
]);
$result1 = $engine->execute($context1);
$batchNo1 = $result1->batchNo;
$this->assertEquals('手工洗', $result1->processType);
// 机洗流程
$engineMachine = ProcessEngine::createMachineWash();
$context2 = $this->createContext([
'readerType' => '机洗', // 使用机洗读卡器
'currentStep' => '',
'endoscopeId' => '',
'morningWashed' => true,
]);
$result2 = $engineMachine->execute($context2);
$batchNo2 = $result2->batchNo;
$this->assertEquals('机洗', $result2->processType);
// 不同流程的批次号应该不同
$this->assertNotEquals($batchNo1, $batchNo2);
}
}