249 lines
8.4 KiB
PHP
249 lines
8.4 KiB
PHP
<?php
|
|
|
|
app_require('routes/moduleSelfServeRoute.php');
|
|
app_require('modules/selfserve/classes/selfserve_lane.php');
|
|
app_require('objects/department_lanes_o.php');
|
|
app_require('classes/object_property.php');
|
|
|
|
use classes\object_property;
|
|
use modules\selfserve\classes\selfserve_lane;
|
|
use objects\department_lanes_o;
|
|
use routes\moduleSelfServeRoute;
|
|
|
|
class SelfserveCustomerLaneAccessRouteHarness extends moduleSelfServeRoute
|
|
{
|
|
/** @var array<string,bool> */
|
|
public array $permissions = [
|
|
'list_own_department_selfserve_vehicle_conditions' => true,
|
|
];
|
|
public bool $laneEnabled = true;
|
|
public bool $moduleEnabled = true;
|
|
public bool $activeWashResult = false;
|
|
/** @var array<int,array{department_id:int,customer_number:int}> */
|
|
public array $activeWashChecks = [];
|
|
/** @var array<int,string> */
|
|
public array $forbiddenPermissions = [];
|
|
|
|
public function __construct()
|
|
{
|
|
// Avoid route_t request initialization in this focused unit test.
|
|
}
|
|
|
|
public function hasPermission(string|\classes\permission_node $permission, int $customer_number = null): bool
|
|
{
|
|
$key = $permission instanceof \classes\permission_node ? (string)$permission->permission : $permission;
|
|
return $this->permissions[$key] ?? false;
|
|
}
|
|
|
|
public function canUseLane(selfserve_lane $lane, int $customer_number): bool
|
|
{
|
|
return $this->canCustomerUseSelfServeLane($lane, $customer_number);
|
|
}
|
|
|
|
public function canUseActiveLane(selfserve_lane $lane, int $customer_number): bool
|
|
{
|
|
return $this->canCustomerUseActiveSelfServeLane($lane, $customer_number);
|
|
}
|
|
|
|
protected function isSelfServeModuleEnabled(): bool
|
|
{
|
|
return $this->moduleEnabled;
|
|
}
|
|
|
|
protected function isLaneSelfServeOperationallyEnabled(selfserve_lane $lane): bool
|
|
{
|
|
return $this->laneEnabled;
|
|
}
|
|
|
|
protected function emitForbidden(array $permissions): void
|
|
{
|
|
$this->forbiddenPermissions = array_values(array_map(
|
|
static fn(string|\classes\permission_node $permission): string => $permission instanceof \classes\permission_node
|
|
? $permission->permission
|
|
: $permission,
|
|
$permissions
|
|
));
|
|
throw new RuntimeException('forbidden');
|
|
}
|
|
|
|
public function requireCommandPermissionForTest(
|
|
selfserve_lane $lane,
|
|
int $customer_number,
|
|
string $command_permission,
|
|
bool $allow_customer_self_serve,
|
|
bool $requires_active_wash = false
|
|
): void {
|
|
$method = new ReflectionMethod(moduleSelfServeRoute::class, 'requireSelfServeLaneCommandPermission');
|
|
$method->invoke($this, $lane, $customer_number, $command_permission, $allow_customer_self_serve, $requires_active_wash);
|
|
}
|
|
|
|
protected function customerHasActiveSelfServeWashInDepartment(int $department_id, int $customer_number): bool
|
|
{
|
|
$this->activeWashChecks[] = [
|
|
'department_id' => $department_id,
|
|
'customer_number' => $customer_number,
|
|
];
|
|
|
|
return $this->activeWashResult;
|
|
}
|
|
}
|
|
|
|
class SelfserveCustomerLaneAccessDepartmentLaneFake extends department_lanes_o
|
|
{
|
|
public function __construct(int $department_id)
|
|
{
|
|
$this->id = -1;
|
|
$this->department = new object_property('department_lanes', -1, 'department', 'int');
|
|
$this->department->set($department_id);
|
|
}
|
|
|
|
public function structure(): void
|
|
{
|
|
// Skip database bootstrap for this unit test.
|
|
}
|
|
}
|
|
|
|
class SelfserveCustomerLaneAccessLaneFake extends selfserve_lane
|
|
{
|
|
public ?int $fakeCustomerNumber = null;
|
|
|
|
public function __construct(int $department_id, ?int $customer_number = null)
|
|
{
|
|
$this->id = 91;
|
|
$this->fakeCustomerNumber = $customer_number;
|
|
$this->department_lane = new SelfserveCustomerLaneAccessDepartmentLaneFake($department_id);
|
|
}
|
|
|
|
public function getCustomerNumber(): ?int
|
|
{
|
|
return $this->fakeCustomerNumber;
|
|
}
|
|
}
|
|
|
|
it('allows customers with own self-serve permission to use enabled self-serve lanes', function (): void {
|
|
$route = new SelfserveCustomerLaneAccessRouteHarness();
|
|
$lane = new SelfserveCustomerLaneAccessLaneFake(4);
|
|
|
|
expect($route->canUseLane($lane, 12345679))->toBeTrue();
|
|
});
|
|
|
|
it('blocks customer lane mutations without own self-serve permission', function (): void {
|
|
$route = new SelfserveCustomerLaneAccessRouteHarness();
|
|
$route->permissions = [];
|
|
$lane = new SelfserveCustomerLaneAccessLaneFake(4);
|
|
|
|
expect($route->canUseLane($lane, 12345679))->toBeFalse();
|
|
});
|
|
|
|
it('blocks customer lane mutations when the lane is not operationally enabled', function (): void {
|
|
$route = new SelfserveCustomerLaneAccessRouteHarness();
|
|
$route->laneEnabled = false;
|
|
$lane = new SelfserveCustomerLaneAccessLaneFake(4);
|
|
|
|
expect($route->canUseLane($lane, 12345679))->toBeFalse();
|
|
});
|
|
|
|
it('allows active wash operations when the lane runtime belongs to the customer', function (): void {
|
|
$route = new SelfserveCustomerLaneAccessRouteHarness();
|
|
$lane = new SelfserveCustomerLaneAccessLaneFake(4, 12345679);
|
|
|
|
expect($route->canUseActiveLane($lane, 12345679))->toBeTrue();
|
|
expect($route->activeWashChecks)->toBe([]);
|
|
});
|
|
|
|
it('keeps active wash operations available if a lane is disabled after start', function (): void {
|
|
$route = new SelfserveCustomerLaneAccessRouteHarness();
|
|
$route->laneEnabled = false;
|
|
$lane = new SelfserveCustomerLaneAccessLaneFake(4, 12345679);
|
|
|
|
expect($route->canUseActiveLane($lane, 12345679))->toBeTrue();
|
|
expect($route->activeWashChecks)->toBe([]);
|
|
});
|
|
|
|
it('falls back to active department sessions for customer active wash operations', function (): void {
|
|
$route = new SelfserveCustomerLaneAccessRouteHarness();
|
|
$route->activeWashResult = true;
|
|
$lane = new SelfserveCustomerLaneAccessLaneFake(4, null);
|
|
|
|
expect($route->canUseActiveLane($lane, 12345679))->toBeTrue();
|
|
expect($route->activeWashChecks)->toBe([
|
|
[
|
|
'department_id' => 4,
|
|
'customer_number' => 12345679,
|
|
],
|
|
]);
|
|
});
|
|
|
|
it('blocks active wash operations for other customers', function (): void {
|
|
$route = new SelfserveCustomerLaneAccessRouteHarness();
|
|
$route->activeWashResult = false;
|
|
$lane = new SelfserveCustomerLaneAccessLaneFake(4, 99999999);
|
|
|
|
expect($route->canUseActiveLane($lane, 12345679))->toBeFalse();
|
|
expect($route->activeWashChecks)->toBe([
|
|
[
|
|
'department_id' => 4,
|
|
'customer_number' => 12345679,
|
|
],
|
|
]);
|
|
});
|
|
|
|
|
|
it('denies customer self-serve command fallback when the self-serve module is disabled', function (): void {
|
|
$route = new SelfserveCustomerLaneAccessRouteHarness();
|
|
$route->moduleEnabled = false;
|
|
$lane = new SelfserveCustomerLaneAccessLaneFake(4, 12345679);
|
|
|
|
expect(fn() => $route->requireCommandPermissionForTest(
|
|
$lane,
|
|
12345679,
|
|
'modules_selfserve_lane_command_execute_stop',
|
|
true,
|
|
true
|
|
))->toThrow(RuntimeException::class, 'forbidden');
|
|
});
|
|
|
|
it('returns deterministic forbidden permissions when disabled module blocks customer self-serve command fallback', function (): void {
|
|
$route = new SelfserveCustomerLaneAccessRouteHarness();
|
|
$route->moduleEnabled = false;
|
|
$lane = new SelfserveCustomerLaneAccessLaneFake(4, 12345679);
|
|
|
|
try {
|
|
$route->requireCommandPermissionForTest(
|
|
$lane,
|
|
12345679,
|
|
'modules_selfserve_lane_command_execute_stop',
|
|
true,
|
|
true
|
|
);
|
|
} catch (RuntimeException $exception) {
|
|
expect($exception->getMessage())->toBe('forbidden');
|
|
}
|
|
|
|
expect($route->forbiddenPermissions)->toBe([
|
|
'modules_selfserve_lane_command_execute',
|
|
'modules_selfserve_lane_command_execute_stop',
|
|
'list_own_department_selfserve_vehicle_conditions',
|
|
]);
|
|
});
|
|
|
|
it('continues allowing operator self-serve commands when the self-serve module is disabled', function (): void {
|
|
$route = new SelfserveCustomerLaneAccessRouteHarness();
|
|
$route->moduleEnabled = false;
|
|
$route->permissions = [
|
|
'modules_selfserve_lane_command_execute' => true,
|
|
'modules_selfserve_lane_command_execute_stop' => true,
|
|
];
|
|
$lane = new SelfserveCustomerLaneAccessLaneFake(4, 12345679);
|
|
|
|
$route->requireCommandPermissionForTest(
|
|
$lane,
|
|
12345679,
|
|
'modules_selfserve_lane_command_execute_stop',
|
|
true,
|
|
true
|
|
);
|
|
|
|
expect($route->forbiddenPermissions)->toBe([]);
|
|
});
|