Release v2.19.1: repair managed font references
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 1m17s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 32s

This commit is contained in:
lzstealth committed 2026-10-24 20:26:00 +01:00
1 parent 90253e98a4
commit 9ca372429b
11 files changed
+212 -23

No files matched your search

+63
View File
@@ -9,6 +9,11 @@ function createPool(responses) {
const queries = [];
return {
queries,
async getConnection() { return this; },
async beginTransaction() { queries.push(['START TRANSACTION']); },
async commit() { queries.push(['COMMIT']); },
async rollback() { queries.push(['ROLLBACK']); },
release() { queries.push(['RELEASE CONNECTION']); },
async query(sql, params) {
queries.push([sql, params]);
const text = String(sql);
@@ -200,4 +205,62 @@ test('2.17.1 migration removes obsolete dashboard.allow grants and permission',
assert.ok(pool.queries.some(function ([sql, params]) {
return String(sql).includes('DELETE FROM a_permissions') && params[0] === 'dashboard.allow';
}));
});
test('2.19.1 migration rebuilds only managed font references for all content in a transaction', async () => {
const pool = createPool([
{ match: sql => sql.includes('information_schema.COLUMNS'), result: [[{ column_count: 1 }]] },
{ match: sql => sql.includes('information_schema.TABLES'), result: [[{ table_count: 0 }]] },
{
match: (sql, params) => sql.startsWith('SELECT id, content_json') && params[0] === 0,
result: [[{ id: 117, content_json: JSON.stringify({ second_place: {
font_family: 'Arial', value: '<span style="font-family: &#39;Ubuntu Regular&#39;, Helvetica, sans-serif;">Second</span>',
source_id: 4, image: '/media/uploads/keep.png'
} }) }]]
},
{
match: (sql, params) => sql.startsWith('SELECT id, content_json') && params[0] === 117,
result: [[{ id: 118, content_json: { hero: { font_family: 'Acme Display' } } }]]
},
{
match: (sql, params) => sql.startsWith('SELECT id, template_id, region_key') && params[0] === 0,
result: [[{ id: 900, template_id: 42, region_key: 'hero', default_content_json: { font_family: 'Acme Display', feed_id: 8 } }]]
}
]);
const pending = await getPendingMigrations(pool, { currentVersion: '2.19.0' });
assert.deepEqual(pending.map(migration => migration.version), ['2.19.1']);
await pending[0].run(pool);
const deletions = pool.queries.filter(([sql]) => sql.startsWith('DELETE'));
assert.deepEqual(deletions, [['DELETE FROM c_content_references WHERE reference_type = ?', ['font-family']]]);
const inserted = pool.queries.filter(([sql]) => sql.startsWith('INSERT IGNORE INTO c_content_references'))
.flatMap(([, params]) => params[0]);
assert.deepEqual(inserted.map(row => row.slice(0, 5)), [
['slide', 117, 'second_place', 'font-family', 'ubuntu regular'],
['slide', 118, 'hero', 'font-family', 'acme display'],
['template', 42, 'hero', 'font-family', 'acme display']
]);
assert.ok(pool.queries.some(([sql, params]) => sql.startsWith('SELECT id, content_json') && params[0] === 118));
assert.ok(pool.queries.some(([sql, params]) => sql.startsWith('SELECT id, template_id, region_key') && params[0] === 900));
assert.ok(!pool.queries.some(([sql]) => /^(UPDATE|ALTER|TRUNCATE)/.test(sql)));
assert.deepEqual(pool.queries.slice(-2), [['COMMIT'], ['RELEASE CONNECTION']]);
assert.deepEqual(await getPendingMigrations(pool, { currentVersion: '2.19.1' }), []);
});
test('2.19.1 font repair rolls back and releases its connection on failure', async () => {
const pool = createPool([
{ match: sql => sql.includes('information_schema.COLUMNS'), result: [[{ column_count: 1 }]] },
{ match: sql => sql.includes('information_schema.TABLES'), result: [[{ table_count: 0 }]] }
]);
const [migration] = await getPendingMigrations(pool, { currentVersion: '2.19.0' });
const query = pool.query.bind(pool);
pool.query = async function (sql, params) {
if (sql.startsWith('SELECT id, content_json')) throw new Error('read failed');
return query(sql, params);
};
await assert.rejects(migration.run(pool), /read failed/);
assert.deepEqual(pool.queries.slice(-2), [['ROLLBACK'], ['RELEASE CONNECTION']]);
assert.ok(!pool.queries.some(([sql]) => sql === 'COMMIT'));
});