<?php
use PHPUnit\Framework\TestCase;
use SHServ\Models\Devices;
use SHServ\Tools\DeviceAPI\Base;
class DevicesModelTransactionTest extends TestCase {
private $tb;
private $devicesModel;
protected function setUp(): void {
$this -> tb = app() -> thin_builder;
$this -> create_devices_table();
$this -> create_device_auth_table();
$this -> devicesModel = new Devices();
}
protected function tearDown(): void {
$this -> tb -> query("DROP TABLE IF EXISTS devices");
$this -> tb -> query("DROP TABLE IF EXISTS device_auth");
}
private function create_devices_table(): void {
$this -> tb -> query("CREATE TABLE devices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
area_id INTEGER DEFAULT 0,
alias TEXT,
name TEXT,
device_type TEXT,
device_ip TEXT,
device_mac TEXT,
device_hard_id TEXT,
firmware_version TEXT,
connection_status TEXT,
status TEXT,
description TEXT,
last_contact TEXT,
create_at TEXT,
update_at TEXT,
UNIQUE(device_hard_id, status)
)");
}
private function create_device_auth_table(): void {
$this -> tb -> query("CREATE TABLE device_auth (
id INTEGER PRIMARY KEY AUTOINCREMENT,
device_id INTEGER,
device_token TEXT,
status TEXT,
create_at TEXT,
update_at TEXT
)");
}
public function test_connect_new_device_happy_path(): void {
$mockApi = new MockDeviceAPIForSetup([
'data' => [
'status' => 'setup',
'device_type' => 'relay',
'ip_address' => '192.168.1.50',
'mac_address' => 'AA:BB:CC:DD:EE:FF',
'device_id' => 'hard_123',
'firmware_version' => '1.0.0',
]
]);
$result = $this -> devicesModel -> connect_new_device(
'192.168.1.50', 'relay_kitchen', 'Kitchen Relay', '', $mockApi
);
$this -> assertInstanceOf(\SHServ\Entities\Device::class, $result);
$this -> assertGreaterThan(0, $result -> id());
$this -> assertSame('relay_kitchen', $result -> alias);
$this -> assertSame('Kitchen Relay', $result -> name);
$fromDb = $this -> devicesModel -> by_id($result -> id());
$this -> assertNotNull($fromDb);
$this -> assertSame('relay', $fromDb -> device_type);
$auth = $result -> auth();
$this -> assertNotNull($auth);
$this -> assertSame('active', $auth -> status);
}
public function test_connect_new_device_rollback_on_auth_failure(): void {
$this -> tb -> query("DROP TABLE device_auth");
$mockApi = new MockDeviceAPIForSetup([
'data' => [
'status' => 'setup',
'device_type' => 'relay',
'ip_address' => '192.168.1.51',
'mac_address' => 'AA:BB:CC:DD:EE:00',
'device_id' => 'hard_456',
'firmware_version' => '1.0.0',
]
]);
$result = $this -> devicesModel -> connect_new_device(
'192.168.1.51', 'relay_fail', 'Fail Relay', '', $mockApi
);
$this -> assertIsArray($result);
$this -> assertFalse($result['result']);
$this -> assertSame('db_error', $result['err_alias']);
$fromDb = $this -> devicesModel -> by_alias('relay_fail');
$this -> assertNull($fromDb);
}
public function test_connect_new_device_rejects_non_setup_mode(): void {
$mockApi = new MockDeviceAPIForSetup([
'data' => [
'status' => 'normal',
'device_type' => 'relay',
'ip_address' => '192.168.1.52',
'mac_address' => 'AA:BB:CC:DD:EE:11',
'device_id' => 'hard_789',
'firmware_version' => '1.0.0',
]
]);
$result = $this -> devicesModel -> connect_new_device(
'192.168.1.52', 'relay_normal', 'Normal Relay', '', $mockApi
);
$this -> assertIsArray($result);
$this -> assertSame('device_mode_error', $result['err_alias']);
}
public function test_connect_new_device_returns_error_when_not_found(): void {
$mockApi = new MockDeviceAPIForSetup([
'data' => null,
]);
$result = $this -> devicesModel -> connect_new_device(
'192.168.1.53', 'relay_missing', 'Missing Relay', '', $mockApi
);
$this -> assertIsArray($result);
$this -> assertSame('device_not_found', $result['err_alias']);
}
public function test_connect_new_device_rejects_duplicate_hard_id(): void {
$mockApi = new MockDeviceAPIForSetup([
'data' => [
'status' => 'setup',
'device_type' => 'relay',
'ip_address' => '192.168.1.54',
'mac_address' => 'AA:BB:CC:DD:EE:22',
'device_id' => 'hard_duplicate',
'firmware_version' => '1.0.0',
]
]);
$result1 = $this -> devicesModel -> connect_new_device(
'192.168.1.54', 'relay_first', 'First Relay', '', $mockApi
);
$this -> assertInstanceOf(\SHServ\Entities\Device::class, $result1);
$result2 = $this -> devicesModel -> connect_new_device(
'192.168.1.54', 'relay_second', 'Second Relay', '', $mockApi
);
$this -> assertIsArray($result2);
$this -> assertFalse($result2['result']);
$this -> assertSame('device_already_registered', $result2['err_alias']);
}
}
class MockDeviceAPIForSetup extends Base {
private array $aboutResponse;
public function __construct(array $aboutResponse) {
parent::__construct('127.0.0.1');
$this -> aboutResponse = $aboutResponse;
}
public function get_about(): array {
return $this -> aboutResponse;
}
}