atagen

malice

public
Star0
Watch0
a6320fb35dc65d5edb74bcf9692c022cf00b436d
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git

Blame: web/test/engine-build.test.ts

d9be72fdb393atagen2026-10-26 09:23 UTC1
import assert from 'node:assert/strict';
d9be72fdb393atagen2026-10-26 09:23 UTC2
import { test } from 'node:test';
5d6f6e2eb5a5atagen2026-10-27 05:42 UTC3
import { compareBuilds, helloAction, mayAutoReload, retryDelay, within } from '../src/lib/engine-build.ts';
d9be72fdb393atagen2026-10-26 09:23 UTC4
d9be72fdb393atagen2026-10-26 09:23 UTC5
test('builds order by timestamp then tag', () => {
d9be72fdb393atagen2026-10-26 09:23 UTC6
  assert.ok((compareBuilds('200-aaa', '100-zzz') ?? 0) > 0);
d9be72fdb393atagen2026-10-26 09:23 UTC7
  assert.ok((compareBuilds('100-aaa', '200-aaa') ?? 0) < 0);
d9be72fdb393atagen2026-10-26 09:23 UTC8
  assert.ok((compareBuilds('100-abc', '100-abd') ?? 0) < 0);
d9be72fdb393atagen2026-10-26 09:23 UTC9
  assert.equal(compareBuilds('100-abc', '100-abc'), 0);
d9be72fdb393atagen2026-10-26 09:23 UTC10
});
d9be72fdb393atagen2026-10-26 09:23 UTC11
d9be72fdb393atagen2026-10-26 09:23 UTC12
test('timestamps compare numerically, not as strings', () => {
d9be72fdb393atagen2026-10-26 09:23 UTC13
  assert.ok((compareBuilds('1000-a', '999-a') ?? 0) > 0);
d9be72fdb393atagen2026-10-26 09:23 UTC14
});
d9be72fdb393atagen2026-10-26 09:23 UTC15
d9be72fdb393atagen2026-10-26 09:23 UTC16
test('malformed build ids never order', () => {
d9be72fdb393atagen2026-10-26 09:23 UTC17
  assert.equal(compareBuilds('dev', '100-a'), null);
d9be72fdb393atagen2026-10-26 09:23 UTC18
  assert.equal(compareBuilds('100-a', ''), null);
d9be72fdb393atagen2026-10-26 09:23 UTC19
  assert.equal(helloAction('100-a', 'garbage'), 'ignore');
d9be72fdb393atagen2026-10-26 09:23 UTC20
});
d9be72fdb393atagen2026-10-26 09:23 UTC21
d9be72fdb393atagen2026-10-26 09:23 UTC22
test('a worker yields to a newer peer', () => {
d9be72fdb393atagen2026-10-26 09:23 UTC23
  assert.equal(helloAction('100-a', '200-b'), 'yield');
d9be72fdb393atagen2026-10-26 09:23 UTC24
});
d9be72fdb393atagen2026-10-26 09:23 UTC25
d9be72fdb393atagen2026-10-26 09:23 UTC26
test('a worker announces itself to an older peer', () => {
d9be72fdb393atagen2026-10-26 09:23 UTC27
  assert.equal(helloAction('200-b', '100-a'), 'announce');
d9be72fdb393atagen2026-10-26 09:23 UTC28
});
d9be72fdb393atagen2026-10-26 09:23 UTC29
d9be72fdb393atagen2026-10-26 09:23 UTC30
test('the same build coexists', () => {
d9be72fdb393atagen2026-10-26 09:23 UTC31
  assert.equal(helloAction('100-a', '100-a'), 'ignore');
d9be72fdb393atagen2026-10-26 09:23 UTC32
});
d9be72fdb393atagen2026-10-26 09:23 UTC33
d9be72fdb393atagen2026-10-26 09:23 UTC34
test('two workers never both yield', () => {
d9be72fdb393atagen2026-10-26 09:23 UTC35
  const pairs: [string, string][] = [['100-a', '200-b'], ['100-b', '100-a'], ['5-x', '50-x']];
d9be72fdb393atagen2026-10-26 09:23 UTC36
  for (const [one, two] of pairs) {
d9be72fdb393atagen2026-10-26 09:23 UTC37
    const actions = [helloAction(one, two), helloAction(two, one)];
d9be72fdb393atagen2026-10-26 09:23 UTC38
    assert.equal(actions.filter((a) => a === 'yield').length, 1);
d9be72fdb393atagen2026-10-26 09:23 UTC39
  }
d9be72fdb393atagen2026-10-26 09:23 UTC40
});
d9be72fdb393atagen2026-10-26 09:23 UTC41
d9be72fdb393atagen2026-10-26 09:23 UTC42
test('auto reload is limited to once per guard window', () => {
d9be72fdb393atagen2026-10-26 09:23 UTC43
  assert.equal(mayAutoReload(1_000_000, null), true);
d9be72fdb393atagen2026-10-26 09:23 UTC44
  assert.equal(mayAutoReload(1_030_000, 1_000_000), false);
d9be72fdb393atagen2026-10-26 09:23 UTC45
  assert.equal(mayAutoReload(1_060_000, 1_000_000), true);
d9be72fdb393atagen2026-10-26 09:23 UTC46
});
d9be72fdb393atagen2026-10-26 09:23 UTC47
d9be72fdb393atagen2026-10-26 09:23 UTC48
test('retry delay backs off and caps', () => {
d9be72fdb393atagen2026-10-26 09:23 UTC49
  assert.deepEqual([0, 1, 2, 3, 4, 10].map(retryDelay), [1000, 2000, 4000, 8000, 8000, 8000]);
d9be72fdb393atagen2026-10-26 09:23 UTC50
});
5d6f6e2eb5a5atagen2026-10-27 05:42 UTC51
5d6f6e2eb5a5atagen2026-10-27 05:42 UTC52
test('a release wait ends when the engine answers, fails, or goes quiet', async () => {
5d6f6e2eb5a5atagen2026-10-27 05:42 UTC53
  const start = Date.now();
5d6f6e2eb5a5atagen2026-10-27 05:42 UTC54
  await within(Promise.resolve(), 5_000);
5d6f6e2eb5a5atagen2026-10-27 05:42 UTC55
  await within(Promise.reject(new Error('gone')), 5_000);
5d6f6e2eb5a5atagen2026-10-27 05:42 UTC56
  assert.ok(Date.now() - start < 1_000);
5d6f6e2eb5a5atagen2026-10-27 05:42 UTC57
  await within(new Promise(() => undefined), 20);
5d6f6e2eb5a5atagen2026-10-27 05:42 UTC58
});