Add template animation editor
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const crypto = require('node:crypto');
|
||||
|
||||
const {
|
||||
collectLiveConnections,
|
||||
isClientNameAvailable,
|
||||
normalizeClientName,
|
||||
normalizeDeviceId,
|
||||
withClientNameReservation
|
||||
} = require('../src/data/client-name-check');
|
||||
|
||||
test('normalize helpers trim names and sanitize device ids', () => {
|
||||
assert.equal(normalizeClientName(' Screen A '), 'Screen A');
|
||||
assert.equal(normalizeClientName(''), '');
|
||||
assert.equal(normalizeDeviceId(' device-01 /abc!? '), 'device-01abc');
|
||||
assert.equal(normalizeDeviceId('x'.repeat(200)).length, 128);
|
||||
});
|
||||
|
||||
test('collectLiveConnections returns an array safely', () => {
|
||||
assert.deepEqual(collectLiveConnections(null), []);
|
||||
assert.deepEqual(collectLiveConnections([{ clientName: 'A' }]), [{ clientName: 'A' }]);
|
||||
});
|
||||
|
||||
test('isClientNameAvailable rejects matching db rows and live connections', async () => {
|
||||
const pool = {
|
||||
async query(sql, params) {
|
||||
assert.match(sql, /FROM d_onboarding_devices/);
|
||||
assert.deepEqual(params, ['Screen A', 'device-01']);
|
||||
return [[{ device_id: 'device-99' }]];
|
||||
}
|
||||
};
|
||||
|
||||
assert.equal(await isClientNameAvailable(pool, ' Screen A ', 'device-01', []), false);
|
||||
assert.equal(await isClientNameAvailable(null, 'Screen A', 'device-01', [{ clientName: 'screen a', clientId: 'device-99' }]), false);
|
||||
assert.equal(await isClientNameAvailable(null, 'Screen A', 'device-01', [{ clientName: 'screen a', clientId: 'device-01' }]), true);
|
||||
assert.equal(await isClientNameAvailable(null, ' ', 'device-01', []), false);
|
||||
});
|
||||
|
||||
test('withClientNameReservation acquires and releases locks around the handler', async () => {
|
||||
const calls = [];
|
||||
const lockName = `ps_client_name_${crypto.createHash('sha1').update('screen a').digest('hex')}`;
|
||||
const connection = {
|
||||
async query(sql, params) {
|
||||
calls.push({ sql, params });
|
||||
if (sql.includes('GET_LOCK')) {
|
||||
return [[{ lock_result: 1 }]];
|
||||
}
|
||||
return [[{ released: 1 }]];
|
||||
},
|
||||
release() {
|
||||
calls.push({ sql: 'RELEASE_CONNECTION' });
|
||||
}
|
||||
};
|
||||
const pool = {
|
||||
async getConnection() {
|
||||
return connection;
|
||||
}
|
||||
};
|
||||
|
||||
const result = await withClientNameReservation(pool, ' Screen A ', async () => 'ok');
|
||||
|
||||
assert.equal(result, 'ok');
|
||||
assert.deepEqual(calls, [
|
||||
{ sql: 'SELECT GET_LOCK(?, 5) AS lock_result', params: [lockName] },
|
||||
{ sql: 'SELECT RELEASE_LOCK(?)', params: [lockName] },
|
||||
{ sql: 'RELEASE_CONNECTION' }
|
||||
]);
|
||||
});
|
||||
|
||||
test('withClientNameReservation rejects busy names', async () => {
|
||||
const connection = {
|
||||
async query(sql) {
|
||||
if (sql.includes('GET_LOCK')) {
|
||||
return [[{ lock_result: 0 }]];
|
||||
}
|
||||
throw new Error('unexpected query');
|
||||
},
|
||||
release() {}
|
||||
};
|
||||
const pool = {
|
||||
async getConnection() {
|
||||
return connection;
|
||||
}
|
||||
};
|
||||
|
||||
await assert.rejects(
|
||||
() => withClientNameReservation(pool, 'Screen A', async () => 'ok'),
|
||||
(error) => error && error.statusCode === 409 && error.message === 'Client name is busy. Please try again.'
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user