feat: 实现TCP Server
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace tests\flow\nodes;
|
||||
|
||||
use tests\flow\TestCase;
|
||||
use app\flow\nodes\DisinfectNode;
|
||||
use app\flow\DbOperationType;
|
||||
|
||||
/**
|
||||
* 消毒节点单元测试
|
||||
*/
|
||||
class DisinfectNodeTest extends TestCase
|
||||
{
|
||||
protected DisinfectNode $node;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->node = new DisinfectNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试节点名称和编码
|
||||
*/
|
||||
public function testNodeIdentity(): void
|
||||
{
|
||||
$this->assertEquals('消毒', $this->node->getName());
|
||||
$this->assertEquals('消毒', $this->node->getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试漂洗后可以刷消毒
|
||||
*/
|
||||
public function testCanHandleAfterRinse(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '消毒',
|
||||
'currentStep' => '漂洗',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试终末漂洗后禁止刷消毒
|
||||
*/
|
||||
public function testCanHandleAfterFinalRinse(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '消毒',
|
||||
'currentStep' => '终末漂洗',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试清洗后禁止直接刷消毒
|
||||
*/
|
||||
public function testCanHandleAfterWash(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '消毒',
|
||||
'currentStep' => '清洗',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试不能处理非消毒读卡器
|
||||
*/
|
||||
public function testCannotHandleNonDisinfectReader(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '清洗',
|
||||
'currentStep' => '漂洗',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试消毒后不能立即刷消毒
|
||||
*/
|
||||
public function testCannotHandleAfterDisinfect(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '消毒',
|
||||
'currentStep' => '消毒',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试处理流程
|
||||
*/
|
||||
public function testHandleProcess(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '消毒',
|
||||
'currentStep' => '漂洗',
|
||||
]);
|
||||
|
||||
$result = $this->node->handle($context);
|
||||
|
||||
$this->assertSuccess($result);
|
||||
$this->assertStep($result, '消毒');
|
||||
$this->assertNotNull($result->getStepLastTime('消毒'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试数据库操作标记
|
||||
*/
|
||||
public function testDatabaseOperationFlags(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '消毒',
|
||||
'currentStep' => '漂洗',
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertTrue($context->needDatabaseOperation);
|
||||
$this->assertEquals(DbOperationType::INSERT, $context->dbOperation);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 WebSocket 通知标记
|
||||
*/
|
||||
public function testWebSocketNotifyFlag(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '消毒',
|
||||
'currentStep' => '漂洗',
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertTrue($context->needWebSocketNotify);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
namespace tests\flow\nodes;
|
||||
|
||||
use tests\flow\TestCase;
|
||||
use app\flow\nodes\DryNode;
|
||||
use app\flow\DbOperationType;
|
||||
|
||||
/**
|
||||
* 干燥节点单元测试
|
||||
*/
|
||||
class DryNodeTest extends TestCase
|
||||
{
|
||||
protected DryNode $node;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->node = new DryNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试节点名称和编码
|
||||
*/
|
||||
public function testNodeIdentity(): void
|
||||
{
|
||||
$this->assertEquals('干燥', $this->node->getName());
|
||||
$this->assertEquals('干燥', $this->node->getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试终末漂洗后可以刷干燥
|
||||
*/
|
||||
public function testCanHandleAfterFinalRinse(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '干燥',
|
||||
'currentStep' => '终末漂洗',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试消毒后可以直接刷干燥(跳过终末漂洗)
|
||||
*/
|
||||
public function testCanHandleAfterDisinfect(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '干燥',
|
||||
'currentStep' => '消毒'
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试漂洗后不能直接刷干燥
|
||||
*/
|
||||
public function testCannotHandleAfterRinse(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '干燥',
|
||||
'currentStep' => '漂洗',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试不能处理非干燥读卡器
|
||||
*/
|
||||
public function testCannotHandleNonDryReader(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '清洗',
|
||||
'currentStep' => '终末漂洗',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试干燥后不能立即刷干燥
|
||||
*/
|
||||
public function testCannotHandleAfterDry(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '干燥',
|
||||
'currentStep' => '干燥',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试处理流程
|
||||
*/
|
||||
public function testHandleProcess(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '干燥',
|
||||
'currentStep' => '终末漂洗',
|
||||
]);
|
||||
|
||||
$result = $this->node->handle($context);
|
||||
|
||||
$this->assertSuccess($result);
|
||||
$this->assertStep($result, '干燥');
|
||||
$this->assertNotNull($result->getStepLastTime('干燥'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试数据库操作标记
|
||||
*/
|
||||
public function testDatabaseOperationFlags(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '干燥',
|
||||
'currentStep' => '终末漂洗',
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertTrue($context->needDatabaseOperation);
|
||||
$this->assertEquals(DbOperationType::INSERT, $context->dbOperation);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 WebSocket 通知标记
|
||||
*/
|
||||
public function testWebSocketNotifyFlag(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '干燥',
|
||||
'currentStep' => '终末漂洗',
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertTrue($context->needWebSocketNotify);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试保持现有批次号
|
||||
*/
|
||||
public function testKeepExistingBatchNo(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '干燥',
|
||||
'currentStep' => '终末漂洗',
|
||||
'batchNo' => '202603031200000000010001',
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertEquals('202603031200000000010001', $context->batchNo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
namespace tests\flow\nodes;
|
||||
|
||||
use tests\flow\TestCase;
|
||||
use app\flow\nodes\EndNode;
|
||||
use app\flow\DbOperationType;
|
||||
|
||||
/**
|
||||
* 结束节点单元测试
|
||||
*/
|
||||
class EndNodeTest extends TestCase
|
||||
{
|
||||
protected EndNode $node;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->node = new EndNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试节点名称和编码
|
||||
*/
|
||||
public function testNodeIdentity(): void
|
||||
{
|
||||
$this->assertEquals('结束', $this->node->getName());
|
||||
$this->assertEquals('结束', $this->node->getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试干燥后可以刷结束
|
||||
*/
|
||||
public function testCanHandleAfterDry(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '结束',
|
||||
'currentStep' => '干燥',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试消毒后可以刷结束(跳过终末漂洗)
|
||||
*/
|
||||
public function testCanHandleAfterDisinfect(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '结束',
|
||||
'currentStep' => '消毒',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试终末漂洗后可以刷结束
|
||||
*/
|
||||
public function testCanHandleAfterFinalRinse(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '结束',
|
||||
'currentStep' => '终末漂洗',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试机洗后可以刷结束
|
||||
*/
|
||||
public function testCanHandleAfterMachineWash(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '结束',
|
||||
'currentStep' => '机洗',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试非结束读卡器不能处理
|
||||
*/
|
||||
public function testCannotHandleNonEndReader(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '清洗',
|
||||
'currentStep' => '干燥',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试清洗后不能直接刷结束
|
||||
*/
|
||||
public function testCannotHandleAfterWash(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '结束',
|
||||
'currentStep' => '清洗',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试漂洗后不能直接刷结束
|
||||
*/
|
||||
public function testCannotHandleAfterRinse(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '结束',
|
||||
'currentStep' => '漂洗',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试空步骤不能刷结束
|
||||
*/
|
||||
public function testCannotHandleWithEmptyStep(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '结束',
|
||||
'currentStep' => '',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试处理流程
|
||||
*/
|
||||
public function testHandleProcess(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '结束',
|
||||
'currentStep' => '干燥',
|
||||
'batchNo' => 'BATCH001',
|
||||
'actionStartTime' => date('Y-m-d H:i:s', time() - 600),
|
||||
]);
|
||||
|
||||
$result = $this->node->handle($context);
|
||||
|
||||
$this->assertSuccess($result);
|
||||
$this->assertStep($result, '结束');
|
||||
$this->assertNotEmpty($result->actionEndTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试数据库操作标记(update 而非 insert)
|
||||
*/
|
||||
public function testDatabaseOperationIsUpdate(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '结束',
|
||||
'currentStep' => '干燥',
|
||||
'batchNo' => 'BATCH001',
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertTrue($context->needDatabaseOperation);
|
||||
$this->assertEquals(DbOperationType::INSERT, $context->dbOperation);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 WebSocket 通知标记
|
||||
*/
|
||||
public function testWebSocketNotifyFlag(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '结束',
|
||||
'currentStep' => '干燥',
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertTrue($context->needWebSocketNotify);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 actionEndTime 被设置
|
||||
*/
|
||||
public function testActionEndTimeIsSet(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '结束',
|
||||
'currentStep' => '干燥',
|
||||
]);
|
||||
|
||||
$before = date('Y-m-d H:i:s');
|
||||
$this->node->handle($context);
|
||||
$after = date('Y-m-d H:i:s');
|
||||
|
||||
$this->assertGreaterThanOrEqual($before, $context->actionEndTime);
|
||||
$this->assertLessThanOrEqual($after, $context->actionEndTime);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace tests\flow\nodes;
|
||||
|
||||
use tests\flow\TestCase;
|
||||
use app\flow\nodes\FinalRinseNode;
|
||||
use app\flow\DbOperationType;
|
||||
|
||||
/**
|
||||
* 终末漂洗节点单元测试
|
||||
*/
|
||||
class FinalRinseNodeTest extends TestCase
|
||||
{
|
||||
protected FinalRinseNode $node;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->node = new FinalRinseNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试消毒后可以刷终末漂洗
|
||||
*/
|
||||
public function testCanHandleAfterDisinfect(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '终末漂洗',
|
||||
'currentStep' => '消毒',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试机洗后可以刷终末漂洗(默认配置)
|
||||
*/
|
||||
public function testCanHandleAfterMachineWashByDefault(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '终末漂洗',
|
||||
'currentStep' => '机洗',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试禁用的节点不会处理任何请求(特殊医院配置)
|
||||
*/
|
||||
public function testCannotHandleAfterMachineWashWhenDisabled(): void
|
||||
{
|
||||
$node = new FinalRinseNode();
|
||||
$node->setEnabled(false); // 禁用节点
|
||||
|
||||
$context = $this->createContext([
|
||||
'readerType' => '终末漂洗',
|
||||
'currentStep' => '机洗',
|
||||
]);
|
||||
|
||||
// 禁用的节点不处理请求:handle 直接将上下文传递给下一节点,不更改 currentStep
|
||||
$result = $node->handle($context);
|
||||
$this->assertEquals('机洗', $result->currentStep); // 步骤不变
|
||||
$this->assertFalse($result->needDatabaseOperation); // 不写库
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试不能处理非终末漂洗读卡器
|
||||
*/
|
||||
public function testCannotHandleNonFinalRinseReader(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '清洗',
|
||||
'currentStep' => '消毒',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试处理流程
|
||||
*/
|
||||
public function testHandleProcess(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '终末漂洗',
|
||||
'currentStep' => '消毒',
|
||||
]);
|
||||
|
||||
$result = $this->node->handle($context);
|
||||
|
||||
$this->assertSuccess($result);
|
||||
$this->assertStep($result, '终末漂洗');
|
||||
$this->assertNotNull($result->getStepLastTime('终末漂洗'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试清洗后不能直接刷终末漂洗
|
||||
*/
|
||||
public function testCannotHandleAfterWash(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '终末漂洗',
|
||||
'currentStep' => '清洗',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试数据库操作标记
|
||||
*/
|
||||
public function testDatabaseOperationFlags(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '终末漂洗',
|
||||
'currentStep' => '消毒',
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertTrue($context->needDatabaseOperation);
|
||||
$this->assertEquals(DbOperationType::INSERT, $context->dbOperation);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 WebSocket 通知标记
|
||||
*/
|
||||
public function testWebSocketNotifyFlag(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '终末漂洗',
|
||||
'currentStep' => '消毒',
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertTrue($context->needWebSocketNotify);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试节点名称和编码
|
||||
*/
|
||||
public function testNodeIdentity(): void
|
||||
{
|
||||
$this->assertEquals('终末漂洗', $this->node->getName());
|
||||
$this->assertEquals('终末漂洗', $this->node->getCode());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
namespace tests\flow\nodes;
|
||||
|
||||
use tests\flow\TestCase;
|
||||
use app\flow\nodes\MachineWashNode;
|
||||
use app\flow\DbOperationType;
|
||||
|
||||
/**
|
||||
* 机洗节点单元测试
|
||||
*/
|
||||
class MachineWashNodeTest extends TestCase
|
||||
{
|
||||
protected MachineWashNode $node;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->node = new MachineWashNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试节点名称和编码
|
||||
*/
|
||||
public function testNodeIdentity(): void
|
||||
{
|
||||
$this->assertEquals('机洗', $this->node->getName());
|
||||
$this->assertEquals('机洗', $this->node->getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试清洗后可以刷机洗
|
||||
*/
|
||||
public function testCanHandleAfterWash(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '机洗',
|
||||
'currentStep' => '清洗',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试漂洗后可以刷机洗
|
||||
*/
|
||||
public function testCanHandleAfterRinse(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '机洗',
|
||||
'currentStep' => '漂洗',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试消毒后可以刷机洗
|
||||
*/
|
||||
public function testCanHandleAfterDisinfect(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '机洗',
|
||||
'currentStep' => '消毒',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试步骤为空时可以刷机洗(新流程开始)
|
||||
*/
|
||||
public function testCanHandleWithEmptyStep(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '机洗',
|
||||
'currentStep' => '',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试结束后可以刷机洗
|
||||
*/
|
||||
public function testCanHandleAfterEnd(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '机洗',
|
||||
'currentStep' => '结束',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试内镜取出后可以刷机洗
|
||||
*/
|
||||
public function testCanHandleAfterEndoscopeOut(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '机洗',
|
||||
'currentStep' => '内镜取出',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试非机洗读卡器不能处理
|
||||
*/
|
||||
public function testCannotHandleNonMachineWashReader(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '清洗',
|
||||
'currentStep' => '清洗',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试终末漂洗后不能刷机洗
|
||||
*/
|
||||
public function testCannotHandleAfterFinalRinse(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '机洗',
|
||||
'currentStep' => '终末漂洗',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试干燥后不能刷机洗
|
||||
*/
|
||||
public function testCannotHandleAfterDry(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '机洗',
|
||||
'currentStep' => '干燥',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试处理流程
|
||||
*/
|
||||
public function testHandleProcess(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '机洗',
|
||||
'currentStep' => '清洗',
|
||||
'batchNo' => 'BATCH001',
|
||||
]);
|
||||
|
||||
$result = $this->node->handle($context);
|
||||
|
||||
$this->assertSuccess($result);
|
||||
$this->assertStep($result, '机洗');
|
||||
$this->assertEquals('机洗', $result->processType);
|
||||
$this->assertNotNull($result->getStepLastTime('机洗'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试数据库操作标记
|
||||
*/
|
||||
public function testDatabaseOperationFlags(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '机洗',
|
||||
'currentStep' => '清洗',
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertTrue($context->needDatabaseOperation);
|
||||
$this->assertEquals(DbOperationType::INSERT, $context->dbOperation);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 WebSocket 通知标记
|
||||
*/
|
||||
public function testWebSocketNotifyFlag(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '机洗',
|
||||
'currentStep' => '清洗',
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertTrue($context->needWebSocketNotify);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace tests\flow\nodes;
|
||||
|
||||
use tests\flow\TestCase;
|
||||
use app\flow\nodes\MorningWashNode;
|
||||
|
||||
/**
|
||||
* 晨洗节点单元测试
|
||||
*/
|
||||
class MorningWashNodeTest extends TestCase
|
||||
{
|
||||
protected MorningWashNode $node;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->node = new MorningWashNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试节点名称和编码
|
||||
*/
|
||||
public function testNodeIdentity(): void
|
||||
{
|
||||
$this->assertEquals('晨洗', $this->node->getName());
|
||||
$this->assertEquals('晨洗', $this->node->getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试可以处理消毒读卡器(晨洗模式)
|
||||
*/
|
||||
public function testCanHandleDisinfectReaderForMorningWash(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '消毒',
|
||||
'currentStep' => '',
|
||||
'needMorningWash' => true,
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试可以处理机洗读卡器(晨洗模式)
|
||||
*/
|
||||
public function testCanHandleMachineWashReaderForMorningWash(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '机洗',
|
||||
'currentStep' => '',
|
||||
'needMorningWash' => true,
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试不需要晨洗时不能处理
|
||||
*/
|
||||
public function testCannotHandleWhenNoNeed(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '晨洗',
|
||||
'currentStep' => '',
|
||||
'needMorningWash' => false,
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试非消毒/机洗读卡器不能处理晨洗
|
||||
*/
|
||||
public function testCannotHandleNonDisinfectMachineReader(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '清洗',
|
||||
'currentStep' => '',
|
||||
'needMorningWash' => true,
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试已完成晨洗后不能再次处理
|
||||
*/
|
||||
public function testCannotHandleWhenAlreadyWashed(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '晨洗',
|
||||
'currentStep' => '晨洗',
|
||||
'needMorningWash' => false,
|
||||
'morningWashed' => true,
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试处理流程(消毒读卡器)
|
||||
*/
|
||||
public function testHandleProcessWithDisinfect(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '消毒',
|
||||
'currentStep' => '',
|
||||
'needMorningWash' => true,
|
||||
'endoscopeId' => '', // 避免触发 DB 查询
|
||||
]);
|
||||
|
||||
$result = $this->node->handle($context);
|
||||
|
||||
$this->assertSuccess($result);
|
||||
$this->assertEquals('清洗', $result->currentStep); // 晨洗后进入清洗步骤
|
||||
$this->assertTrue($result->morningWashed);
|
||||
$this->assertEquals('手工洗(晨洗)', $result->processType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试处理流程(机洗读卡器)
|
||||
*/
|
||||
public function testHandleProcessWithMachineWash(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '机洗',
|
||||
'currentStep' => '',
|
||||
'needMorningWash' => true,
|
||||
'endoscopeId' => '', // 避免触发 DB 查询
|
||||
]);
|
||||
|
||||
$result = $this->node->handle($context);
|
||||
|
||||
$this->assertSuccess($result);
|
||||
$this->assertEquals('清洗', $result->currentStep);
|
||||
$this->assertTrue($result->morningWashed);
|
||||
$this->assertEquals('机洗(晨洗)', $result->processType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试生成批次号
|
||||
*/
|
||||
public function testGenerateBatchNo(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '消毒',
|
||||
'currentStep' => '',
|
||||
'needMorningWash' => true,
|
||||
'endoscopeId' => '', // 避免触发 DB 查询
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertNotEmpty($context->batchNo);
|
||||
$this->assertTrue($context->needDatabaseOperation);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
namespace tests\flow\nodes;
|
||||
|
||||
use tests\flow\TestCase;
|
||||
use app\flow\nodes\RinseNode;
|
||||
use app\flow\DbOperationType;
|
||||
|
||||
/**
|
||||
* 漂洗节点单元测试
|
||||
*/
|
||||
class RinseNodeTest extends TestCase
|
||||
{
|
||||
protected RinseNode $node;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->node = new RinseNode();
|
||||
// 确保每个测试时节点都是启用状态
|
||||
$this->node->setEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试节点名称和编码
|
||||
*/
|
||||
public function testNodeIdentity(): void
|
||||
{
|
||||
$this->assertEquals('漂洗', $this->node->getName());
|
||||
$this->assertEquals('漂洗', $this->node->getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试清洗后可以刷漂洗
|
||||
*/
|
||||
public function testCanHandleAfterWash(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '漂洗',
|
||||
'currentStep' => '清洗',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试非漂洗读卡器不能处理
|
||||
*/
|
||||
public function testCannotHandleNonRinseReader(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '清洗',
|
||||
'currentStep' => '清洗',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试消毒后不能刷漂洗
|
||||
*/
|
||||
public function testCannotHandleAfterDisinfect(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '漂洗',
|
||||
'currentStep' => '消毒',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试步骤为空时不能刷漂洗
|
||||
*/
|
||||
public function testCannotHandleWithEmptyStep(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '漂洗',
|
||||
'currentStep' => '',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试漂洗后不能立即再次漂洗
|
||||
*/
|
||||
public function testCannotHandleAfterRinse(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '漂洗',
|
||||
'currentStep' => '漂洗',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试处理流程
|
||||
*/
|
||||
public function testHandleProcess(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '漂洗',
|
||||
'currentStep' => '清洗',
|
||||
'batchNo' => 'BATCH001',
|
||||
]);
|
||||
|
||||
$result = $this->node->handle($context);
|
||||
|
||||
$this->assertSuccess($result);
|
||||
$this->assertStep($result, '漂洗');
|
||||
$this->assertNotNull($result->getStepLastTime('漂洗'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试数据库操作标记
|
||||
*/
|
||||
public function testDatabaseOperationFlags(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '漂洗',
|
||||
'currentStep' => '清洗',
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertTrue($context->needDatabaseOperation);
|
||||
$this->assertEquals(DbOperationType::INSERT, $context->dbOperation);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 WebSocket 通知标记
|
||||
*/
|
||||
public function testWebSocketNotifyFlag(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '漂洗',
|
||||
'currentStep' => '清洗',
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertTrue($context->needWebSocketNotify);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试节点被禁用后直接跳过
|
||||
*/
|
||||
public function testDisabledNodeSkips(): void
|
||||
{
|
||||
$this->node->setEnabled(false);
|
||||
|
||||
$context = $this->createContext([
|
||||
'readerType' => '漂洗',
|
||||
'currentStep' => '清洗',
|
||||
]);
|
||||
|
||||
$result = $this->node->handle($context);
|
||||
|
||||
// 被禁用,currentStep 不应该变为漂洗
|
||||
$this->assertEquals('清洗', $result->currentStep);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace tests\flow\nodes;
|
||||
|
||||
use tests\flow\TestCase;
|
||||
use app\flow\nodes\WashNode;
|
||||
use app\flow\DbOperationType;
|
||||
|
||||
/**
|
||||
* 清洗节点单元测试
|
||||
*/
|
||||
class WashNodeTest extends TestCase
|
||||
{
|
||||
protected WashNode $node;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->node = new WashNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试节点名称和编码
|
||||
*/
|
||||
public function testNodeIdentity(): void
|
||||
{
|
||||
$this->assertEquals('清洗', $this->node->getName());
|
||||
$this->assertEquals('清洗', $this->node->getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试可以处理清洗读卡器
|
||||
*/
|
||||
public function testCanHandleWashReader(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '清洗',
|
||||
'currentStep' => '',
|
||||
'morningWashed' => true,
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试不能处理非清洗读卡器
|
||||
*/
|
||||
public function testCannotHandleNonWashReader(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '消毒',
|
||||
'currentStep' => '',
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试新流程可以开始清洗
|
||||
*/
|
||||
public function testCanStartNewWashProcess(): void
|
||||
{
|
||||
$validSteps = ['', '结束', '内镜取出', '内镜放入', '测漏正常'];
|
||||
|
||||
foreach ($validSteps as $step) {
|
||||
$context = $this->createContext([
|
||||
'readerType' => '清洗',
|
||||
'currentStep' => $step,
|
||||
'morningWashed' => true,
|
||||
]);
|
||||
|
||||
$this->assertTrue(
|
||||
$this->node->canHandle($context),
|
||||
"步骤 '{$step}' 应该可以开始清洗"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试未完成晨洗不能开始清洗
|
||||
*/
|
||||
public function testCannotWashWithoutMorningWash(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '清洗',
|
||||
'currentStep' => '',
|
||||
'needMorningWash' => true,
|
||||
'morningWashed' => false,
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->node->canHandle($context));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试处理流程
|
||||
*/
|
||||
public function testHandleProcess(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '清洗',
|
||||
'currentStep' => '',
|
||||
'morningWashed' => true,
|
||||
'endoscopeId' => '', // 避免触发 DB 查询
|
||||
]);
|
||||
|
||||
$result = $this->node->handle($context);
|
||||
|
||||
$this->assertSuccess($result);
|
||||
$this->assertStep($result, '清洗');
|
||||
$this->assertEquals('手工洗', $result->processType);
|
||||
$this->assertNotNull($result->getStepLastTime('清洗'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试生成批次号
|
||||
*/
|
||||
public function testGenerateBatchNo(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '清洗',
|
||||
'currentStep' => '',
|
||||
'morningWashed' => true,
|
||||
'endoscopeId' => '', // 避免触发 DB 查询
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertNotEmpty($context->batchNo);
|
||||
$this->assertTrue($context->needDatabaseOperation);
|
||||
$this->assertEquals(DbOperationType::INSERT, $context->dbOperation);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试已有批次号不重新生成
|
||||
*/
|
||||
public function testKeepExistingBatchNo(): void
|
||||
{
|
||||
$context = $this->createContext([
|
||||
'readerType' => '清洗',
|
||||
'currentStep' => '漂洗', // 已有流程
|
||||
'batchNo' => 'EXISTING001',
|
||||
'morningWashed' => true,
|
||||
]);
|
||||
|
||||
$this->node->handle($context);
|
||||
|
||||
$this->assertEquals('EXISTING001', $context->batchNo);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user