pzp-gc/test/dict-ghosts.test.js

119 lines
3.3 KiB
JavaScript

const test = require('node:test')
const assert = require('node:assert')
const p = require('node:util').promisify
const { createPeer } = require('./util')
function getFields(msgs) {
return msgs
.map((msg) => msg.data?.update)
.filter((x) => !!x)
.map((x) => x.age ?? x.name)
}
function isErased(msg) {
return !msg.data
}
function isDeleted(msg) {
return !msg
}
function isPresent(msg) {
return !!msg.data.update
}
test('Dict ghosts', async (t) => {
const alice = createPeer({
name: 'alice',
dict: { ghostSpan: 2 },
})
await alice.db.loaded()
// Alice creates her own account
const aliceID = await p(alice.db.account.create)({
subdomain: 'account',
_nonce: 'alice',
})
// Alice constructs a dict
await p(alice.dict.load)(aliceID)
await p(alice.dict.update)('profile', { name: 'alice' })
await p(alice.dict.update)('profile', { age: 24 })
await p(alice.dict.update)('profile', { name: 'Alice' })
await p(alice.dict.update)('profile', { age: 25 })
await p(alice.dict.update)('profile', { name: 'ALICE' })
const dictID = alice.dict.getFeedID('profile')
let mootID
let msgID1
let msgID2
let msgID3
let msgID4
let msgID5
for await (const rec of alice.db.records()) {
if (rec.msg.metadata.dataSize === 0) mootID = rec.id
if (rec.msg.data?.update?.name === 'alice') msgID1 = rec.id
if (rec.msg.data?.update?.age === 24) msgID2 = rec.id
if (rec.msg.data?.update?.name === 'Alice') msgID3 = rec.id
if (rec.msg.data?.update?.age === 25) msgID4 = rec.id
if (rec.msg.data?.update?.name === 'ALICE') msgID5 = rec.id
}
const msgs = []
for await (const msg of alice.db.msgs()) {
msgs.push(msg)
}
// Assert situation before GC
assert.deepEqual(
getFields(msgs),
['alice', 24, 'Alice', 25, 'ALICE'],
'has all dict msgs'
)
assert.ok(isErased(await p(alice.db.get)(mootID)), 'moot by def erased')
assert.ok(isPresent(await p(alice.db.get)(msgID1)), 'msg1 exists')
assert.ok(isPresent(await p(alice.db.get)(msgID2)), 'msg2 exists')
assert.ok(isPresent(await p(alice.db.get)(msgID3)), 'msg3 exists')
assert.ok(isPresent(await p(alice.db.get)(msgID4)), 'msg4 exists')
assert.ok(isPresent(await p(alice.db.get)(msgID5)), 'msg5 exists')
assert.deepEqual(
await p(alice.db.log.stats)(),
{ totalBytes: 4520, deletedBytes: 0 },
'log stats before'
)
// Perform garbage collection
alice.goals.set(aliceID, 'all')
alice.goals.set(dictID, 'dict')
await p(alice.gc.forceImmediately)()
const msgs2 = []
for await (const msg of alice.db.msgs()) {
msgs2.push(msg)
}
// Assert situation after GC
assert.deepEqual(
getFields(msgs2),
[25, 'ALICE'],
'alice has only field root msgs'
)
assert.deepEqual(
await p(alice.db.log.stats)(),
{ totalBytes: 3121, deletedBytes: 0 },
'log stats after'
)
assert.ok(isErased(await p(alice.db.get)(mootID)), 'moot by def erased')
assert.ok(isDeleted(await p(alice.db.get)(msgID1)), 'msg1 deleted')
assert.ok(isDeleted(await p(alice.db.get)(msgID2)), 'msg2 deleted') // ghost!
assert.ok(isErased(await p(alice.db.get)(msgID3)), 'msg3 erased')
assert.ok(isPresent(await p(alice.db.get)(msgID4)), 'msg4 exists')
assert.ok(isPresent(await p(alice.db.get)(msgID5)), 'msg5 exists')
assert.deepEqual(alice.db.ghosts.get(dictID), [msgID2])
await p(alice.close)(true)
})