mirror of https://codeberg.org/pzp/pzp-dict.git
210 lines
6.2 KiB
JavaScript
210 lines
6.2 KiB
JavaScript
const test = require('node:test')
|
|
const assert = require('node:assert')
|
|
const path = require('path')
|
|
const os = require('os')
|
|
const rimraf = require('rimraf')
|
|
const MsgV4 = require('pzp-db/msg-v4')
|
|
const Keypair = require('pzp-keypair')
|
|
const p = require('util').promisify
|
|
const { createPeer } = require('./util')
|
|
|
|
const DIR = path.join(os.tmpdir(), 'pzp-dict')
|
|
rimraf.sync(DIR)
|
|
|
|
const aliceKeypair = Keypair.generate('ed25519', 'alice')
|
|
|
|
async function getMsgID(peer, index, domain) {
|
|
let i = 0
|
|
for await (const rec of peer.db.records()) {
|
|
if (rec.msg.metadata.domain === domain && !!rec.msg.data) {
|
|
if (i === index) return rec.id
|
|
i++
|
|
}
|
|
}
|
|
throw new Error('msg not found')
|
|
}
|
|
|
|
let peer
|
|
let aliceID
|
|
test('setup', async (t) => {
|
|
peer = createPeer({
|
|
global: {
|
|
keypair: aliceKeypair,
|
|
path: DIR,
|
|
},
|
|
dict: { ghostSpan: 40 },
|
|
})
|
|
|
|
await peer.db.loaded()
|
|
|
|
aliceID = await p(peer.db.account.create)({
|
|
subdomain: 'account',
|
|
_nonce: 'alice',
|
|
})
|
|
await p(peer.dict.load)(aliceID)
|
|
await p(peer.dict.load)(aliceID) // on purpose test that re-load is idempotent
|
|
|
|
peer.dict.setGhostSpan(4)
|
|
assert.equal(peer.dict.getGhostSpan(), 4, 'getGhostSpan')
|
|
})
|
|
|
|
test('Dict update() and get()', async (t) => {
|
|
assert(
|
|
await p(peer.dict.update)('profile', { name: 'alice' }),
|
|
'update .name'
|
|
)
|
|
const UPDATE0_ID = await getMsgID(peer, 0, 'dict_v1__profile')
|
|
assert.deepEqual(await p(peer.dict.read)(aliceID, 'profile'), { name: 'alice' }, 'get')
|
|
|
|
const fieldRoots1 = peer.dict._getFieldRoots('profile')
|
|
assert.deepEqual(fieldRoots1, { name: [UPDATE0_ID] }, 'fieldRoots')
|
|
|
|
assert(await p(peer.dict.update)('profile', { age: 20 }), 'update .age')
|
|
const UPDATE1_ID = await getMsgID(peer, 1, 'dict_v1__profile')
|
|
assert.deepEqual(
|
|
await p(peer.dict.read)(aliceID, 'profile'),
|
|
{ name: 'alice', age: 20 },
|
|
'get'
|
|
)
|
|
|
|
const fieldRoots2 = peer.dict._getFieldRoots('profile')
|
|
assert.deepEqual(
|
|
fieldRoots2,
|
|
{ name: [UPDATE0_ID], age: [UPDATE1_ID] },
|
|
'fieldRoots'
|
|
)
|
|
|
|
assert.equal(
|
|
await p(peer.dict.update)('profile', { name: 'alice' }),
|
|
false,
|
|
'redundant update .name'
|
|
)
|
|
assert.deepEqual(
|
|
await p(peer.dict.read)(aliceID, 'profile'),
|
|
{ name: 'alice', age: 20 },
|
|
'get'
|
|
)
|
|
|
|
assert.equal(
|
|
await p(peer.dict.update)('profile', { name: 'Alice' }),
|
|
true,
|
|
'update .name'
|
|
)
|
|
const UPDATE2_ID = await getMsgID(peer, 2, 'dict_v1__profile')
|
|
assert.deepEqual(
|
|
await p(peer.dict.read)(aliceID, 'profile'),
|
|
{ name: 'Alice', age: 20 },
|
|
'get'
|
|
)
|
|
|
|
const fieldRoots3 = peer.dict._getFieldRoots('profile')
|
|
assert.deepEqual(
|
|
fieldRoots3,
|
|
{ age: [UPDATE1_ID], name: [UPDATE2_ID] },
|
|
'fieldRoots'
|
|
)
|
|
})
|
|
|
|
test('Dict squeeze', async (t) => {
|
|
assert(await p(peer.dict.update)('profile', { age: 21 }), 'update .age')
|
|
assert(await p(peer.dict.update)('profile', { age: 22 }), 'update .age')
|
|
assert(await p(peer.dict.update)('profile', { age: 23 }), 'update .age')
|
|
const UPDATE2_ID = await getMsgID(peer, 2, 'dict_v1__profile')
|
|
const UPDATE5_ID = await getMsgID(peer, 5, 'dict_v1__profile')
|
|
|
|
const fieldRoots4 = peer.dict._getFieldRoots('profile')
|
|
assert.deepEqual(
|
|
fieldRoots4,
|
|
{ name: [UPDATE2_ID], age: [UPDATE5_ID] },
|
|
'fieldRoots'
|
|
)
|
|
|
|
assert.equal(await p(peer.dict._squeezePotential)('profile'), 3, 'squeezePotential=3')
|
|
assert.equal(await p(peer.dict.squeeze)('profile'), true, 'squeezed')
|
|
const UPDATE6_ID = await getMsgID(peer, 6, 'dict_v1__profile')
|
|
|
|
const fieldRoots5 = peer.dict._getFieldRoots('profile')
|
|
assert.deepEqual(
|
|
fieldRoots5,
|
|
{ name: [UPDATE6_ID], age: [UPDATE6_ID] },
|
|
'fieldRoots'
|
|
)
|
|
|
|
assert.equal(await p(peer.dict._squeezePotential)('profile'), 0, 'squeezePotential=0')
|
|
assert.equal(
|
|
await p(peer.dict.squeeze)('profile'),
|
|
false,
|
|
'squeeze idempotent'
|
|
)
|
|
|
|
const fieldRoots6 = peer.dict._getFieldRoots('profile')
|
|
assert.deepEqual(fieldRoots6, fieldRoots5, 'fieldRoots')
|
|
})
|
|
|
|
test('Dict isGhostable', async (t) => {
|
|
const moot = MsgV4.createMoot(aliceID, 'dict_v1__profile', aliceKeypair)
|
|
const mootID = MsgV4.getMsgID(moot)
|
|
|
|
assert.equal(mootID, peer.dict.getFeedID('profile'), 'getFeedID')
|
|
|
|
const tangle = await p(peer.db.getTangle)(mootID)
|
|
const msgIDs = tangle.topoSort()
|
|
|
|
const fieldRoots = peer.dict._getFieldRoots('profile')
|
|
assert.deepEqual(fieldRoots.age, [msgIDs[7]])
|
|
|
|
// Remember from the setup, that ghostSpan=4
|
|
assert.equal(msgIDs.length, 8)
|
|
assert.equal(await p(peer.dict.isGhostable)(msgIDs[0], mootID), false) // moot
|
|
assert.equal(await p(peer.dict.isGhostable)(msgIDs[1], mootID), false)
|
|
assert.equal(await p(peer.dict.isGhostable)(msgIDs[2], mootID), false)
|
|
assert.equal(await p(peer.dict.isGhostable)(msgIDs[3], mootID), true) // in ghostSpan
|
|
assert.equal(await p(peer.dict.isGhostable)(msgIDs[4], mootID), true) // in ghostSpan
|
|
assert.equal(await p(peer.dict.isGhostable)(msgIDs[5], mootID), true) // in ghostSpan
|
|
assert.equal(await p(peer.dict.isGhostable)(msgIDs[6], mootID), true) // in ghostSpan
|
|
assert.equal(await p(peer.dict.isGhostable)(msgIDs[7], mootID), false) // field root
|
|
})
|
|
|
|
test('Dict receives old branched update', async (t) => {
|
|
const UPDATE6_ID = await getMsgID(peer, 6, 'dict_v1__profile')
|
|
|
|
const moot = MsgV4.createMoot(aliceID, 'dict_v1__profile', aliceKeypair)
|
|
const mootID = MsgV4.getMsgID(moot)
|
|
|
|
assert.equal(await p(peer.dict.minRequiredDepth)(mootID), 7, 'minRequiredDepth')
|
|
|
|
const tangle = new MsgV4.Tangle(mootID)
|
|
tangle.add(mootID, moot)
|
|
await p(peer.db.add)(moot, mootID)
|
|
|
|
const msg = MsgV4.create({
|
|
keypair: aliceKeypair,
|
|
domain: 'dict_v1__profile',
|
|
account: aliceID,
|
|
accountTips: [aliceID],
|
|
data: { update: { age: 2 }, supersedes: [] },
|
|
tangles: {
|
|
[mootID]: tangle,
|
|
},
|
|
})
|
|
const rec = await p(peer.db.add)(msg, mootID)
|
|
|
|
const fieldRoots7 = peer.dict._getFieldRoots('profile')
|
|
assert.deepEqual(
|
|
fieldRoots7,
|
|
{
|
|
name: [UPDATE6_ID],
|
|
age: [UPDATE6_ID, rec.id],
|
|
},
|
|
'fieldRoots'
|
|
)
|
|
|
|
assert.equal(await p(peer.dict.minRequiredDepth)(mootID), 1, 'minRequiredDepth')
|
|
|
|
assert.equal(await p(peer.dict._squeezePotential)('profile'), 6, 'squeezePotential=6')
|
|
})
|
|
|
|
test('teardown', async (t) => {
|
|
await p(peer.close)(true)
|
|
})
|