@torrent-tv/proxy 2.69.0 → 2.69.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -189,3 +189,66 @@ test("the capacity follows the store's live allowance", () => {
189
189
  lru.setCapacity(0);
190
190
  assert.equal(lru.capacity, 2, "a capacity below one is refused, not obeyed");
191
191
  });
192
+
193
+ test("the demand is the union of the readers' windows, not their sum", () => {
194
+ const lru = new PieceLru(88);
195
+ // Two readers of one file — picture and sound — overlap by construction.
196
+ // Summing them would say the store is short when it is not.
197
+ lru.protect("video", 100, 149);
198
+ lru.protect("audio", 130, 179);
199
+
200
+ const demand = lru.demand();
201
+ assert.equal(demand.readers, 2);
202
+ assert.equal(demand.unionPieces, 80, "100..179 is eighty pieces, not a hundred");
203
+ assert.equal(demand.widestPieces, 50);
204
+ assert.equal(demand.capacity, 88);
205
+
206
+ lru.protect("second-viewer", 900, 979);
207
+ assert.equal(lru.demand().unionPieces, 160, "windows that do not touch add up");
208
+
209
+ lru.unprotect("second-viewer");
210
+ lru.unprotect("audio");
211
+ lru.unprotect("video");
212
+ assert.deepEqual(
213
+ lru.demand(),
214
+ { readers: 0, unionPieces: 0, widestPieces: 0, capacity: 88 },
215
+ "no reader asking for anything is not the same as asking for one piece"
216
+ );
217
+ });
218
+
219
+ test("an eviction says whether it had to take a piece a reader declared", () => {
220
+ const lru = new PieceLru(3);
221
+ lru.touch(10);
222
+ lru.touch(11);
223
+ lru.touch(12);
224
+ lru.protect("video", 11, 12);
225
+
226
+ const spare = lru.evictionChoice();
227
+ assert.equal(spare.index, 10, "the piece outside every window goes first");
228
+ assert.equal(spare.protectionYielded, false);
229
+ assert.equal(spare.distance, 1, "one piece away from the window at 11");
230
+
231
+ // Nothing spare left: both survivors are inside the declared window.
232
+ lru.remove(10);
233
+ const forced = lru.evictionChoice();
234
+ assert.equal(forced.index, 11);
235
+ assert.equal(forced.protectionYielded, true, "the store is holding less than it is asked to");
236
+ assert.equal(forced.distance, 0, "inside a window");
237
+
238
+ assert.equal(lru.evictionCandidate(), 11, "the older answer is the same choice");
239
+ });
240
+
241
+ test("with nothing declared there is no distance to report", () => {
242
+ const lru = new PieceLru(2);
243
+ lru.touch(7);
244
+ const choice = lru.evictionChoice();
245
+ assert.equal(choice.index, 7);
246
+ assert.equal(choice.distance, -1, "-1 is absence, and 0 would read as inside a window");
247
+
248
+ lru.pin(7);
249
+ assert.deepEqual(
250
+ lru.evictionChoice(),
251
+ { index: null, protectionYielded: false, distance: -1 },
252
+ "a pinned piece is never a candidate, and says so without a distance"
253
+ );
254
+ });
@@ -132,3 +132,52 @@ test("pinned pieces are never evicted, and the pin count is reported", async ()
132
132
  await fs.rm(directory, { recursive: true, force: true });
133
133
  }
134
134
  });
135
+
136
+ test("the store says why it spills: what is asked of it, what it had to take, how soon it came back", async () => {
137
+ const capacity = 4;
138
+ const { store, directory } = await makeStore(capacity);
139
+ try {
140
+ // A reader declaring more than the store may hold. This is the shape the
141
+ // field session of 2026-09-02 is suspected of — 88 slots against an
142
+ // encoder running 120-380 s ahead of a viewer, half the reads missing —
143
+ // and nothing recorded it (roadmap item 9).
144
+ store.protectRange("video", 0, 9);
145
+ for (let index = 0; index < 10; index += 1) {
146
+ await put(store, index, pieceOf(index));
147
+ }
148
+
149
+ const asked = store.stats();
150
+ assert.equal(asked.demand.readers, 1);
151
+ assert.equal(asked.demand.unionPieces, 10);
152
+ assert.equal(asked.demand.capacity, capacity);
153
+ assert.ok(
154
+ asked.demand.unionPieces > asked.demand.capacity,
155
+ "a reader asking for more than the store holds is arithmetic, not a policy fault"
156
+ );
157
+ assert.ok(
158
+ asked.evictedProtected > 0,
159
+ "every eviction here had to take a piece the reader had declared"
160
+ );
161
+
162
+ // Read back the pieces that were spilled: each one comes home, and the
163
+ // store says how long it had been away.
164
+ for (let index = 0; index < 10; index += 1) {
165
+ const bytes = await get(store, index);
166
+ assert.ok(bytes.equals(pieceOf(index)), `piece ${index} came back changed`);
167
+ }
168
+
169
+ const after = store.stats();
170
+ assert.ok(after.revivalAgeSamples > 0, "pieces came back and their age was recorded");
171
+ assert.equal(typeof after.revivalAgeMedianMs, "number");
172
+ assert.ok(
173
+ after.revivedWithinFiveSeconds > 0,
174
+ "a piece wanted again seconds after it left should not have left"
175
+ );
176
+
177
+ store.releaseProtection("video");
178
+ assert.equal(store.stats().demand.readers, 0, "a reader that ends stops being counted");
179
+ } finally {
180
+ store.destroy(() => undefined);
181
+ await fs.rm(directory, { recursive: true, force: true });
182
+ }
183
+ });