From 54de2e56741c8570d1b0a0fd037a5f402447277b Mon Sep 17 00:00:00 2001 From: Jeppe Bundgaard Date: Wed, 27 May 2026 19:30:31 +0200 Subject: [PATCH] Add fake classes for relay logic and refactor relay shutdown without pre-checking status Introduce helper classes `SelfserveWashCompletionRelayValueFake`, `SelfserveWashCompletionDepartmentLaneFake`, `SelfserveWashCompletionRelayLaneFake`, and `SelfserveWashCompletionFlowHarness` to simulate relay logic for unit tests. Refactor `turnOffRelayIfConfiguredAndOn` to `turnOffRelayIfConfigured`, removing relay status pre-check for cleaner and machine relays when completing a wash session, and test associated relay actions. --- .../selfserve/classes/selfserve_wash_flow.php | 23 ++--- .../SelfserveStartCleanerRelayWiringTest.php | 5 + ...SelfserveWashCompletionRelayWiringTest.php | 97 ++++++++++++++++++- 3 files changed, 104 insertions(+), 21 deletions(-) diff --git a/services/nginx/app/modules/selfserve/classes/selfserve_wash_flow.php b/services/nginx/app/modules/selfserve/classes/selfserve_wash_flow.php index 32ffe7b6..cf90eca1 100644 --- a/services/nginx/app/modules/selfserve/classes/selfserve_wash_flow.php +++ b/services/nginx/app/modules/selfserve/classes/selfserve_wash_flow.php @@ -273,28 +273,19 @@ class selfserve_wash_flow implements selfserve_wash_flow_i return; } - $this->turnOffRelayIfConfiguredAndOn($lane, selfserve_lane_relay::MACHINE); - $this->turnOffRelayIfConfiguredAndOn($lane, selfserve_lane_relay::MACHINE_CLEANER); + $this->turnOffRelayIfConfigured($lane, selfserve_lane_relay::MACHINE); + $this->turnOffRelayIfConfigured($lane, selfserve_lane_relay::MACHINE_CLEANER); } catch (\Throwable) { // Best effort only; session completion flow must continue. } } - protected function turnOffRelayIfConfiguredAndOn(selfserve_lane $lane, selfserve_lane_relay $relay): void + protected function turnOffRelayIfConfigured(selfserve_lane $lane, selfserve_lane_relay $relay): void { if (!$this->isRelayConfiguredForLane($lane, $relay)) { return; } - try { - $status = $lane->getRelayStatus($relay); - if ((bool)($status['on'] ?? false) !== true) { - return; - } - } catch (\Throwable) { - // If relay status can't be read, still attempt turn-off as best effort. - } - try { $lane->setRelayStatusHard($relay, false); } catch (\Throwable) { @@ -723,14 +714,14 @@ class selfserve_wash_flow implements selfserve_wash_flow_i protected function enableMachineRelayIfAllowed(array $snapshot, selfserve_wash_sessions_o $session): void { - if ((bool)$session->machine_relay_enabled->value() === true) { - return; - } - $laneId = (int)$snapshot['lane']['id']; $lane = (new selfserve())->lane($laneId); $this->enableCleanerRelayForStartedWash($lane); + if ((bool)$session->machine_relay_enabled->value() === true) { + return; + } + $session->markRelayEnabled(); $this->logSessionEvent((int)$session->id, selfserve_wash_event_type::MACHINE_RELAY_ENABLED, [ 'lane_id' => $laneId, diff --git a/services/nginx/app/tests/Unit/Selfserve/SelfserveStartCleanerRelayWiringTest.php b/services/nginx/app/tests/Unit/Selfserve/SelfserveStartCleanerRelayWiringTest.php index eb5186cf..f812cf00 100644 --- a/services/nginx/app/tests/Unit/Selfserve/SelfserveStartCleanerRelayWiringTest.php +++ b/services/nginx/app/tests/Unit/Selfserve/SelfserveStartCleanerRelayWiringTest.php @@ -22,6 +22,11 @@ it('keeps cleaner relay enable wired into machine relay start paths', function ( expect($enableMachineRelayMethodOffset)->not->toBeFalse(); $enableMachineRelayMethod = substr($washFlow, (int)$enableMachineRelayMethodOffset, 1200); expect($enableMachineRelayMethod)->toContain('$this->enableCleanerRelayForStartedWash($lane);'); + $cleanerEnableOffset = strpos($enableMachineRelayMethod, '$this->enableCleanerRelayForStartedWash($lane);'); + $alreadyEnabledGuardOffset = strpos($enableMachineRelayMethod, 'if ((bool)$session->machine_relay_enabled->value() === true)'); + expect($cleanerEnableOffset)->not->toBeFalse() + ->and($alreadyEnabledGuardOffset)->not->toBeFalse() + ->and($cleanerEnableOffset)->toBeLessThan($alreadyEnabledGuardOffset); expect($moduleRoute)->not->toBeFalse(); $machineEnableRouteOffset = strpos($moduleRoute, '/modules/self-serve/lane/relay/machine/enable'); diff --git a/services/nginx/app/tests/Unit/Selfserve/SelfserveWashCompletionRelayWiringTest.php b/services/nginx/app/tests/Unit/Selfserve/SelfserveWashCompletionRelayWiringTest.php index c4fdf8b5..ebd0f9f3 100644 --- a/services/nginx/app/tests/Unit/Selfserve/SelfserveWashCompletionRelayWiringTest.php +++ b/services/nginx/app/tests/Unit/Selfserve/SelfserveWashCompletionRelayWiringTest.php @@ -1,5 +1,79 @@ storedValue; + } +} + +class SelfserveWashCompletionDepartmentLaneFake extends \objects\department_lanes_o +{ + public function __construct(string $machineRelayId = 'relay-machine', string $cleanerRelayId = 'relay-cleaner') + { + $this->relay_machine_id = new SelfserveWashCompletionRelayValueFake($machineRelayId); + $this->relay_machine_cleaner_id = new SelfserveWashCompletionRelayValueFake($cleanerRelayId); + $this->relay_machine_program_picker_id = new SelfserveWashCompletionRelayValueFake(''); + } + + public function exists(): bool + { + return true; + } +} + +class SelfserveWashCompletionRelayLaneFake extends selfserve_lane +{ + /** @var selfserve_lane_relay[] */ + public array $statusReads = []; + /** @var array */ + public array $relayWrites = []; + + public function __construct(bool $reportedOn) + { + $this->id = 77; + $this->reportedOn = $reportedOn; + $this->department_lane = new SelfserveWashCompletionDepartmentLaneFake(); + } + + private bool $reportedOn; + + public function getRelayStatus(selfserve_lane_relay $relay): array + { + $this->statusReads[] = $relay; + return ['on' => $this->reportedOn]; + } + + public function setRelayStatusHard(selfserve_lane_relay $relay, bool $on): bool + { + $this->relayWrites[] = [$relay, $on]; + return true; + } +} + +class SelfserveWashCompletionFlowHarness extends selfserve_wash_flow +{ + public function __construct() {} + + public function turnOffConfiguredRelay(selfserve_lane $lane, selfserve_lane_relay $relay): void + { + $this->turnOffRelayIfConfigured($lane, $relay); + } +} + it('forces machine and cleaner relays off when a self-serve wash session is completed', function (): void { $washFlow = file_get_contents(app_path('modules/selfserve/classes/selfserve_wash_flow.php')); @@ -10,14 +84,27 @@ it('forces machine and cleaner relays off when a self-serve wash session is comp expect($methodOffset)->not->toBeFalse(); $methodBody = substr($washFlow, (int)$methodOffset, 1500); - expect($methodBody)->toContain('$this->turnOffRelayIfConfiguredAndOn($lane, selfserve_lane_relay::MACHINE);'); - expect($methodBody)->toContain('$this->turnOffRelayIfConfiguredAndOn($lane, selfserve_lane_relay::MACHINE_CLEANER);'); + expect($methodBody)->toContain('$this->turnOffRelayIfConfigured($lane, selfserve_lane_relay::MACHINE);'); + expect($methodBody)->toContain('$this->turnOffRelayIfConfigured($lane, selfserve_lane_relay::MACHINE_CLEANER);'); - $helperOffset = strpos($washFlow, 'protected function turnOffRelayIfConfiguredAndOn'); + $helperOffset = strpos($washFlow, 'protected function turnOffRelayIfConfigured'); expect($helperOffset)->not->toBeFalse(); $helperBody = substr($washFlow, (int)$helperOffset, 1500); - expect($helperBody)->toContain('$status = $lane->getRelayStatus($relay);'); - expect($helperBody)->toContain("if ((bool)(\$status['on'] ?? false) !== true)"); expect($helperBody)->toContain('$lane->setRelayStatusHard($relay, false);'); + expect($helperBody)->not->toContain('$lane->getRelayStatus($relay)'); +}); + +it('always dispatches completion relay off for configured machine relays without a status precheck', function (): void { + $lane = new SelfserveWashCompletionRelayLaneFake(reportedOn: false); + $flow = new SelfserveWashCompletionFlowHarness(); + + $flow->turnOffConfiguredRelay($lane, selfserve_lane_relay::MACHINE); + $flow->turnOffConfiguredRelay($lane, selfserve_lane_relay::MACHINE_CLEANER); + + expect($lane->statusReads)->toBe([]) + ->and($lane->relayWrites)->toBe([ + [selfserve_lane_relay::MACHINE, false], + [selfserve_lane_relay::MACHINE_CLEANER, false], + ]); });