1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
// Exercise the production refill scheduler with delayed and sparse sources.
// Run: bun tools/pager-loading-test.js
import { readFileSync } from 'node:fs';
import vm from 'node:vm';
import assert from 'node:assert/strict';
const source = readFileSync(new URL('../src/features/messages.js', import.meta.url), 'utf8');
const scheduler = source.slice(source.indexOf(' const PAGER_INITIAL ='), source.indexOf(' // Slides for feed items', source.indexOf(' const PAGER_INITIAL =')));
function fixture(kind = 'images', grid = false) {
let clock = 100000, calls = 0, pending = null, count = 3;
const groups = Array.from({ length: 300 }, () => ({}));
const cache = { shown: 3, notes: Array(3), stopped: false };
const index = { until: 10000, images: new Map(), videos: new Map() };
const p = { kind, cur: { closest: () => groups[0] } };
const more = async () => {
calls++;
if (pending) await pending;
count += 10;
cache.shown += 10; cache.notes.length += 10;
index.until -= 100;
};
const src = { c: cache, more, done: () => false };
const ctx = vm.createContext({
pager: p, pagerGroups: () => groups.slice(0, count),
pagerSource: () => grid ? null : src, feedNow: () => cache, mediaIndex: () => index, feedDef: () => ({}),
crawlMedia: (c, k) => { assert.equal(c, cache); assert.equal(k, kind); return more(); },
growPager: () => {}, Date: { now: () => clock },
});
vm.runInContext(scheduler, ctx);
return {
ctx, p, src, cache, index, load: () => ctx.pagerLoadAhead(),
go: (i) => { p.cur = { closest: () => groups[i] }; },
advance: () => { clock += 11000; },
delay: () => { let resolve; pending = new Promise((r) => { resolve = r; }); return () => { pending = null; resolve(); }; },
count: () => count, calls: () => calls,
};
}
for (const grid of [false, true]) for (const kind of ['images', 'videos']) {
const f = fixture(kind, grid);
await f.load();
assert.equal(f.calls(), 3, 'opening starts loading immediately to at least 30 posts');
f.advance(); await f.load();
assert.equal(f.calls(), 3, 'a full buffer does not download forever');
f.go(29); f.advance();
const finish = f.delay();
const loading = f.load();
assert.equal(f.calls(), 4, 'refill starts well before the end');
f.go(0); await f.load();
assert.equal(f.calls(), 4, 'wrapping during a request does not start a concurrent one');
finish(); await loading;
assert.equal(f.count(), 53, 'refill continues after wrapping, keeping 20 beyond the furthest post');
console.log('✓ early loading and wrap refill:', grid ? 'grid' : 'feed/profile', kind);
}
{
const f = fixture();
f.src.more = async () => { f.cache.notes.length++; };
await f.load();
assert.equal(f.cache.notes.length, 11, 'sparse results are limited to eight requests per run');
f.advance(); await f.load();
assert.equal(f.cache.notes.length, 19, 'timer can resume sparse results from the first post');
}
{
const f = fixture();
let calls = 0;
f.src.more = async () => { calls++; };
await f.load(); await f.load();
assert.equal(calls, 1, 'an empty result backs off');
f.advance(); await f.load();
assert.equal(calls, 2, 'an empty source can retry');
f.src.done = () => true;
f.advance(); await f.load();
assert.equal(calls, 2, 'an exhausted source is not requested');
}
{
const f = fixture();
const finish = f.delay(), loading = f.load();
f.ctx.pager = { kind: 'videos' };
finish(); await loading;
assert.equal(f.calls(), 1, 'closing or switching pagers stops the old refill');
}
console.log('✓ sparse sources, backoff, exhaustion, and pager lifecycle');
|