- Add boardDeviceService for managing device pairing, status, claiming, and revocation. - Introduce boardDeviceSettings for default settings and validation logic. - Create integration tests for device lifecycle, concurrent claims, and updates. - Add unit tests for device pairing, claiming, and settings validation. - Implement API tests for device endpoints with JWT authentication. - Develop in-memory repository for testing purposes. - Create frontend components for managing devices, including a form for device settings. - Style DevicesPage with CSS for better user experience.
25 lines
2.9 KiB
JavaScript
25 lines
2.9 KiB
JavaScript
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs/promises');
|
|
const path = require('node:path');
|
|
const { Pool } = require('pg');
|
|
const { createBoardDeviceRepository } = require('../src/services/boardDeviceRepository');
|
|
const { createBoardDeviceService } = require('../src/services/boardDeviceService');
|
|
const { defaults } = require('../src/services/boardDeviceSettings');
|
|
test('PostgreSQL device lifecycle, concurrent claims/updates, city isolation and retry after a lost reply', { skip: !process.env.BOARD_DEVICE_TEST_DATABASE_URL }, async () => {
|
|
const url = process.env.BOARD_DEVICE_TEST_DATABASE_URL; assert.match(new URL(url).pathname, /test/i, 'Use a dedicated test database');
|
|
const admin = new Pool({ connectionString: url }); const schema = `board_device_test_${Date.now()}`; let pool;
|
|
try {
|
|
await admin.query(`CREATE SCHEMA ${schema}`); pool = new Pool({ connectionString: url, options: `-c search_path=${schema},public` });
|
|
await pool.query('CREATE TABLE cities(id INTEGER PRIMARY KEY,name TEXT,is_active BOOLEAN); CREATE TABLE users(id INTEGER PRIMARY KEY); CREATE TABLE stops(id INTEGER PRIMARY KEY,city_id INTEGER REFERENCES cities(id),name TEXT,description TEXT); CREATE TABLE routes(id INTEGER PRIMARY KEY,city_id INTEGER,route_number TEXT,name TEXT); CREATE TABLE route_stops(route_id INTEGER,stop_id INTEGER); INSERT INTO cities VALUES(1,\'Полоцк\',true),(2,\'Новополоцк\',true); INSERT INTO users VALUES(1); INSERT INTO stops VALUES(1,1,\'Швейная фабрика\',\'на центр\'),(2,2,\'Другая\',\'конечная\');');
|
|
const sql = await fs.readFile(path.join(__dirname, '../migrations/016_board_devices.sql'), 'utf8'); await pool.query(sql); await pool.query(sql);
|
|
const service = createBoardDeviceService(createBoardDeviceRepository(pool)); const p = await service.start({ width: 1920 });
|
|
const claims = await Promise.allSettled([service.claim(1,{code:p.code,name:'A',settings:defaults},1),service.claim(1,{code:p.code,name:'B',settings:defaults},1)]);
|
|
assert.equal(claims.filter(r=>r.status==='fulfilled').length,1); const row=(await service.status(p.token)).device;
|
|
assert.equal((await service.status(p.token)).device.id,row.id); assert.equal((await service.list(2)).length,0);
|
|
const updates=await Promise.allSettled([service.update(row.id,1,{name:'C',settings:defaults,revision:1},1),service.update(row.id,1,{name:'D',settings:defaults,revision:1},1)]);assert.equal(updates.filter(r=>r.status==='fulfilled').length,1);
|
|
await service.heartbeat(p.token,{appliedRevision:2});assert.equal((await service.list(1))[0].appliedRevision,2);
|
|
await assert.rejects(service.revoke(row.id,2,1),e=>e.status===404);await service.revoke(row.id,1,1);await assert.rejects(service.status(p.token),e=>e.status===410);
|
|
} finally { if(pool) await pool.end();await admin.query(`DROP SCHEMA IF EXISTS ${schema} CASCADE`);await admin.end(); }
|
|
});
|