|
@@ -1,72 +0,0 @@
|
|
|
-import { describe, expect, test } from "bun:test"
|
|
|
|
|
-import { Lock } from "@/util/lock"
|
|
|
|
|
-
|
|
|
|
|
-function tick() {
|
|
|
|
|
- return new Promise<void>((r) => queueMicrotask(r))
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-async function flush(n = 5) {
|
|
|
|
|
- for (let i = 0; i < n; i++) await tick()
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-describe("util.lock", () => {
|
|
|
|
|
- test("writer exclusivity: blocks reads and other writes while held", async () => {
|
|
|
|
|
- const key = "lock:" + Math.random().toString(36).slice(2)
|
|
|
|
|
-
|
|
|
|
|
- const state = {
|
|
|
|
|
- writer2: false,
|
|
|
|
|
- reader: false,
|
|
|
|
|
- writers: 0,
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Acquire writer1
|
|
|
|
|
- using writer1 = await Lock.write(key)
|
|
|
|
|
- state.writers++
|
|
|
|
|
- expect(state.writers).toBe(1)
|
|
|
|
|
-
|
|
|
|
|
- // Start writer2 candidate (should block)
|
|
|
|
|
- const writer2Task = (async () => {
|
|
|
|
|
- const w = await Lock.write(key)
|
|
|
|
|
- state.writers++
|
|
|
|
|
- expect(state.writers).toBe(1)
|
|
|
|
|
- state.writer2 = true
|
|
|
|
|
- // Hold for a tick so reader cannot slip in
|
|
|
|
|
- await tick()
|
|
|
|
|
- return w
|
|
|
|
|
- })()
|
|
|
|
|
-
|
|
|
|
|
- // Start reader candidate (should block)
|
|
|
|
|
- const readerTask = (async () => {
|
|
|
|
|
- const r = await Lock.read(key)
|
|
|
|
|
- state.reader = true
|
|
|
|
|
- return r
|
|
|
|
|
- })()
|
|
|
|
|
-
|
|
|
|
|
- // Flush microtasks and assert neither acquired
|
|
|
|
|
- await flush()
|
|
|
|
|
- expect(state.writer2).toBe(false)
|
|
|
|
|
- expect(state.reader).toBe(false)
|
|
|
|
|
-
|
|
|
|
|
- // Release writer1
|
|
|
|
|
- writer1[Symbol.dispose]()
|
|
|
|
|
- state.writers--
|
|
|
|
|
-
|
|
|
|
|
- // writer2 should acquire next
|
|
|
|
|
- const writer2 = await writer2Task
|
|
|
|
|
- expect(state.writer2).toBe(true)
|
|
|
|
|
-
|
|
|
|
|
- // Reader still blocked while writer2 held
|
|
|
|
|
- await flush()
|
|
|
|
|
- expect(state.reader).toBe(false)
|
|
|
|
|
-
|
|
|
|
|
- // Release writer2
|
|
|
|
|
- writer2[Symbol.dispose]()
|
|
|
|
|
- state.writers--
|
|
|
|
|
-
|
|
|
|
|
- // Reader should now acquire
|
|
|
|
|
- const reader = await readerTask
|
|
|
|
|
- expect(state.reader).toBe(true)
|
|
|
|
|
-
|
|
|
|
|
- reader[Symbol.dispose]()
|
|
|
|
|
- })
|
|
|
|
|
-})
|
|
|