Files
api/services/nginx/app/tests/Unit/Selfserve/ShellyRelayInventoryTest.php
T
Jeppe Bundgaard f2e2b9a8f4 Update relay-handling logic and test assertions for device binding and local IP resolution
- Correct test cases to ensure proper relay IDs are switched.
- Add robust local IP resolution for relay-device bindings, including caching and inventory backfill.
- Introduce fast-path options for relay status and switch dispatch.
- Validate PHP extensions (`curl`, `sqlite3`) in edge agent images.
2026-04-27 16:02:36 +02:00

207 lines
7.8 KiB
PHP

<?php
app_require('classes/shelly_relay_inventory.php');
use classes\shelly_relay_inventory;
it('normalizes owned Shelly devices into relay select options', function (): void {
$inventory = (new shelly_relay_inventory())
->setInventoryFetcher(static function (): array {
return [
'isok' => true,
'data' => [
'devices_status' => [
'device-key-1' => [
'_dev_info' => [
'id' => 'shelly-plus-01',
'code' => 'SPSW-001PE16EU',
'model' => 'Shelly Plus 1PM',
'online' => 1,
],
'name' => 'Entry Gate',
'wifi_sta' => [
'ip' => '10.32.0.11',
],
'status' => [
'switch:0' => [
'output' => false,
'name' => 'Entrance Relay',
],
],
],
'device-key-2' => [
'_dev_info' => [
'id' => 'shelly-pro-03',
'code' => 'SPSW-201XE16EU',
'model' => 'Shelly Pro 2PM',
],
'name' => 'Machine Cabinet',
'status' => [
'eth' => [
'ip' => '10.32.0.12',
],
],
'relays' => [
['ison' => false, 'name' => 'Program Picker'],
],
],
'device-key-3' => [
'_dev_info' => [
'id' => 'shelly-legacy-02',
'code' => 'SHSW-1',
'model' => 'Shelly 1',
'online' => 0,
],
'relays' => [
['ison' => false],
],
],
'device-key-4' => [
'_dev_info' => [
'id' => 'shelly-sensor-01',
'code' => 'SHHT-1',
'model' => 'Shelly H&T',
'online' => 1,
],
'sensor' => [
'temperature' => 21.5,
],
],
],
],
];
})
->setDeviceListFetcher(static function (): array {
return [
'isok' => true,
'data' => [
'devices' => [
'shelly-plus-01' => [
'id' => 'shelly-plus-01',
'name' => 'Gate From Shelly Cloud',
'type' => 'SPSW-001PE16EU',
'cloud_online' => true,
],
'shelly-pro-03' => [
'id' => 'shelly-pro-03',
'name' => 'Program Picker From Shelly Cloud',
'type' => 'SPSW-201XE16EU',
'cloud_online' => false,
],
],
],
];
});
expect($inventory->listRelayOptions())->toBe([
[
'id' => 'shelly-plus-01',
'name' => 'Gate From Shelly Cloud (Shelly Plus 1PM)',
'device_id' => 'shelly-plus-01',
'device_name' => 'Gate From Shelly Cloud',
'cloud_name' => 'Gate From Shelly Cloud',
'device_type' => 'Shelly Plus 1PM',
'code' => 'SPSW-001PE16EU',
'control_type' => 'Switch',
'control_name' => 'Entrance Relay',
'local_ip' => '10.32.0.11',
'status_color' => 'Green',
'online' => true,
],
[
'id' => 'shelly-pro-03',
'name' => 'Program Picker From Shelly Cloud (Shelly Pro 2PM)',
'device_id' => 'shelly-pro-03',
'device_name' => 'Program Picker From Shelly Cloud',
'cloud_name' => 'Program Picker From Shelly Cloud',
'device_type' => 'Shelly Pro 2PM',
'code' => 'SPSW-201XE16EU',
'control_type' => 'Relay',
'control_name' => 'Program Picker',
'local_ip' => '10.32.0.12',
'status_color' => 'Red',
'online' => false,
],
[
'id' => 'shelly-legacy-02',
'name' => 'shelly-legacy-02 (Shelly 1)',
'device_id' => 'shelly-legacy-02',
'device_name' => null,
'cloud_name' => null,
'device_type' => 'Shelly 1',
'code' => 'SHSW-1',
'control_type' => 'Relay',
'control_name' => null,
'local_ip' => null,
'status_color' => 'Red',
'online' => false,
],
]);
});
it('falls back to local device and control names when Shelly cloud list metadata is unavailable', function (): void {
$inventory = (new shelly_relay_inventory())
->setInventoryFetcher(static function (): array {
return [
'isok' => true,
'data' => [
'devices_status' => [
'device-key-1' => [
'_dev_info' => [
'id' => 'shelly-plus-01',
'code' => 'SPSW-001PE16EU',
'model' => 'Shelly Plus 1PM',
'online' => 1,
],
'ip' => '10.32.0.21',
'name' => 'Entry Gate',
'status' => [
'switch:0' => [
'output' => false,
'name' => 'Entrance Relay',
],
],
],
],
],
];
})
->setDeviceListFetcher(static function (): array {
return [
'isok' => false,
'errors' => [
'404' => 'Requested method was not found',
],
];
});
expect($inventory->listRelayOptions())->toBe([
[
'id' => 'shelly-plus-01',
'name' => 'Entry Gate / Entrance Relay (Shelly Plus 1PM)',
'device_id' => 'shelly-plus-01',
'device_name' => 'Entry Gate',
'cloud_name' => null,
'device_type' => 'Shelly Plus 1PM',
'code' => 'SPSW-001PE16EU',
'control_type' => 'Switch',
'control_name' => 'Entrance Relay',
'local_ip' => '10.32.0.21',
'status_color' => 'Green',
'online' => true,
],
]);
});
it('fails fast when Shelly inventory does not include owned devices status', function (): void {
$inventory = (new shelly_relay_inventory())->setInventoryFetcher(static function (): array {
return [
'isok' => true,
'data' => [],
];
});
expect(fn() => $inventory->listRelayOptions())
->toThrow(Exception::class, 'Shelly relay inventory response was missing devices_status');
});