mirror of https://codeberg.org/pzp/pzp-db.git
refactor/prettify tests
This commit is contained in:
parent
9356b9b3d9
commit
f40ea71ff9
|
@ -12,217 +12,219 @@ const DIR = path.join(os.tmpdir(), 'ppppp-db-account-add')
|
|||
rimraf.sync(DIR)
|
||||
|
||||
test('account.add()', async (t) => {
|
||||
const keypair1 = Keypair.generate('ed25519', 'alice')
|
||||
const keypair2 = Keypair.generate('ed25519', 'bob')
|
||||
await t.test('Basic usage', async (t) => {
|
||||
const keypair1 = Keypair.generate('ed25519', 'alice')
|
||||
const keypair2 = Keypair.generate('ed25519', 'bob')
|
||||
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair: keypair1, path: DIR })
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair: keypair1, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
const account = await p(peer.db.account.create)({
|
||||
keypair: keypair1,
|
||||
domain: 'person',
|
||||
})
|
||||
await peer.db.loaded()
|
||||
const account = await p(peer.db.account.create)({
|
||||
keypair: keypair1,
|
||||
domain: 'person',
|
||||
})
|
||||
|
||||
assert.equal(peer.db.account.has({ account, keypair: keypair2 }), false)
|
||||
assert.equal(peer.db.account.has({ account, keypair: keypair2 }), false)
|
||||
|
||||
const consent = peer.db.account.consent({ account, keypair: keypair2 })
|
||||
const consent = peer.db.account.consent({ account, keypair: keypair2 })
|
||||
|
||||
const accountRec1 = await p(peer.db.account.add)({
|
||||
account,
|
||||
keypair: keypair2,
|
||||
consent,
|
||||
powers: ['box'],
|
||||
})
|
||||
assert.ok(accountRec1, 'accountRec1 exists')
|
||||
const { id, msg } = accountRec1
|
||||
assert.ok(account, 'id exists')
|
||||
assert.deepEqual(
|
||||
msg.data,
|
||||
{
|
||||
action: 'add',
|
||||
add: {
|
||||
key: {
|
||||
purpose: 'sig',
|
||||
algorithm: 'ed25519',
|
||||
bytes: keypair2.public,
|
||||
const accountRec1 = await p(peer.db.account.add)({
|
||||
account,
|
||||
keypair: keypair2,
|
||||
consent,
|
||||
powers: ['box'],
|
||||
})
|
||||
assert.ok(accountRec1, 'accountRec1 exists')
|
||||
const { id, msg } = accountRec1
|
||||
assert.ok(account, 'id exists')
|
||||
assert.deepEqual(
|
||||
msg.data,
|
||||
{
|
||||
action: 'add',
|
||||
add: {
|
||||
key: {
|
||||
purpose: 'sig',
|
||||
algorithm: 'ed25519',
|
||||
bytes: keypair2.public,
|
||||
},
|
||||
consent,
|
||||
powers: ['box'],
|
||||
},
|
||||
consent,
|
||||
powers: ['box'],
|
||||
},
|
||||
},
|
||||
'msg.data.add NEW KEY'
|
||||
)
|
||||
assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
|
||||
assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
|
||||
assert.equal(msg.metadata.domain, 'person', 'msg.metadata.domain')
|
||||
assert.deepEqual(
|
||||
msg.metadata.tangles,
|
||||
{ [account]: { depth: 1, prev: [account] } },
|
||||
'msg.metadata.tangles'
|
||||
)
|
||||
assert.equal(msg.pubkey, keypair1.public, 'msg.pubkey OLD KEY')
|
||||
'msg.data.add NEW KEY'
|
||||
)
|
||||
assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
|
||||
assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
|
||||
assert.equal(msg.metadata.domain, 'person', 'msg.metadata.domain')
|
||||
assert.deepEqual(
|
||||
msg.metadata.tangles,
|
||||
{ [account]: { depth: 1, prev: [account] } },
|
||||
'msg.metadata.tangles'
|
||||
)
|
||||
assert.equal(msg.pubkey, keypair1.public, 'msg.pubkey OLD KEY')
|
||||
|
||||
assert.equal(peer.db.account.has({ account, keypair: keypair2 }), true)
|
||||
assert.equal(peer.db.account.has({ account, keypair: keypair2 }), true)
|
||||
|
||||
await p(peer.close)()
|
||||
})
|
||||
|
||||
test('keypair with no "add" powers cannot account.add()', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
const keypair1 = Keypair.generate('ed25519', 'alice')
|
||||
const keypair2 = Keypair.generate('ed25519', 'bob')
|
||||
const keypair3 = Keypair.generate('ed25519', 'carol')
|
||||
|
||||
const peer1 = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair: keypair1, path: DIR })
|
||||
|
||||
await peer1.db.loaded()
|
||||
const id = await p(peer1.db.account.create)({
|
||||
keypair: keypair1,
|
||||
domain: 'account',
|
||||
await p(peer.close)()
|
||||
})
|
||||
const msg1 = peer1.db.get(id)
|
||||
|
||||
const { msg: msg2 } = await p(peer1.db.account.add)({
|
||||
account: id,
|
||||
keypair: keypair2,
|
||||
powers: [],
|
||||
})
|
||||
assert.equal(msg2.data.add.key.bytes, keypair2.public)
|
||||
await t.test('keypair with no "add" powers cannot add', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
const keypair1 = Keypair.generate('ed25519', 'alice')
|
||||
const keypair2 = Keypair.generate('ed25519', 'bob')
|
||||
const keypair3 = Keypair.generate('ed25519', 'carol')
|
||||
|
||||
assert.equal(peer1.db.account.has({ account: id, keypair: keypair2 }), true)
|
||||
const peer1 = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair: keypair1, path: DIR })
|
||||
|
||||
await p(peer1.close)()
|
||||
rimraf.sync(DIR)
|
||||
await peer1.db.loaded()
|
||||
const id = await p(peer1.db.account.create)({
|
||||
keypair: keypair1,
|
||||
domain: 'account',
|
||||
})
|
||||
const msg1 = peer1.db.get(id)
|
||||
|
||||
const peer2 = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair: keypair2, path: DIR })
|
||||
const { msg: msg2 } = await p(peer1.db.account.add)({
|
||||
account: id,
|
||||
keypair: keypair2,
|
||||
powers: [],
|
||||
})
|
||||
assert.equal(msg2.data.add.key.bytes, keypair2.public)
|
||||
|
||||
await peer2.db.loaded()
|
||||
await p(peer2.db.add)(msg1, id)
|
||||
await p(peer2.db.add)(msg2, id)
|
||||
assert.equal(peer1.db.account.has({ account: id, keypair: keypair2 }), true)
|
||||
|
||||
// Test author-side power validation
|
||||
assert.rejects(
|
||||
p(peer2.db.account.add)({
|
||||
await p(peer1.close)()
|
||||
rimraf.sync(DIR)
|
||||
|
||||
const peer2 = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair: keypair2, path: DIR })
|
||||
|
||||
await peer2.db.loaded()
|
||||
await p(peer2.db.add)(msg1, id)
|
||||
await p(peer2.db.add)(msg2, id)
|
||||
|
||||
// Test author-side power validation
|
||||
assert.rejects(
|
||||
p(peer2.db.account.add)({
|
||||
account: id,
|
||||
keypair: keypair3,
|
||||
powers: [],
|
||||
}),
|
||||
/signing keypair does not have the "add" power/
|
||||
)
|
||||
|
||||
// Make the author disobey power validation
|
||||
const { msg: msg3 } = await p(peer2.db.account.add)({
|
||||
account: id,
|
||||
keypair: keypair3,
|
||||
powers: [],
|
||||
}),
|
||||
/signing keypair does not have the "add" power/
|
||||
)
|
||||
_disobey: true,
|
||||
})
|
||||
|
||||
// Make the author disobey power validation
|
||||
const { msg: msg3 } = await p(peer2.db.account.add)({
|
||||
account: id,
|
||||
keypair: keypair3,
|
||||
powers: [],
|
||||
_disobey: true,
|
||||
assert.equal(msg3.data.add.key.bytes, keypair3.public)
|
||||
|
||||
await p(peer2.close)()
|
||||
rimraf.sync(DIR)
|
||||
|
||||
const peer1again = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair: keypair1, path: DIR })
|
||||
|
||||
await peer1again.db.loaded()
|
||||
await p(peer1again.db.add)(msg1, id) // re-add because lost during rimraf
|
||||
await p(peer1again.db.add)(msg2, id) // re-add because lost during rimraf
|
||||
|
||||
// Test replicator-side power validation
|
||||
assert.rejects(
|
||||
p(peer1again.db.add)(msg3, id),
|
||||
/add\(\) failed to verify msg/
|
||||
)
|
||||
|
||||
await p(peer1again.close)()
|
||||
})
|
||||
|
||||
assert.equal(msg3.data.add.key.bytes, keypair3.public)
|
||||
await t.test('publish with a key in the account', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
|
||||
await p(peer2.close)()
|
||||
rimraf.sync(DIR)
|
||||
const keypair1 = Keypair.generate('ed25519', 'alice')
|
||||
const keypair2 = Keypair.generate('ed25519', 'bob')
|
||||
|
||||
const peer1again = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair: keypair1, path: DIR })
|
||||
let peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair: keypair1, path: DIR })
|
||||
|
||||
await peer1again.db.loaded()
|
||||
await p(peer1again.db.add)(msg1, id) // re-add because lost during rimraf
|
||||
await p(peer1again.db.add)(msg2, id) // re-add because lost during rimraf
|
||||
await peer.db.loaded()
|
||||
|
||||
// Test replicator-side power validation
|
||||
assert.rejects(
|
||||
p(peer1again.db.add)(msg3, id),
|
||||
/add\(\) failed to verify msg/
|
||||
)
|
||||
const account = await p(peer.db.account.create)({
|
||||
keypair: keypair1,
|
||||
domain: 'person',
|
||||
})
|
||||
const accountMsg0 = peer.db.get(account)
|
||||
|
||||
await p(peer1again.close)()
|
||||
})
|
||||
|
||||
test('publish with a key in the account', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
|
||||
const keypair1 = Keypair.generate('ed25519', 'alice')
|
||||
const keypair2 = Keypair.generate('ed25519', 'bob')
|
||||
|
||||
let peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair: keypair1, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
|
||||
const account = await p(peer.db.account.create)({
|
||||
keypair: keypair1,
|
||||
domain: 'person',
|
||||
})
|
||||
const accountMsg0 = peer.db.get(account)
|
||||
|
||||
// Consent is implicitly created because keypair2 has .private
|
||||
const accountRec1 = await p(peer.db.account.add)({
|
||||
account,
|
||||
keypair: keypair2,
|
||||
})
|
||||
|
||||
const postRec = await p(peer.db.feed.publish)({
|
||||
account,
|
||||
domain: 'post',
|
||||
data: { text: 'hello' },
|
||||
keypair: keypair2,
|
||||
})
|
||||
assert.equal(postRec.msg.data.text, 'hello', 'post text correct')
|
||||
const postsID = peer.db.feed.getID(account, 'post')
|
||||
assert.ok(postsID, 'postsID exists')
|
||||
|
||||
const recs = [...peer.db.records()]
|
||||
assert.equal(recs.length, 4, '4 records')
|
||||
const [_accountRec0, _accountRec1, postsRoot, _post] = recs
|
||||
assert.deepEqual(_accountRec0.msg, accountMsg0, 'accountMsg0')
|
||||
assert.deepEqual(_accountRec1.msg, accountRec1.msg, 'accountMsg1')
|
||||
assert.deepEqual(
|
||||
postsRoot.msg.metadata,
|
||||
{
|
||||
dataHash: null,
|
||||
dataSize: 0,
|
||||
// Consent is implicitly created because keypair2 has .private
|
||||
const accountRec1 = await p(peer.db.account.add)({
|
||||
account,
|
||||
keypair: keypair2,
|
||||
})
|
||||
|
||||
const postRec = await p(peer.db.feed.publish)({
|
||||
account,
|
||||
accountTips: null,
|
||||
tangles: {},
|
||||
domain: 'post',
|
||||
v: 3,
|
||||
},
|
||||
'postsRoot'
|
||||
)
|
||||
assert.deepEqual(_post.msg, postRec.msg, 'postMsg')
|
||||
data: { text: 'hello' },
|
||||
keypair: keypair2,
|
||||
})
|
||||
assert.equal(postRec.msg.data.text, 'hello', 'post text correct')
|
||||
const postsID = peer.db.feed.getID(account, 'post')
|
||||
assert.ok(postsID, 'postsID exists')
|
||||
|
||||
await p(peer.close)()
|
||||
const recs = [...peer.db.records()]
|
||||
assert.equal(recs.length, 4, '4 records')
|
||||
const [_accountRec0, _accountRec1, postsRoot, _post] = recs
|
||||
assert.deepEqual(_accountRec0.msg, accountMsg0, 'accountMsg0')
|
||||
assert.deepEqual(_accountRec1.msg, accountRec1.msg, 'accountMsg1')
|
||||
assert.deepEqual(
|
||||
postsRoot.msg.metadata,
|
||||
{
|
||||
dataHash: null,
|
||||
dataSize: 0,
|
||||
account,
|
||||
accountTips: null,
|
||||
tangles: {},
|
||||
domain: 'post',
|
||||
v: 3,
|
||||
},
|
||||
'postsRoot'
|
||||
)
|
||||
assert.deepEqual(_post.msg, postRec.msg, 'postMsg')
|
||||
|
||||
// Re-load as Carol, add the msgs to validate them
|
||||
rimraf.sync(DIR)
|
||||
const keypair3 = Keypair.generate('ed25519', 'carol')
|
||||
await p(peer.close)()
|
||||
|
||||
const carol = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair: keypair3, path: DIR })
|
||||
// Re-load as Carol, add the msgs to validate them
|
||||
rimraf.sync(DIR)
|
||||
const keypair3 = Keypair.generate('ed25519', 'carol')
|
||||
|
||||
await carol.db.loaded()
|
||||
const carol = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair: keypair3, path: DIR })
|
||||
|
||||
await p(carol.db.add)(accountMsg0, account)
|
||||
await p(carol.db.add)(accountRec1.msg, account)
|
||||
await p(carol.db.add)(postsRoot.msg, postsID)
|
||||
await p(carol.db.add)(postRec.msg, postsID)
|
||||
// t.pass('carol added all msgs successfully')
|
||||
await carol.db.loaded()
|
||||
|
||||
await p(carol.close)()
|
||||
await p(carol.db.add)(accountMsg0, account)
|
||||
await p(carol.db.add)(accountRec1.msg, account)
|
||||
await p(carol.db.add)(postsRoot.msg, postsID)
|
||||
await p(carol.db.add)(postRec.msg, postsID)
|
||||
// t.pass('carol added all msgs successfully')
|
||||
|
||||
await p(carol.close)()
|
||||
})
|
||||
})
|
||||
|
|
|
@ -11,148 +11,150 @@ const Keypair = require('ppppp-keypair')
|
|||
const DIR = path.join(os.tmpdir(), 'ppppp-db-account-create')
|
||||
rimraf.sync(DIR)
|
||||
|
||||
test('account.create() with just "domain"', async (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair, path: DIR })
|
||||
test('account.create() ', async (t) => {
|
||||
await t.test('create with just "domain"', async (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
const account = await p(peer.db.account.create)({
|
||||
domain: 'person',
|
||||
_nonce: 'MYNONCE',
|
||||
})
|
||||
assert.ok(account, 'accountRec0 exists')
|
||||
const msg = peer.db.get(account)
|
||||
assert.deepEqual(
|
||||
msg.data,
|
||||
{
|
||||
action: 'add',
|
||||
add: {
|
||||
key: {
|
||||
purpose: 'sig',
|
||||
algorithm: 'ed25519',
|
||||
bytes: keypair.public,
|
||||
await peer.db.loaded()
|
||||
const account = await p(peer.db.account.create)({
|
||||
domain: 'person',
|
||||
_nonce: 'MYNONCE',
|
||||
})
|
||||
assert.ok(account, 'accountRec0 exists')
|
||||
const msg = peer.db.get(account)
|
||||
assert.deepEqual(
|
||||
msg.data,
|
||||
{
|
||||
action: 'add',
|
||||
add: {
|
||||
key: {
|
||||
purpose: 'sig',
|
||||
algorithm: 'ed25519',
|
||||
bytes: keypair.public,
|
||||
},
|
||||
nonce: 'MYNONCE',
|
||||
powers: ['add', 'del', 'box'],
|
||||
},
|
||||
nonce: 'MYNONCE',
|
||||
powers: ['add', 'del', 'box'],
|
||||
},
|
||||
},
|
||||
'msg.data.add'
|
||||
)
|
||||
assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
|
||||
assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
|
||||
assert.deepEqual(
|
||||
Object.keys(msg.metadata.tangles),
|
||||
[],
|
||||
'msg.metadata.tangles'
|
||||
)
|
||||
assert.equal(msg.pubkey, keypair.public, 'msg.pubkey')
|
||||
'msg.data.add'
|
||||
)
|
||||
assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
|
||||
assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
|
||||
assert.deepEqual(
|
||||
Object.keys(msg.metadata.tangles),
|
||||
[],
|
||||
'msg.metadata.tangles'
|
||||
)
|
||||
assert.equal(msg.pubkey, keypair.public, 'msg.pubkey')
|
||||
|
||||
await p(peer.close)()
|
||||
})
|
||||
|
||||
test('account.create() with "keypair" and "domain"', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
const account = await p(peer.db.account.create)({
|
||||
keypair,
|
||||
domain: 'person',
|
||||
await p(peer.close)()
|
||||
})
|
||||
assert.ok(account, 'account created')
|
||||
const msg = peer.db.get(account)
|
||||
assert.equal(msg.data.add.key.bytes, keypair.public, 'msg.data.add')
|
||||
assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
|
||||
assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
|
||||
assert.deepEqual(
|
||||
Object.keys(msg.metadata.tangles),
|
||||
[],
|
||||
'msg.metadata.tangles'
|
||||
)
|
||||
assert.equal(msg.pubkey, keypair.public, 'msg.pubkey')
|
||||
|
||||
await p(peer.close)()
|
||||
})
|
||||
await t.test('create with "keypair" and "domain"', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
test('account.find() can find', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const domain = 'person'
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair, path: DIR })
|
||||
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair, path: DIR })
|
||||
await peer.db.loaded()
|
||||
const account = await p(peer.db.account.create)({
|
||||
keypair,
|
||||
domain: 'person',
|
||||
})
|
||||
assert.ok(account, 'account created')
|
||||
const msg = peer.db.get(account)
|
||||
assert.equal(msg.data.add.key.bytes, keypair.public, 'msg.data.add')
|
||||
assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
|
||||
assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
|
||||
assert.deepEqual(
|
||||
Object.keys(msg.metadata.tangles),
|
||||
[],
|
||||
'msg.metadata.tangles'
|
||||
)
|
||||
assert.equal(msg.pubkey, keypair.public, 'msg.pubkey')
|
||||
|
||||
await peer.db.loaded()
|
||||
const account = await p(peer.db.account.create)({ keypair, domain })
|
||||
assert.ok(account, 'account created')
|
||||
|
||||
const found = await p(peer.db.account.find)({ keypair, domain })
|
||||
assert.equal(found, account, 'found')
|
||||
|
||||
await p(peer.close)()
|
||||
})
|
||||
|
||||
test('account.findOrCreate() can find', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const domain = 'person'
|
||||
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
const account = await p(peer.db.account.create)({ keypair, domain })
|
||||
assert.ok(account, 'account created')
|
||||
|
||||
const found = await p(peer.db.account.findOrCreate)({ keypair, domain })
|
||||
assert.equal(found, account, 'found')
|
||||
|
||||
await p(peer.close)()
|
||||
})
|
||||
|
||||
test('account.findOrCreate() can create', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const domain = 'person'
|
||||
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
|
||||
let gotError = false
|
||||
await p(peer.db.account.find)({ keypair, domain }).catch((err) => {
|
||||
assert.equal(err.cause, 'ENOENT')
|
||||
gotError = true
|
||||
await p(peer.close)()
|
||||
})
|
||||
assert.ok(gotError, 'account not found')
|
||||
|
||||
const account = await p(peer.db.account.findOrCreate)({ keypair, domain })
|
||||
assert.ok(account, 'account created')
|
||||
const msg = peer.db.get(account)
|
||||
assert.equal(msg.data.add.key.bytes, keypair.public, 'msg.data.add')
|
||||
assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
|
||||
assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
|
||||
assert.deepEqual(
|
||||
Object.keys(msg.metadata.tangles),
|
||||
[],
|
||||
'msg.metadata.tangles'
|
||||
)
|
||||
assert.equal(msg.pubkey, keypair.public, 'msg.pubkey')
|
||||
await t.test('account.find() can find', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const domain = 'person'
|
||||
|
||||
await p(peer.close)()
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
const account = await p(peer.db.account.create)({ keypair, domain })
|
||||
assert.ok(account, 'account created')
|
||||
|
||||
const found = await p(peer.db.account.find)({ keypair, domain })
|
||||
assert.equal(found, account, 'found')
|
||||
|
||||
await p(peer.close)()
|
||||
})
|
||||
|
||||
await t.test('account.findOrCreate() can find', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const domain = 'person'
|
||||
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
const account = await p(peer.db.account.create)({ keypair, domain })
|
||||
assert.ok(account, 'account created')
|
||||
|
||||
const found = await p(peer.db.account.findOrCreate)({ keypair, domain })
|
||||
assert.equal(found, account, 'found')
|
||||
|
||||
await p(peer.close)()
|
||||
})
|
||||
|
||||
await t.test('account.findOrCreate() can create', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const domain = 'person'
|
||||
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
|
||||
let gotError = false
|
||||
await p(peer.db.account.find)({ keypair, domain }).catch((err) => {
|
||||
assert.equal(err.cause, 'ENOENT')
|
||||
gotError = true
|
||||
})
|
||||
assert.ok(gotError, 'account not found')
|
||||
|
||||
const account = await p(peer.db.account.findOrCreate)({ keypair, domain })
|
||||
assert.ok(account, 'account created')
|
||||
const msg = peer.db.get(account)
|
||||
assert.equal(msg.data.add.key.bytes, keypair.public, 'msg.data.add')
|
||||
assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
|
||||
assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
|
||||
assert.deepEqual(
|
||||
Object.keys(msg.metadata.tangles),
|
||||
[],
|
||||
'msg.metadata.tangles'
|
||||
)
|
||||
assert.equal(msg.pubkey, keypair.public, 'msg.pubkey')
|
||||
|
||||
await p(peer.close)()
|
||||
})
|
||||
})
|
||||
|
|
|
@ -6,14 +6,13 @@ const p = require('node:util').promisify
|
|||
const rimraf = require('rimraf')
|
||||
const SecretStack = require('secret-stack')
|
||||
const Log = require('../lib/log')
|
||||
const push = require('push-stream')
|
||||
const caps = require('ppppp-caps')
|
||||
const Keypair = require('ppppp-keypair')
|
||||
|
||||
const DIR = path.join(os.tmpdir(), 'ppppp-db-del')
|
||||
rimraf.sync(DIR)
|
||||
|
||||
test('del', async (t) => {
|
||||
test('del()', async (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
|
|
|
@ -13,7 +13,7 @@ const Keypair = require('ppppp-keypair')
|
|||
const DIR = path.join(os.tmpdir(), 'ppppp-db-erase')
|
||||
rimraf.sync(DIR)
|
||||
|
||||
test('erase', async (t) => {
|
||||
test('erase()', async (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
|
|
|
@ -12,31 +12,23 @@ const MsgV3 = require('../lib/msg-v3')
|
|||
const DIR = path.join(os.tmpdir(), 'ppppp-db-feed-publish')
|
||||
rimraf.sync(DIR)
|
||||
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
let peer
|
||||
let id
|
||||
let moot
|
||||
let mootID
|
||||
test('setup', async (t) => {
|
||||
peer = SecretStack({ appKey: caps.shse })
|
||||
test('feed.getID()', async (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
|
||||
id = (await p(peer.db.account.create)({domain: 'person'}))
|
||||
moot = MsgV3.createMoot(id, 'post', keypair)
|
||||
mootID = MsgV3.getMsgID(moot)
|
||||
const id = await p(peer.db.account.create)({ domain: 'person' })
|
||||
const moot = MsgV3.createMoot(id, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
|
||||
await p(peer.db.add)(moot, mootID)
|
||||
})
|
||||
|
||||
test('feed.getID()', async (t) => {
|
||||
const feedID = peer.db.feed.getID(id, 'post')
|
||||
assert.equal(feedID, mootID, 'feed.getID() returns moot ID')
|
||||
})
|
||||
|
||||
test('teardown', (t) => {
|
||||
peer.close(t.end)
|
||||
await p(peer.close)(true)
|
||||
})
|
||||
|
|
|
@ -12,148 +12,151 @@ const MsgV3 = require('../lib/msg-v3')
|
|||
const DIR = path.join(os.tmpdir(), 'ppppp-db-feed-publish')
|
||||
rimraf.sync(DIR)
|
||||
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const bobKeypair = Keypair.generate('ed25519', 'bob')
|
||||
let peer
|
||||
let id
|
||||
let moot
|
||||
let mootID
|
||||
test('setup', async (t) => {
|
||||
peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
|
||||
id = (await p(peer.db.account.create)({domain: 'person'}))
|
||||
moot = MsgV3.createMoot(id, 'post', keypair)
|
||||
mootID = MsgV3.getMsgID(moot)
|
||||
})
|
||||
|
||||
let msgID1
|
||||
let rec1
|
||||
let msgID2
|
||||
test('feed.publish()', async (t) => {
|
||||
rec1 = await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'I am 1st post' },
|
||||
})
|
||||
assert.equal(rec1.msg.data.text, 'I am 1st post', 'msg1 text correct')
|
||||
assert.equal(
|
||||
rec1.msg.metadata.tangles[mootID].depth,
|
||||
1,
|
||||
'msg1 tangle depth correct'
|
||||
)
|
||||
assert.deepEqual(
|
||||
rec1.msg.metadata.tangles[mootID].prev,
|
||||
[mootID],
|
||||
'msg1 tangle prev correct'
|
||||
)
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const bobKeypair = Keypair.generate('ed25519', 'bob')
|
||||
let peer
|
||||
let id
|
||||
let moot
|
||||
let mootID
|
||||
|
||||
msgID1 = MsgV3.getMsgID(rec1.msg)
|
||||
// Setup
|
||||
{
|
||||
peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair, path: DIR })
|
||||
|
||||
const rec2 = await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'I am 2nd post' },
|
||||
await peer.db.loaded()
|
||||
|
||||
id = await p(peer.db.account.create)({ domain: 'person' })
|
||||
moot = MsgV3.createMoot(id, 'post', keypair)
|
||||
mootID = MsgV3.getMsgID(moot)
|
||||
}
|
||||
|
||||
let msgID1
|
||||
let rec1
|
||||
let msgID2
|
||||
|
||||
await t.test('can add new msgs to the db', async (t) => {
|
||||
rec1 = await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'I am 1st post' },
|
||||
})
|
||||
assert.equal(rec1.msg.data.text, 'I am 1st post', 'msg1 text correct')
|
||||
assert.equal(
|
||||
rec1.msg.metadata.tangles[mootID].depth,
|
||||
1,
|
||||
'msg1 tangle depth correct'
|
||||
)
|
||||
assert.deepEqual(
|
||||
rec1.msg.metadata.tangles[mootID].prev,
|
||||
[mootID],
|
||||
'msg1 tangle prev correct'
|
||||
)
|
||||
|
||||
msgID1 = MsgV3.getMsgID(rec1.msg)
|
||||
|
||||
const rec2 = await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'I am 2nd post' },
|
||||
})
|
||||
assert.equal(rec2.msg.data.text, 'I am 2nd post', 'msg2 text correct')
|
||||
assert.equal(
|
||||
rec2.msg.metadata.tangles[mootID].depth,
|
||||
2,
|
||||
'msg2 tangle depth correct'
|
||||
)
|
||||
assert.deepEqual(
|
||||
rec2.msg.metadata.tangles[mootID].prev,
|
||||
[msgID1],
|
||||
'msg2 tangle prev correct'
|
||||
)
|
||||
msgID2 = MsgV3.getMsgID(rec2.msg)
|
||||
})
|
||||
assert.equal(rec2.msg.data.text, 'I am 2nd post', 'msg2 text correct')
|
||||
assert.equal(
|
||||
rec2.msg.metadata.tangles[mootID].depth,
|
||||
2,
|
||||
'msg2 tangle depth correct'
|
||||
)
|
||||
assert.deepEqual(
|
||||
rec2.msg.metadata.tangles[mootID].prev,
|
||||
[msgID1],
|
||||
'msg2 tangle prev correct'
|
||||
)
|
||||
msgID2 = MsgV3.getMsgID(rec2.msg)
|
||||
})
|
||||
|
||||
test('add() forked then feed.publish() merged', async (t) => {
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
tangle.add(rec1.id, rec1.msg)
|
||||
|
||||
const msg3 = MsgV3.create({
|
||||
keypair,
|
||||
account: id,
|
||||
accountTips: [id],
|
||||
domain: 'post',
|
||||
data: { text: '3rd post forked from 1st' },
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
|
||||
const rec3 = await p(peer.db.add)(msg3, mootID)
|
||||
const msgID3 = MsgV3.getMsgID(rec3.msg)
|
||||
|
||||
const rec4 = await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'I am 4th post' },
|
||||
})
|
||||
assert.ok(rec4, '4th post published')
|
||||
assert.equal(
|
||||
rec4.msg.metadata.tangles[mootID].prev.length,
|
||||
3,
|
||||
'msg4 prev has 3' // is root, msg2 and msg3'
|
||||
)
|
||||
assert.ok(
|
||||
rec4.msg.metadata.tangles[mootID].prev.includes(mootID),
|
||||
'msg4 prev has root'
|
||||
)
|
||||
assert.ok(
|
||||
rec4.msg.metadata.tangles[mootID].prev.includes(msgID2),
|
||||
'msg4 prev has msg2'
|
||||
)
|
||||
assert.ok(
|
||||
rec4.msg.metadata.tangles[mootID].prev.includes(msgID3),
|
||||
'msg4 prev has msg3'
|
||||
)
|
||||
})
|
||||
|
||||
test('feed.publish() encrypted with box', async (t) => {
|
||||
const recEncrypted = await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'I am chewing food', recps: [keypair.public] },
|
||||
encryptionFormat: 'box',
|
||||
})
|
||||
assert.equal(typeof recEncrypted.msg.data, 'string')
|
||||
assert.ok(recEncrypted.msg.data.endsWith('.box'), '.box')
|
||||
|
||||
const msgDecrypted = peer.db.get(recEncrypted.id)
|
||||
assert.equal(msgDecrypted.data.text, 'I am chewing food')
|
||||
})
|
||||
|
||||
test('feed.publish() with tangles', async (t) => {
|
||||
const recA = await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
domain: 'comment',
|
||||
data: { text: 'I am root' },
|
||||
})
|
||||
assert.equal(recA.msg.data.text, 'I am root', 'root text correct')
|
||||
|
||||
const recB = await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
domain: 'comment',
|
||||
data: { text: 'I am comment 1' },
|
||||
tangles: [recA.id],
|
||||
keypair: bobKeypair,
|
||||
})
|
||||
assert.equal(recB.msg.metadata.tangles[recA.id].depth, 1, 'tangle depth 1')
|
||||
assert.deepEqual(
|
||||
recB.msg.metadata.tangles[recA.id].prev,
|
||||
[recA.id],
|
||||
'tangle prev'
|
||||
)
|
||||
})
|
||||
|
||||
test('teardown', (t) => {
|
||||
peer.close(t.end)
|
||||
|
||||
await t.test('merges tangle after a forked add()', async (t) => {
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
tangle.add(rec1.id, rec1.msg)
|
||||
|
||||
const msg3 = MsgV3.create({
|
||||
keypair,
|
||||
account: id,
|
||||
accountTips: [id],
|
||||
domain: 'post',
|
||||
data: { text: '3rd post forked from 1st' },
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
|
||||
const rec3 = await p(peer.db.add)(msg3, mootID)
|
||||
const msgID3 = MsgV3.getMsgID(rec3.msg)
|
||||
|
||||
const rec4 = await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'I am 4th post' },
|
||||
})
|
||||
assert.ok(rec4, '4th post published')
|
||||
assert.equal(
|
||||
rec4.msg.metadata.tangles[mootID].prev.length,
|
||||
3,
|
||||
'msg4 prev has 3' // is root, msg2 and msg3'
|
||||
)
|
||||
assert.ok(
|
||||
rec4.msg.metadata.tangles[mootID].prev.includes(mootID),
|
||||
'msg4 prev has root'
|
||||
)
|
||||
assert.ok(
|
||||
rec4.msg.metadata.tangles[mootID].prev.includes(msgID2),
|
||||
'msg4 prev has msg2'
|
||||
)
|
||||
assert.ok(
|
||||
rec4.msg.metadata.tangles[mootID].prev.includes(msgID3),
|
||||
'msg4 prev has msg3'
|
||||
)
|
||||
})
|
||||
|
||||
await t.test('publish encrypted with box', async (t) => {
|
||||
const recEncrypted = await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'I am chewing food', recps: [keypair.public] },
|
||||
encryptionFormat: 'box',
|
||||
})
|
||||
assert.equal(typeof recEncrypted.msg.data, 'string')
|
||||
assert.ok(recEncrypted.msg.data.endsWith('.box'), '.box')
|
||||
|
||||
const msgDecrypted = peer.db.get(recEncrypted.id)
|
||||
assert.equal(msgDecrypted.data.text, 'I am chewing food')
|
||||
})
|
||||
|
||||
await t.test('publish with tangles', async (t) => {
|
||||
const recA = await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
domain: 'comment',
|
||||
data: { text: 'I am root' },
|
||||
})
|
||||
assert.equal(recA.msg.data.text, 'I am root', 'root text correct')
|
||||
|
||||
const recB = await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
domain: 'comment',
|
||||
data: { text: 'I am comment 1' },
|
||||
tangles: [recA.id],
|
||||
keypair: bobKeypair,
|
||||
})
|
||||
assert.equal(recB.msg.metadata.tangles[recA.id].depth, 1, 'tangle depth 1')
|
||||
assert.deepEqual(
|
||||
recB.msg.metadata.tangles[recA.id].prev,
|
||||
[recA.id],
|
||||
'tangle prev'
|
||||
)
|
||||
})
|
||||
|
||||
await p(peer.close)(true)
|
||||
})
|
||||
|
|
|
@ -12,34 +12,27 @@ const MsgV3 = require('../lib/msg-v3')
|
|||
const DIR = path.join(os.tmpdir(), 'ppppp-db-get')
|
||||
rimraf.sync(DIR)
|
||||
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
let peer
|
||||
let id
|
||||
let msgID1
|
||||
test('setup', async (t) => {
|
||||
peer = SecretStack({ appKey: caps.shse })
|
||||
test('get()', async (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
|
||||
id = (await p(peer.db.account.create)({domain: 'person'}))
|
||||
const id = await p(peer.db.account.create)({ domain: 'person' })
|
||||
|
||||
const rec1 = await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'I am 1st post' },
|
||||
})
|
||||
msgID1 = MsgV3.getMsgID(rec1.msg)
|
||||
})
|
||||
const msgID1 = MsgV3.getMsgID(rec1.msg)
|
||||
|
||||
test('get() supports msg IDs', async (t) => {
|
||||
const msg = peer.db.get(msgID1)
|
||||
assert.ok(msg, 'msg exists')
|
||||
assert.equal(msg.data.text, 'I am 1st post')
|
||||
})
|
||||
|
||||
test('teardown', (t) => {
|
||||
peer.close(t.end)
|
||||
await p(peer.close)(true)
|
||||
})
|
||||
|
|
|
@ -11,263 +11,280 @@ const Keypair = require('ppppp-keypair')
|
|||
const DIR = path.join(os.tmpdir(), 'ppppp-db-tangle')
|
||||
rimraf.sync(DIR)
|
||||
|
||||
let peer
|
||||
let rootPost, reply1Lo, reply1Hi, reply2, reply3Lo, reply3Hi
|
||||
let tangle
|
||||
test('setup', async (t) => {
|
||||
const keypairA = Keypair.generate('ed25519', 'alice')
|
||||
const keypairB = Keypair.generate('ed25519', 'bob')
|
||||
const keypairC = Keypair.generate('ed25519', 'carol')
|
||||
test('getTangle()', async (t) => {
|
||||
let peer
|
||||
let rootPost, reply1Lo, reply1Hi, reply2, reply3Lo, reply3Hi
|
||||
let tangle
|
||||
|
||||
peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair: keypairA, path: DIR })
|
||||
// Setup
|
||||
{
|
||||
const keypairA = Keypair.generate('ed25519', 'alice')
|
||||
const keypairB = Keypair.generate('ed25519', 'bob')
|
||||
const keypairC = Keypair.generate('ed25519', 'carol')
|
||||
|
||||
await peer.db.loaded()
|
||||
peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
.use(require('ssb-box'))
|
||||
.call(null, { keypair: keypairA, path: DIR })
|
||||
|
||||
const id = await p(peer.db.account.create)({ domain: 'person' })
|
||||
await peer.db.loaded()
|
||||
|
||||
// Slow down append so that we can trigger msg creation in parallel
|
||||
const originalAppend = peer.db._getLog().append
|
||||
peer.db._getLog().append = function (...args) {
|
||||
setTimeout(originalAppend, 20, ...args)
|
||||
const id = await p(peer.db.account.create)({ domain: 'person' })
|
||||
|
||||
// Slow down append so that we can trigger msg creation in parallel
|
||||
const originalAppend = peer.db._getLog().append
|
||||
peer.db._getLog().append = function (...args) {
|
||||
setTimeout(originalAppend, 20, ...args)
|
||||
}
|
||||
|
||||
rootPost = (
|
||||
await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
keypair: keypairA,
|
||||
domain: 'comment',
|
||||
data: { text: 'root' },
|
||||
})
|
||||
).id
|
||||
|
||||
const [{ id: reply1B }, { id: reply1C }] = await Promise.all([
|
||||
p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
keypair: keypairB,
|
||||
domain: 'comment',
|
||||
data: { text: 'reply 1B' },
|
||||
tangles: [rootPost],
|
||||
}),
|
||||
p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
keypair: keypairC,
|
||||
domain: 'comment',
|
||||
data: { text: 'reply 1C' },
|
||||
tangles: [rootPost],
|
||||
}),
|
||||
])
|
||||
reply1Lo = reply1B.localeCompare(reply1C) < 0 ? reply1B : reply1C
|
||||
reply1Hi = reply1B.localeCompare(reply1C) < 0 ? reply1C : reply1B
|
||||
|
||||
reply2 = (
|
||||
await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
keypair: keypairA,
|
||||
domain: 'comment',
|
||||
data: { text: 'reply 2' },
|
||||
tangles: [rootPost],
|
||||
})
|
||||
).id
|
||||
|
||||
const [{ id: reply3B }, { id: reply3C }] = await Promise.all([
|
||||
p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
keypair: keypairB,
|
||||
domain: 'comment',
|
||||
data: { text: 'reply 3B' },
|
||||
tangles: [rootPost],
|
||||
}),
|
||||
p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
keypair: keypairC,
|
||||
domain: 'comment',
|
||||
data: { text: 'reply 3C' },
|
||||
tangles: [rootPost],
|
||||
}),
|
||||
])
|
||||
reply3Lo = reply3B.localeCompare(reply3C) < 0 ? reply3B : reply3C
|
||||
reply3Hi = reply3B.localeCompare(reply3C) < 0 ? reply3C : reply3B
|
||||
|
||||
tangle = peer.db.getTangle(rootPost)
|
||||
}
|
||||
|
||||
rootPost = (
|
||||
await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
keypair: keypairA,
|
||||
domain: 'comment',
|
||||
data: { text: 'root' },
|
||||
})
|
||||
).id
|
||||
await t.test('Tangle.has', (t) => {
|
||||
assert.equal(tangle.has(rootPost), true, 'has rootPost')
|
||||
assert.equal(tangle.has(reply1Lo), true, 'has reply1Lo')
|
||||
assert.equal(tangle.has(reply1Hi), true, 'has reply1Hi')
|
||||
assert.equal(tangle.has(reply2), true, 'has reply2A')
|
||||
assert.equal(tangle.has(reply3Lo), true, 'has reply3Lo')
|
||||
assert.equal(tangle.has(reply3Hi), true, 'has reply3Hi')
|
||||
assert.equal(tangle.has('nonsense'), false, 'does not have nonsense')
|
||||
})
|
||||
|
||||
const [{ id: reply1B }, { id: reply1C }] = await Promise.all([
|
||||
p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
keypair: keypairB,
|
||||
domain: 'comment',
|
||||
data: { text: 'reply 1B' },
|
||||
tangles: [rootPost],
|
||||
}),
|
||||
p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
keypair: keypairC,
|
||||
domain: 'comment',
|
||||
data: { text: 'reply 1C' },
|
||||
tangles: [rootPost],
|
||||
}),
|
||||
])
|
||||
reply1Lo = reply1B.localeCompare(reply1C) < 0 ? reply1B : reply1C
|
||||
reply1Hi = reply1B.localeCompare(reply1C) < 0 ? reply1C : reply1B
|
||||
await t.test('Tangle.getDepth', (t) => {
|
||||
assert.equal(tangle.getDepth(rootPost), 0, 'depth of rootPost is 0')
|
||||
assert.equal(tangle.getDepth(reply1Lo), 1, 'depth of reply1Lo is 1')
|
||||
assert.equal(tangle.getDepth(reply1Hi), 1, 'depth of reply1Hi is 1')
|
||||
assert.equal(tangle.getDepth(reply2), 2, 'depth of reply2A is 2')
|
||||
assert.equal(tangle.getDepth(reply3Lo), 3, 'depth of reply3Lo is 3')
|
||||
assert.equal(tangle.getDepth(reply3Hi), 3, 'depth of reply3Hi is 3')
|
||||
})
|
||||
|
||||
reply2 = (
|
||||
await p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
keypair: keypairA,
|
||||
domain: 'comment',
|
||||
data: { text: 'reply 2' },
|
||||
tangles: [rootPost],
|
||||
})
|
||||
).id
|
||||
await t.test('Tangle.maxDepth', (t) => {
|
||||
assert.equal(tangle.maxDepth, 3, 'max depth is 3')
|
||||
})
|
||||
|
||||
const [{ id: reply3B }, { id: reply3C }] = await Promise.all([
|
||||
p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
keypair: keypairB,
|
||||
domain: 'comment',
|
||||
data: { text: 'reply 3B' },
|
||||
tangles: [rootPost],
|
||||
}),
|
||||
p(peer.db.feed.publish)({
|
||||
account: id,
|
||||
keypair: keypairC,
|
||||
domain: 'comment',
|
||||
data: { text: 'reply 3C' },
|
||||
tangles: [rootPost],
|
||||
}),
|
||||
])
|
||||
reply3Lo = reply3B.localeCompare(reply3C) < 0 ? reply3B : reply3C
|
||||
reply3Hi = reply3B.localeCompare(reply3C) < 0 ? reply3C : reply3B
|
||||
await t.test('Tangle.topoSort', (t) => {
|
||||
const sorted = tangle.topoSort()
|
||||
|
||||
tangle = peer.db.getTangle(rootPost)
|
||||
})
|
||||
assert.deepEqual(sorted, [
|
||||
rootPost,
|
||||
reply1Lo,
|
||||
reply1Hi,
|
||||
reply2,
|
||||
reply3Lo,
|
||||
reply3Hi,
|
||||
])
|
||||
})
|
||||
|
||||
test('Tangle.has', (t) => {
|
||||
assert.equal(tangle.has(rootPost), true, 'has rootPost')
|
||||
assert.equal(tangle.has(reply1Lo), true, 'has reply1Lo')
|
||||
assert.equal(tangle.has(reply1Hi), true, 'has reply1Hi')
|
||||
assert.equal(tangle.has(reply2), true, 'has reply2A')
|
||||
assert.equal(tangle.has(reply3Lo), true, 'has reply3Lo')
|
||||
assert.equal(tangle.has(reply3Hi), true, 'has reply3Hi')
|
||||
assert.equal(tangle.has('nonsense'), false, 'does not have nonsense')
|
||||
})
|
||||
await t.test('Tangle.precedes', (t) => {
|
||||
assert.equal(
|
||||
tangle.precedes(rootPost, reply1Lo),
|
||||
true,
|
||||
'rootPost precedes reply1Lo'
|
||||
)
|
||||
assert.equal(
|
||||
tangle.precedes(rootPost, reply1Hi),
|
||||
true,
|
||||
'rootPost precedes reply1Hi'
|
||||
)
|
||||
assert.equal(
|
||||
tangle.precedes(reply1Hi, rootPost),
|
||||
false,
|
||||
'reply1Hi doesnt precede rootPost'
|
||||
)
|
||||
assert.equal(
|
||||
tangle.precedes(reply1Lo, reply1Hi),
|
||||
false,
|
||||
'reply1Lo doesnt precede reply1Hi'
|
||||
)
|
||||
assert.equal(
|
||||
tangle.precedes(reply1Lo, reply1Lo),
|
||||
false,
|
||||
'reply1Lo doesnt precede itself'
|
||||
)
|
||||
assert.equal(
|
||||
tangle.precedes(reply1Lo, reply3Hi),
|
||||
true,
|
||||
'reply1Lo precedes reply3Hi'
|
||||
)
|
||||
assert.equal(
|
||||
tangle.precedes(reply1Hi, reply2),
|
||||
true,
|
||||
'reply1Hi precedes reply2A'
|
||||
)
|
||||
assert.equal(
|
||||
tangle.precedes(reply3Lo, reply1Hi),
|
||||
false,
|
||||
'reply3Lo doesnt precede reply1Hi'
|
||||
)
|
||||
})
|
||||
|
||||
test('Tangle.getDepth', (t) => {
|
||||
assert.equal(tangle.getDepth(rootPost), 0, 'depth of rootPost is 0')
|
||||
assert.equal(tangle.getDepth(reply1Lo), 1, 'depth of reply1Lo is 1')
|
||||
assert.equal(tangle.getDepth(reply1Hi), 1, 'depth of reply1Hi is 1')
|
||||
assert.equal(tangle.getDepth(reply2), 2, 'depth of reply2A is 2')
|
||||
assert.equal(tangle.getDepth(reply3Lo), 3, 'depth of reply3Lo is 3')
|
||||
assert.equal(tangle.getDepth(reply3Hi), 3, 'depth of reply3Hi is 3')
|
||||
})
|
||||
await t.test('Tangle.tips', (t) => {
|
||||
const tips = tangle.tips
|
||||
|
||||
test('Tangle.maxDepth', (t) => {
|
||||
assert.equal(tangle.maxDepth, 3, 'max depth is 3')
|
||||
})
|
||||
assert.equal(tips.size, 2, 'there are 2 tips')
|
||||
assert.equal(tips.has(reply3Lo), true, 'tips contains reply3Lo')
|
||||
assert.equal(tips.has(reply3Hi), true, 'tips contains reply3Hi')
|
||||
})
|
||||
|
||||
test('Tangle.topoSort', (t) => {
|
||||
const sorted = tangle.topoSort()
|
||||
await t.test('Tangle.getLipmaaSet', (t) => {
|
||||
assert.equal(tangle.getLipmaaSet(0).size, 0, 'lipmaa 0 (empty)')
|
||||
|
||||
assert.deepEqual(sorted, [
|
||||
rootPost,
|
||||
reply1Lo,
|
||||
reply1Hi,
|
||||
reply2,
|
||||
reply3Lo,
|
||||
reply3Hi,
|
||||
])
|
||||
})
|
||||
assert.equal(tangle.getLipmaaSet(1).size, 1, 'lipmaa 1 (-1)')
|
||||
assert.equal(tangle.getLipmaaSet(1).has(rootPost), true, 'lipmaa 1 (-1)')
|
||||
|
||||
test('Tangle.precedes', (t) => {
|
||||
assert.equal(
|
||||
tangle.precedes(rootPost, reply1Lo),
|
||||
true,
|
||||
'rootPost precedes reply1Lo'
|
||||
)
|
||||
assert.equal(
|
||||
tangle.precedes(rootPost, reply1Hi),
|
||||
true,
|
||||
'rootPost precedes reply1Hi'
|
||||
)
|
||||
assert.equal(
|
||||
tangle.precedes(reply1Hi, rootPost),
|
||||
false,
|
||||
'reply1Hi doesnt precede rootPost'
|
||||
)
|
||||
assert.equal(
|
||||
tangle.precedes(reply1Lo, reply1Hi),
|
||||
false,
|
||||
'reply1Lo doesnt precede reply1Hi'
|
||||
)
|
||||
assert.equal(
|
||||
tangle.precedes(reply1Lo, reply1Lo),
|
||||
false,
|
||||
'reply1Lo doesnt precede itself'
|
||||
)
|
||||
assert.equal(
|
||||
tangle.precedes(reply1Lo, reply3Hi),
|
||||
true,
|
||||
'reply1Lo precedes reply3Hi'
|
||||
)
|
||||
assert.equal(
|
||||
tangle.precedes(reply1Hi, reply2),
|
||||
true,
|
||||
'reply1Hi precedes reply2A'
|
||||
)
|
||||
assert.equal(
|
||||
tangle.precedes(reply3Lo, reply1Hi),
|
||||
false,
|
||||
'reply3Lo doesnt precede reply1Hi'
|
||||
)
|
||||
})
|
||||
assert.equal(tangle.getLipmaaSet(2).size, 2, 'lipmaa 2 (-1)')
|
||||
assert.equal(tangle.getLipmaaSet(2).has(reply1Lo), true, 'lipmaa 2 (-1)')
|
||||
assert.equal(tangle.getLipmaaSet(2).has(reply1Hi), true, 'lipmaa 2 (-1)')
|
||||
|
||||
test('Tangle.tips', (t) => {
|
||||
const tips = tangle.tips
|
||||
assert.equal(tangle.getLipmaaSet(3).size, 1, 'lipmaa 3 (leap!)')
|
||||
assert.equal(tangle.getLipmaaSet(3).has(rootPost), true, 'lipmaa 3 (leap!)')
|
||||
|
||||
assert.equal(tips.size, 2, 'there are 2 tips')
|
||||
assert.equal(tips.has(reply3Lo), true, 'tips contains reply3Lo')
|
||||
assert.equal(tips.has(reply3Hi), true, 'tips contains reply3Hi')
|
||||
})
|
||||
assert.equal(tangle.getLipmaaSet(4).size, 2, 'lipmaa 4 (-1)')
|
||||
assert.equal(tangle.getLipmaaSet(4).has(reply3Lo), true, 'lipmaa 4 (-1)')
|
||||
assert.equal(tangle.getLipmaaSet(4).has(reply3Hi), true, 'lipmaa 4 (-1)')
|
||||
|
||||
test('Tangle.getLipmaaSet', (t) => {
|
||||
assert.equal(tangle.getLipmaaSet(0).size, 0, 'lipmaa 0 (empty)')
|
||||
assert.equal(tangle.getLipmaaSet(5).size, 0, 'lipmaa 5 (empty)')
|
||||
})
|
||||
|
||||
assert.equal(tangle.getLipmaaSet(1).size, 1, 'lipmaa 1 (-1)')
|
||||
assert.equal(tangle.getLipmaaSet(1).has(rootPost), true, 'lipmaa 1 (-1)')
|
||||
await t.test('Tangle.getDeletablesAndErasables basic', (t) => {
|
||||
const { deletables, erasables } = tangle.getDeletablesAndErasables(reply2)
|
||||
|
||||
assert.equal(tangle.getLipmaaSet(2).size, 2, 'lipmaa 2 (-1)')
|
||||
assert.equal(tangle.getLipmaaSet(2).has(reply1Lo), true, 'lipmaa 2 (-1)')
|
||||
assert.equal(tangle.getLipmaaSet(2).has(reply1Hi), true, 'lipmaa 2 (-1)')
|
||||
assert.deepEqual([...deletables], [reply1Hi], 'deletables')
|
||||
assert.deepEqual([...erasables], [reply1Lo, rootPost], 'erasables')
|
||||
})
|
||||
|
||||
assert.equal(tangle.getLipmaaSet(3).size, 1, 'lipmaa 3 (leap!)')
|
||||
assert.equal(tangle.getLipmaaSet(3).has(rootPost), true, 'lipmaa 3 (leap!)')
|
||||
await t.test('Tangle.getDeletablesAndErasables with many inputs', (t) => {
|
||||
const { deletables, erasables } = tangle.getDeletablesAndErasables(
|
||||
reply3Lo,
|
||||
reply2
|
||||
)
|
||||
|
||||
assert.equal(tangle.getLipmaaSet(4).size, 2, 'lipmaa 4 (-1)')
|
||||
assert.equal(tangle.getLipmaaSet(4).has(reply3Lo), true, 'lipmaa 4 (-1)')
|
||||
assert.equal(tangle.getLipmaaSet(4).has(reply3Hi), true, 'lipmaa 4 (-1)')
|
||||
assert.deepEqual([...deletables], [reply1Hi], 'deletables')
|
||||
assert.deepEqual([...erasables], [reply1Lo, rootPost], 'erasables')
|
||||
})
|
||||
|
||||
assert.equal(tangle.getLipmaaSet(5).size, 0, 'lipmaa 5 (empty)')
|
||||
})
|
||||
await t.test(
|
||||
'Tangle.getDeletablesAndErasables with many inputs again',
|
||||
(t) => {
|
||||
const { deletables, erasables } = tangle.getDeletablesAndErasables(
|
||||
reply3Lo,
|
||||
reply3Hi
|
||||
)
|
||||
|
||||
test('Tangle.getDeletablesAndErasables basic', (t) => {
|
||||
const { deletables, erasables } = tangle.getDeletablesAndErasables(reply2)
|
||||
|
||||
assert.deepEqual([...deletables], [reply1Hi], 'deletables')
|
||||
assert.deepEqual([...erasables], [reply1Lo, rootPost], 'erasables')
|
||||
})
|
||||
|
||||
test('Tangle.getDeletablesAndErasables with many inputs', (t) => {
|
||||
const { deletables, erasables } = tangle.getDeletablesAndErasables(
|
||||
reply3Lo,
|
||||
reply2
|
||||
assert.deepEqual(
|
||||
[...deletables],
|
||||
[reply1Lo, reply1Hi, reply2],
|
||||
'deletables'
|
||||
)
|
||||
assert.deepEqual([...erasables], [rootPost], 'erasables')
|
||||
}
|
||||
)
|
||||
|
||||
assert.deepEqual([...deletables], [reply1Hi], 'deletables')
|
||||
assert.deepEqual([...erasables], [reply1Lo, rootPost], 'erasables')
|
||||
})
|
||||
await t.test('Tangle.getDeletablesAndErasables with lipmaa', (t) => {
|
||||
const { deletables, erasables } = tangle.getDeletablesAndErasables(reply3Lo)
|
||||
|
||||
test('Tangle.getDeletablesAndErasables with many inputs again', (t) => {
|
||||
const { deletables, erasables } = tangle.getDeletablesAndErasables(
|
||||
reply3Lo,
|
||||
reply3Hi
|
||||
assert.deepEqual(
|
||||
[...deletables],
|
||||
[reply1Lo, reply1Hi, reply2],
|
||||
'deletables'
|
||||
)
|
||||
assert.deepEqual([...erasables], [rootPost], 'erasables')
|
||||
})
|
||||
|
||||
await t.test('Tangle.getMinimumAmong', (t) => {
|
||||
const actual1 = tangle.getMinimumAmong([reply1Lo, reply1Hi])
|
||||
const expected1 = [reply1Lo, reply1Hi]
|
||||
assert.deepEqual(actual1, expected1)
|
||||
|
||||
const actual2 = tangle.getMinimumAmong([reply1Lo, reply1Hi, reply2])
|
||||
const expected2 = [reply1Lo, reply1Hi]
|
||||
assert.deepEqual(actual2, expected2)
|
||||
|
||||
const actual3 = tangle.getMinimumAmong([reply2, reply3Lo, reply3Hi])
|
||||
const expected3 = [reply2]
|
||||
assert.deepEqual(actual3, expected3)
|
||||
|
||||
const actual4 = tangle.getMinimumAmong([reply1Hi, reply3Lo])
|
||||
const expected4 = [reply1Hi]
|
||||
assert.deepEqual(actual4, expected4)
|
||||
})
|
||||
|
||||
await t.test(
|
||||
'Tangle.topoSort after some have been deleted and erased',
|
||||
async (t) => {
|
||||
const { deletables, erasables } =
|
||||
tangle.getDeletablesAndErasables(reply3Lo)
|
||||
for (const msgID of deletables) {
|
||||
await p(peer.db.del)(msgID)
|
||||
}
|
||||
for (const msgID of erasables) {
|
||||
await p(peer.db.erase)(msgID)
|
||||
}
|
||||
|
||||
const tangle2 = peer.db.getTangle(rootPost)
|
||||
const sorted = tangle2.topoSort()
|
||||
|
||||
assert.deepEqual(sorted, [rootPost, reply3Lo, reply3Hi])
|
||||
}
|
||||
)
|
||||
|
||||
assert.deepEqual([...deletables], [reply1Lo, reply1Hi, reply2], 'deletables')
|
||||
assert.deepEqual([...erasables], [rootPost], 'erasables')
|
||||
})
|
||||
|
||||
test('Tangle.getDeletablesAndErasables with lipmaa', (t) => {
|
||||
const { deletables, erasables } = tangle.getDeletablesAndErasables(reply3Lo)
|
||||
|
||||
assert.deepEqual([...deletables], [reply1Lo, reply1Hi, reply2], 'deletables')
|
||||
assert.deepEqual([...erasables], [rootPost], 'erasables')
|
||||
})
|
||||
|
||||
test('Tangle.getMinimumAmong', (t) => {
|
||||
const actual1 = tangle.getMinimumAmong([reply1Lo, reply1Hi])
|
||||
const expected1 = [reply1Lo, reply1Hi]
|
||||
assert.deepEqual(actual1, expected1)
|
||||
|
||||
const actual2 = tangle.getMinimumAmong([reply1Lo, reply1Hi, reply2])
|
||||
const expected2 = [reply1Lo, reply1Hi]
|
||||
assert.deepEqual(actual2, expected2)
|
||||
|
||||
const actual3 = tangle.getMinimumAmong([reply2, reply3Lo, reply3Hi])
|
||||
const expected3 = [reply2]
|
||||
assert.deepEqual(actual3, expected3)
|
||||
|
||||
const actual4 = tangle.getMinimumAmong([reply1Hi, reply3Lo])
|
||||
const expected4 = [reply1Hi]
|
||||
assert.deepEqual(actual4, expected4)
|
||||
})
|
||||
|
||||
test('Tangle.topoSort after some have been deleted and erased', async (t) => {
|
||||
const { deletables, erasables } = tangle.getDeletablesAndErasables(reply3Lo)
|
||||
for (const msgID of deletables) {
|
||||
await p(peer.db.del)(msgID)
|
||||
}
|
||||
for (const msgID of erasables) {
|
||||
await p(peer.db.erase)(msgID)
|
||||
}
|
||||
|
||||
const tangle2 = peer.db.getTangle(rootPost)
|
||||
const sorted = tangle2.topoSort()
|
||||
|
||||
assert.deepEqual(sorted, [rootPost, reply3Lo, reply3Hi])
|
||||
})
|
||||
|
||||
test('teardown', async (t) => {
|
||||
await p(peer.close)(true)
|
||||
})
|
||||
|
|
|
@ -4,74 +4,76 @@ const fs = require('node:fs')
|
|||
const p = require('node:util').promisify
|
||||
const Log = require('../../lib/log')
|
||||
|
||||
test('Log handles basic binary records', async function (t) {
|
||||
const file = '/tmp/ppppp-db-log-test-basic-binary.log'
|
||||
try {
|
||||
fs.unlinkSync(file)
|
||||
} catch (_) {}
|
||||
const log = Log(file, { blockSize: 2 * 1024 })
|
||||
test('Log basics', async function (t) {
|
||||
await t.test('Log handles basic binary records', async function (t) {
|
||||
const file = '/tmp/ppppp-db-log-test-basic-binary.log'
|
||||
try {
|
||||
fs.unlinkSync(file)
|
||||
} catch (_) {}
|
||||
const log = Log(file, { blockSize: 2 * 1024 })
|
||||
|
||||
const msg1 = Buffer.from('testing')
|
||||
const msg2 = Buffer.from('testing2')
|
||||
const msg1 = Buffer.from('testing')
|
||||
const msg2 = Buffer.from('testing2')
|
||||
|
||||
const offset1 = await p(log.append)(msg1)
|
||||
assert.equal(offset1, 0)
|
||||
const offset1 = await p(log.append)(msg1)
|
||||
assert.equal(offset1, 0)
|
||||
|
||||
const offset2 = await p(log.append)(msg2)
|
||||
assert.equal(offset2, msg1.length + 2)
|
||||
const offset2 = await p(log.append)(msg2)
|
||||
assert.equal(offset2, msg1.length + 2)
|
||||
|
||||
const b1 = await p(log._get)(offset1)
|
||||
assert.equal(b1.toString(), msg1.toString())
|
||||
const b1 = await p(log._get)(offset1)
|
||||
assert.equal(b1.toString(), msg1.toString())
|
||||
|
||||
const b2 = await p(log._get)(offset2)
|
||||
assert.equal(b2.toString(), msg2.toString())
|
||||
const b2 = await p(log._get)(offset2)
|
||||
assert.equal(b2.toString(), msg2.toString())
|
||||
|
||||
await p(log.close)()
|
||||
})
|
||||
|
||||
const json1 = { text: 'testing' }
|
||||
const json2 = { test: 'testing2' }
|
||||
|
||||
test('Log handles basic json records', async function (t) {
|
||||
const file = '/tmp/ppppp-db-log-test-basic-json.log'
|
||||
try {
|
||||
fs.unlinkSync(file)
|
||||
} catch (_) {}
|
||||
const log = Log(file, {
|
||||
blockSize: 2 * 1024,
|
||||
codec: require('flumecodec/json'),
|
||||
await p(log.close)()
|
||||
})
|
||||
|
||||
const offset1 = await p(log.append)(json1)
|
||||
assert.equal(offset1, 0)
|
||||
const json1 = { text: 'testing' }
|
||||
const json2 = { test: 'testing2' }
|
||||
|
||||
const offset2 = await p(log.append)(json2)
|
||||
assert.equal(offset2, 20)
|
||||
await t.test('Log handles basic json records', async function (t) {
|
||||
const file = '/tmp/ppppp-db-log-test-basic-json.log'
|
||||
try {
|
||||
fs.unlinkSync(file)
|
||||
} catch (_) {}
|
||||
const log = Log(file, {
|
||||
blockSize: 2 * 1024,
|
||||
codec: require('flumecodec/json'),
|
||||
})
|
||||
|
||||
const rec1 = await p(log._get)(offset1)
|
||||
assert.deepEqual(rec1, json1)
|
||||
const offset1 = await p(log.append)(json1)
|
||||
assert.equal(offset1, 0)
|
||||
|
||||
const rec2 = await p(log._get)(offset2)
|
||||
assert.deepEqual(rec2, json2)
|
||||
const offset2 = await p(log.append)(json2)
|
||||
assert.equal(offset2, 20)
|
||||
|
||||
await p(log.close)()
|
||||
})
|
||||
const rec1 = await p(log._get)(offset1)
|
||||
assert.deepEqual(rec1, json1)
|
||||
|
||||
test('Log handles basic json record re-reading', async function (t) {
|
||||
const file = '/tmp/ppppp-db-log-test-basic-json.log'
|
||||
const log = Log(file, {
|
||||
blockSize: 2 * 1024,
|
||||
codec: require('flumecodec/json'),
|
||||
const rec2 = await p(log._get)(offset2)
|
||||
assert.deepEqual(rec2, json2)
|
||||
|
||||
await p(log.close)()
|
||||
})
|
||||
|
||||
await p(log.onDrain)()
|
||||
assert.equal(log.since.value, 20)
|
||||
await t.test('Log handles basic json record re-reading', async function (t) {
|
||||
const file = '/tmp/ppppp-db-log-test-basic-json.log'
|
||||
const log = Log(file, {
|
||||
blockSize: 2 * 1024,
|
||||
codec: require('flumecodec/json'),
|
||||
})
|
||||
|
||||
const rec1 = await p(log._get)(0)
|
||||
assert.deepEqual(rec1, json1)
|
||||
await p(log.onDrain)()
|
||||
assert.equal(log.since.value, 20)
|
||||
|
||||
const rec2 = await p(log._get)(20)
|
||||
assert.deepEqual(rec2, json2)
|
||||
const rec1 = await p(log._get)(0)
|
||||
assert.deepEqual(rec1, json1)
|
||||
|
||||
await p(log.close)()
|
||||
const rec2 = await p(log._get)(20)
|
||||
assert.deepEqual(rec2, json2)
|
||||
|
||||
await p(log.close)()
|
||||
})
|
||||
})
|
||||
|
|
|
@ -14,176 +14,178 @@ const msg3 = Buffer.from(
|
|||
'hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db hello offsetty db'
|
||||
)
|
||||
|
||||
test('Log performing simple delete', async (t) => {
|
||||
const file = '/tmp/ppppp-db-log-test-del.log'
|
||||
try {
|
||||
fs.unlinkSync(file)
|
||||
} catch (_) {}
|
||||
const log = Log(file, { blockSize: 2 * 1024 })
|
||||
test('Log deletes', async (t) => {
|
||||
await t.test('Simple delete', async (t) => {
|
||||
const file = '/tmp/ppppp-db-log-test-del.log'
|
||||
try {
|
||||
fs.unlinkSync(file)
|
||||
} catch (_) {}
|
||||
const log = Log(file, { blockSize: 2 * 1024 })
|
||||
|
||||
const offset1 = await p(log.append)(msg1)
|
||||
assert.equal(offset1, 0)
|
||||
const offset2 = await p(log.append)(msg2)
|
||||
assert.ok(offset2 > offset1)
|
||||
const offset3 = await p(log.append)(msg3)
|
||||
assert.ok(offset3 > offset2)
|
||||
const offset1 = await p(log.append)(msg1)
|
||||
assert.equal(offset1, 0)
|
||||
const offset2 = await p(log.append)(msg2)
|
||||
assert.ok(offset2 > offset1)
|
||||
const offset3 = await p(log.append)(msg3)
|
||||
assert.ok(offset3 > offset2)
|
||||
|
||||
const buf1 = await p(log._get)(offset1)
|
||||
assert.equal(buf1.toString(), msg1.toString())
|
||||
const buf2 = await p(log._get)(offset2)
|
||||
assert.equal(buf2.toString(), msg2.toString())
|
||||
const buf3 = await p(log._get)(offset3)
|
||||
assert.equal(buf3.toString(), msg3.toString())
|
||||
const buf1 = await p(log._get)(offset1)
|
||||
assert.equal(buf1.toString(), msg1.toString())
|
||||
const buf2 = await p(log._get)(offset2)
|
||||
assert.equal(buf2.toString(), msg2.toString())
|
||||
const buf3 = await p(log._get)(offset3)
|
||||
assert.equal(buf3.toString(), msg3.toString())
|
||||
|
||||
await p(log.del)(offset2)
|
||||
await p(log.onDeletesFlushed)()
|
||||
await assert.rejects(p(log._get)(offset2), (err) => {
|
||||
assert.ok(err)
|
||||
assert.equal(err.message, 'Record has been deleted')
|
||||
assert.equal(err.code, 'ERR_AAOL_DELETED_RECORD')
|
||||
return true
|
||||
await p(log.del)(offset2)
|
||||
await p(log.onDeletesFlushed)()
|
||||
await assert.rejects(p(log._get)(offset2), (err) => {
|
||||
assert.ok(err)
|
||||
assert.equal(err.message, 'Record has been deleted')
|
||||
assert.equal(err.code, 'ERR_AAOL_DELETED_RECORD')
|
||||
return true
|
||||
})
|
||||
|
||||
await p(log.close)()
|
||||
})
|
||||
|
||||
await p(log.close)()
|
||||
})
|
||||
await t.test('Deleted records are not invalid upon re-opening', async (t) => {
|
||||
const file = '/tmp/ppppp-db-log-test-del-invalid.log'
|
||||
try {
|
||||
fs.unlinkSync(file)
|
||||
} catch (_) {}
|
||||
|
||||
test('Log deleted records are not invalid upon re-opening', async (t) => {
|
||||
const file = '/tmp/ppppp-db-log-test-del-invalid.log'
|
||||
try {
|
||||
fs.unlinkSync(file)
|
||||
} catch (_) {}
|
||||
|
||||
const opts = {
|
||||
blockSize: 2 * 1024,
|
||||
codec: {
|
||||
encode(msg) {
|
||||
return Buffer.from(JSON.stringify(msg), 'utf8')
|
||||
const opts = {
|
||||
blockSize: 2 * 1024,
|
||||
codec: {
|
||||
encode(msg) {
|
||||
return Buffer.from(JSON.stringify(msg), 'utf8')
|
||||
},
|
||||
decode(buf) {
|
||||
return JSON.parse(buf.toString('utf8'))
|
||||
},
|
||||
},
|
||||
decode(buf) {
|
||||
return JSON.parse(buf.toString('utf8'))
|
||||
},
|
||||
},
|
||||
validateRecord(buf) {
|
||||
try {
|
||||
JSON.parse(buf.toString('utf8'))
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
},
|
||||
}
|
||||
const log = Log(file, opts)
|
||||
|
||||
const offset1 = await p(log.append)({ text: 'm0' })
|
||||
const offset2 = await p(log.append)({ text: 'm1' })
|
||||
const offset3 = await p(log.append)({ text: 'm2' })
|
||||
|
||||
await p(log.del)(offset2)
|
||||
await p(log.onDeletesFlushed)()
|
||||
|
||||
await p(log.close)()
|
||||
|
||||
const log2 = Log(file, opts)
|
||||
|
||||
let arr = []
|
||||
await new Promise((resolve) => {
|
||||
log2.scan(
|
||||
(offset, value, size) => {
|
||||
arr.push(value)
|
||||
},
|
||||
(err) => {
|
||||
assert.ifError(err)
|
||||
assert.deepEqual(arr, [{ text: 'm0' }, null, { text: 'm2' }])
|
||||
resolve()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
await assert.rejects(p(log2._get)(offset2), (err) => {
|
||||
assert.ok(err)
|
||||
assert.equal(err.message, 'Record has been deleted')
|
||||
assert.equal(err.code, 'ERR_AAOL_DELETED_RECORD')
|
||||
return true
|
||||
})
|
||||
|
||||
await p(log2.close)()
|
||||
})
|
||||
|
||||
test('Log deletes are handled by scan()', async (t) => {
|
||||
const file = '/tmp/offset-test_' + Date.now() + '.log'
|
||||
const log = Log(file, { blockSize: 64 * 1024 })
|
||||
|
||||
const buf1 = Buffer.from('hello one')
|
||||
const buf2 = Buffer.from('hello two')
|
||||
|
||||
const offset1 = await p(log.append)(buf1)
|
||||
const offset2 = await p(log.append)(buf2)
|
||||
|
||||
await p(log.del)(offset1)
|
||||
await p(log.onDrain)()
|
||||
await p(log.onDeletesFlushed)()
|
||||
|
||||
const arr = []
|
||||
await new Promise((resolve) => {
|
||||
log.scan(
|
||||
(offset, rec, length) => {
|
||||
arr.push(rec)
|
||||
},
|
||||
(err) => {
|
||||
assert.ifError(err)
|
||||
resolve()
|
||||
}
|
||||
)
|
||||
})
|
||||
assert.deepEqual(arr, [null, buf2])
|
||||
|
||||
await p(log.close)()
|
||||
})
|
||||
|
||||
test('Log can handle many deleted records', { timeout: 60e3 }, async (t) => {
|
||||
const file = '/tmp/aaol-test-delete-many' + Date.now() + '.log'
|
||||
const log = Log(file, { blockSize: 64 * 1024 })
|
||||
|
||||
const TOTAL = 100000
|
||||
const offsets = []
|
||||
const logAppend = p(log.append)
|
||||
if (process.env.VERBOSE) console.time('append ' + TOTAL)
|
||||
for (let i = 0; i < TOTAL; i += 1) {
|
||||
const offset = await logAppend(Buffer.from(`hello ${i}`))
|
||||
offsets.push(offset)
|
||||
}
|
||||
assert('appended records')
|
||||
if (process.env.VERBOSE) console.timeEnd('append ' + TOTAL)
|
||||
|
||||
await p(log.onDrain)()
|
||||
|
||||
const logDel = p(log.del)
|
||||
if (process.env.VERBOSE) console.time('delete ' + TOTAL / 2)
|
||||
for (let i = 0; i < TOTAL; i += 2) {
|
||||
await logDel(offsets[i])
|
||||
}
|
||||
if (process.env.VERBOSE) console.timeEnd('delete ' + TOTAL / 2)
|
||||
assert('deleted messages')
|
||||
|
||||
await p(log.onDeletesFlushed)()
|
||||
|
||||
await new Promise((resolve) => {
|
||||
let i = 0
|
||||
log.scan(
|
||||
(offset, rec, length) => {
|
||||
if (i % 2 === 0) {
|
||||
if (rec !== null) assert.fail('record ' + i + ' should be deleted')
|
||||
} else {
|
||||
if (rec === null) assert.fail('record ' + i + ' should be present')
|
||||
validateRecord(buf) {
|
||||
try {
|
||||
JSON.parse(buf.toString('utf8'))
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
i += 1
|
||||
},
|
||||
(err) => {
|
||||
assert.ifError(err)
|
||||
resolve()
|
||||
}
|
||||
)
|
||||
}
|
||||
const log = Log(file, opts)
|
||||
|
||||
const offset1 = await p(log.append)({ text: 'm0' })
|
||||
const offset2 = await p(log.append)({ text: 'm1' })
|
||||
const offset3 = await p(log.append)({ text: 'm2' })
|
||||
|
||||
await p(log.del)(offset2)
|
||||
await p(log.onDeletesFlushed)()
|
||||
|
||||
await p(log.close)()
|
||||
|
||||
const log2 = Log(file, opts)
|
||||
|
||||
let arr = []
|
||||
await new Promise((resolve) => {
|
||||
log2.scan(
|
||||
(offset, value, size) => {
|
||||
arr.push(value)
|
||||
},
|
||||
(err) => {
|
||||
assert.ifError(err)
|
||||
assert.deepEqual(arr, [{ text: 'm0' }, null, { text: 'm2' }])
|
||||
resolve()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
await assert.rejects(p(log2._get)(offset2), (err) => {
|
||||
assert.ok(err)
|
||||
assert.equal(err.message, 'Record has been deleted')
|
||||
assert.equal(err.code, 'ERR_AAOL_DELETED_RECORD')
|
||||
return true
|
||||
})
|
||||
|
||||
await p(log2.close)()
|
||||
})
|
||||
|
||||
await p(log.close)()
|
||||
await t.test('Deletes are noticed by scan()', async (t) => {
|
||||
const file = '/tmp/offset-test_' + Date.now() + '.log'
|
||||
const log = Log(file, { blockSize: 64 * 1024 })
|
||||
|
||||
const buf1 = Buffer.from('hello one')
|
||||
const buf2 = Buffer.from('hello two')
|
||||
|
||||
const offset1 = await p(log.append)(buf1)
|
||||
const offset2 = await p(log.append)(buf2)
|
||||
|
||||
await p(log.del)(offset1)
|
||||
await p(log.onDrain)()
|
||||
await p(log.onDeletesFlushed)()
|
||||
|
||||
const arr = []
|
||||
await new Promise((resolve) => {
|
||||
log.scan(
|
||||
(offset, rec, length) => {
|
||||
arr.push(rec)
|
||||
},
|
||||
(err) => {
|
||||
assert.ifError(err)
|
||||
resolve()
|
||||
}
|
||||
)
|
||||
})
|
||||
assert.deepEqual(arr, [null, buf2])
|
||||
|
||||
await p(log.close)()
|
||||
})
|
||||
|
||||
await t.test('Many deleted records', { timeout: 60e3 }, async (t) => {
|
||||
const file = '/tmp/aaol-test-delete-many' + Date.now() + '.log'
|
||||
const log = Log(file, { blockSize: 64 * 1024 })
|
||||
|
||||
const TOTAL = 100000
|
||||
const offsets = []
|
||||
const logAppend = p(log.append)
|
||||
if (process.env.VERBOSE) console.time('append ' + TOTAL)
|
||||
for (let i = 0; i < TOTAL; i += 1) {
|
||||
const offset = await logAppend(Buffer.from(`hello ${i}`))
|
||||
offsets.push(offset)
|
||||
}
|
||||
assert('appended records')
|
||||
if (process.env.VERBOSE) console.timeEnd('append ' + TOTAL)
|
||||
|
||||
await p(log.onDrain)()
|
||||
|
||||
const logDel = p(log.del)
|
||||
if (process.env.VERBOSE) console.time('delete ' + TOTAL / 2)
|
||||
for (let i = 0; i < TOTAL; i += 2) {
|
||||
await logDel(offsets[i])
|
||||
}
|
||||
if (process.env.VERBOSE) console.timeEnd('delete ' + TOTAL / 2)
|
||||
assert('deleted messages')
|
||||
|
||||
await p(log.onDeletesFlushed)()
|
||||
|
||||
await new Promise((resolve) => {
|
||||
let i = 0
|
||||
log.scan(
|
||||
(offset, rec, length) => {
|
||||
if (i % 2 === 0) {
|
||||
if (rec !== null) assert.fail('record ' + i + ' should be deleted')
|
||||
} else {
|
||||
if (rec === null) assert.fail('record ' + i + ' should be present')
|
||||
}
|
||||
i += 1
|
||||
},
|
||||
(err) => {
|
||||
assert.ifError(err)
|
||||
resolve()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
await p(log.close)()
|
||||
})
|
||||
})
|
||||
|
|
|
@ -9,58 +9,60 @@ var file = '/tmp/ds-test_restart.log'
|
|||
var msg1 = { text: 'hello world hello world' }
|
||||
var msg2 = { text: 'hello world hello world 2' }
|
||||
|
||||
test('Log (fix buggy write) simple', async (t) => {
|
||||
try {
|
||||
fs.unlinkSync(file)
|
||||
} catch (_) {}
|
||||
const log = Log(file, {
|
||||
block: 16 * 1024,
|
||||
codec: require('flumecodec/json'),
|
||||
test('Log fix buggy write', async (t) => {
|
||||
await t.test('Simple', async (t) => {
|
||||
try {
|
||||
fs.unlinkSync(file)
|
||||
} catch (_) {}
|
||||
const log = Log(file, {
|
||||
block: 16 * 1024,
|
||||
codec: require('flumecodec/json'),
|
||||
})
|
||||
|
||||
const offset1 = await p(log.append)(msg1)
|
||||
assert.equal(offset1, 0)
|
||||
const offset2 = await p(log.append)(msg2)
|
||||
assert.equal(offset2, 36)
|
||||
|
||||
await p(log.onDrain)()
|
||||
let arr = []
|
||||
await new Promise((resolve) => {
|
||||
log.scan(
|
||||
(offset, msg, size) => {
|
||||
arr.push(msg)
|
||||
},
|
||||
(err) => {
|
||||
assert.ifError(err)
|
||||
resolve()
|
||||
}
|
||||
)
|
||||
})
|
||||
assert.deepEqual(arr, [msg1, msg2])
|
||||
|
||||
await p(log.close)()
|
||||
})
|
||||
|
||||
const offset1 = await p(log.append)(msg1)
|
||||
assert.equal(offset1, 0)
|
||||
const offset2 = await p(log.append)(msg2)
|
||||
assert.equal(offset2, 36)
|
||||
await t.test('Re-read', async (t) => {
|
||||
const log = Log(file, {
|
||||
block: 16 * 1024,
|
||||
codec: require('flumecodec/json'),
|
||||
})
|
||||
|
||||
await p(log.onDrain)()
|
||||
let arr = []
|
||||
await new Promise((resolve) => {
|
||||
log.scan(
|
||||
(offset, msg, size) => {
|
||||
arr.push(msg)
|
||||
},
|
||||
(err) => {
|
||||
assert.ifError(err)
|
||||
resolve()
|
||||
}
|
||||
)
|
||||
await p(log.onDrain)()
|
||||
let arr = []
|
||||
await new Promise((resolve) => {
|
||||
log.scan(
|
||||
(offset, msg, size) => {
|
||||
arr.push(msg)
|
||||
},
|
||||
(err) => {
|
||||
assert.ifError(err)
|
||||
resolve()
|
||||
}
|
||||
)
|
||||
})
|
||||
assert.deepEqual(arr, [msg1, msg2])
|
||||
|
||||
await p(log.close)()
|
||||
})
|
||||
assert.deepEqual(arr, [msg1, msg2])
|
||||
|
||||
await p(log.close)()
|
||||
})
|
||||
|
||||
test('Log (fix buggy write) reread', async (t) => {
|
||||
const log = Log(file, {
|
||||
block: 16 * 1024,
|
||||
codec: require('flumecodec/json'),
|
||||
})
|
||||
|
||||
await p(log.onDrain)()
|
||||
let arr = []
|
||||
await new Promise((resolve) => {
|
||||
log.scan(
|
||||
(offset, msg, size) => {
|
||||
arr.push(msg)
|
||||
},
|
||||
(err) => {
|
||||
assert.ifError(err)
|
||||
resolve()
|
||||
}
|
||||
)
|
||||
})
|
||||
assert.deepEqual(arr, [msg1, msg2])
|
||||
|
||||
await p(log.close)()
|
||||
})
|
||||
|
|
|
@ -3,82 +3,84 @@ const assert = require('node:assert')
|
|||
const Keypair = require('ppppp-keypair')
|
||||
const MsgV3 = require('../../lib/msg-v3')
|
||||
|
||||
test('MsgV3 invalid domain not a string', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
test('MsgV3 domain validation', async (t) => {
|
||||
await t.test('Not a string', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
domain: 123,
|
||||
})
|
||||
},
|
||||
/invalid domain/,
|
||||
'not a string'
|
||||
)
|
||||
})
|
||||
|
||||
test('MsgV3 invalid domain with "/" character', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
domain: 'group/init',
|
||||
})
|
||||
},
|
||||
/invalid domain/,
|
||||
'invalid domain if contains /'
|
||||
)
|
||||
})
|
||||
|
||||
test('MsgV3 invalid domain with "*" character', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
domain: 'star*',
|
||||
})
|
||||
},
|
||||
/invalid domain/,
|
||||
'invalid domain if contains *'
|
||||
)
|
||||
})
|
||||
|
||||
test('MsgV3 invalid domain too short', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
domain: 'xy',
|
||||
})
|
||||
},
|
||||
/shorter than 3/,
|
||||
'invalid domain if too short'
|
||||
)
|
||||
})
|
||||
|
||||
test('MsgV3 invalid domain too long', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
domain: 'a'.repeat(120),
|
||||
})
|
||||
},
|
||||
/100\+ characters long/,
|
||||
'invalid domain if too long'
|
||||
)
|
||||
assert.throws(
|
||||
() => {
|
||||
MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
domain: 123,
|
||||
})
|
||||
},
|
||||
/invalid domain/,
|
||||
'not a string'
|
||||
)
|
||||
})
|
||||
|
||||
await t.test('"/" character', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
domain: 'group/init',
|
||||
})
|
||||
},
|
||||
/invalid domain/,
|
||||
'invalid domain if contains /'
|
||||
)
|
||||
})
|
||||
|
||||
await t.test('"*" character', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
domain: 'star*',
|
||||
})
|
||||
},
|
||||
/invalid domain/,
|
||||
'invalid domain if contains *'
|
||||
)
|
||||
})
|
||||
|
||||
await t.test('Too short', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
domain: 'xy',
|
||||
})
|
||||
},
|
||||
/shorter than 3/,
|
||||
'invalid domain if too short'
|
||||
)
|
||||
})
|
||||
|
||||
await t.test('too long', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
domain: 'a'.repeat(120),
|
||||
})
|
||||
},
|
||||
/100\+ characters long/,
|
||||
'invalid domain if too long'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -10,338 +10,340 @@ const account = MsgV3.getMsgID(
|
|||
)
|
||||
const pubkeys = new Set([keypair.public])
|
||||
|
||||
test('MsgV3 invalid msg with non-array prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
test('MsgV3 tangles prev validation', async (t) => {
|
||||
await t.test('Non-array is a bad prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
|
||||
const msg = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
const msg = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
msg.metadata.tangles[mootID].prev = null
|
||||
const msgID = MsgV3.getMsgID(msg)
|
||||
|
||||
const err = MsgV3.validate(msg, tangle, pubkeys, msgID, mootID)
|
||||
assert.ok(err, 'invalid 2nd msg throws')
|
||||
assert.match(
|
||||
err,
|
||||
/prev ".*" should have been an array/,
|
||||
'invalid 2nd msg description'
|
||||
)
|
||||
})
|
||||
msg.metadata.tangles[mootID].prev = null
|
||||
const msgID = MsgV3.getMsgID(msg)
|
||||
|
||||
const err = MsgV3.validate(msg, tangle, pubkeys, msgID, mootID)
|
||||
assert.ok(err, 'invalid 2nd msg throws')
|
||||
assert.match(
|
||||
err,
|
||||
/prev ".*" should have been an array/,
|
||||
'invalid 2nd msg description'
|
||||
)
|
||||
})
|
||||
|
||||
test('MsgV3 invalid msg with bad prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID1 = MsgV3.getMsgID(msg1)
|
||||
tangle.add(msgID1, msg1)
|
||||
|
||||
const msg2 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
msg2.metadata.tangles[mootID].depth = 1
|
||||
msg2.metadata.tangles[mootID].prev = [1234]
|
||||
const msgID2 = MsgV3.getMsgID(msg2)
|
||||
|
||||
const err = MsgV3.validate(msg2, tangle, pubkeys, msgID2, mootID)
|
||||
assert.ok(err, 'invalid 2nd msg throws')
|
||||
assert.match(
|
||||
err,
|
||||
/prev item ".*" should have been a string/,
|
||||
'invalid 2nd msg description'
|
||||
)
|
||||
})
|
||||
|
||||
test('MsgV3 invalid msg with URI in prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID1 = MsgV3.getMsgID(msg1)
|
||||
tangle.add(msgID1, msg1)
|
||||
|
||||
const msg2 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID2 = MsgV3.getMsgID(msg2)
|
||||
const randBuf = Buffer.alloc(16).fill(16)
|
||||
const fakeMsgKey1 = `ppppp:message/v3/${base58.encode(randBuf)}`
|
||||
msg2.metadata.tangles[mootID].depth = 1
|
||||
msg2.metadata.tangles[mootID].prev = [fakeMsgKey1]
|
||||
|
||||
const err = MsgV3.validate(msg2, tangle, pubkeys, msgID2, mootID)
|
||||
assert.ok(err, 'invalid 2nd msg throws')
|
||||
assert.match(err, /prev item ".*" is a URI/, 'invalid 2nd msg description')
|
||||
})
|
||||
|
||||
test('MsgV3 invalid msg with unknown prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID1 = MsgV3.getMsgID(msg1)
|
||||
tangle.add(msgID1, msg1)
|
||||
|
||||
const unknownMsg = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Alien' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const unknownMsgID = MsgV3.getMsgID(unknownMsg)
|
||||
|
||||
const fakeMootID = 'ABCDEabcde' + mootID.substring(10)
|
||||
const tangle2 = new MsgV3.Tangle(fakeMootID)
|
||||
tangle2.add(fakeMootID, moot)
|
||||
tangle2.add(unknownMsgID, unknownMsg)
|
||||
|
||||
const msg2 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle2,
|
||||
},
|
||||
})
|
||||
const msgID2 = MsgV3.getMsgID(msg2)
|
||||
|
||||
const err = MsgV3.validate(msg2, tangle, pubkeys, msgID2, mootID)
|
||||
assert.ok(err, 'invalid 2nd msg throws')
|
||||
assert.match(
|
||||
err,
|
||||
/all prev are locally unknown/,
|
||||
'invalid 2nd msg description'
|
||||
)
|
||||
})
|
||||
|
||||
test('MsgV3 invalid feed msg with a different pubkey', (t) => {
|
||||
const keypairA = Keypair.generate('ed25519', 'alice')
|
||||
const keypairB = Keypair.generate('ed25519', 'bob')
|
||||
|
||||
const accountB = MsgV3.getMsgID(
|
||||
MsgV3.createAccount(keypairB, 'person', 'MYNONCE')
|
||||
)
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
const feedTangle = new MsgV3.Tangle(mootID)
|
||||
feedTangle.add(mootID, moot)
|
||||
|
||||
const msg = MsgV3.create({
|
||||
keypair: keypairB,
|
||||
data: { text: 'Hello world!' },
|
||||
account: accountB,
|
||||
accountTips: [accountB],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: feedTangle,
|
||||
},
|
||||
})
|
||||
const msgID = MsgV3.getMsgID(msg)
|
||||
|
||||
const err = MsgV3.validate(msg, feedTangle, pubkeys, msgID, mootID)
|
||||
assert.ok(err, 'invalid msg throws')
|
||||
assert.match(
|
||||
err,
|
||||
/pubkey ".*" should have been one of ".*" from the account ".*"/,
|
||||
'invalid msg'
|
||||
)
|
||||
})
|
||||
|
||||
test('MsgV3 invalid feed msg with a different domain', (t) => {
|
||||
const keypairA = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
const feedTangle = new MsgV3.Tangle(mootID)
|
||||
feedTangle.add(mootID, moot)
|
||||
|
||||
const msg = MsgV3.create({
|
||||
keypair: keypairA,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'comment',
|
||||
tangles: {
|
||||
[mootID]: feedTangle,
|
||||
},
|
||||
})
|
||||
const msgID = MsgV3.getMsgID(msg)
|
||||
|
||||
const err = MsgV3.validate(msg, feedTangle, pubkeys, msgID, mootID)
|
||||
assert.ok(err, 'invalid msg throws')
|
||||
assert.match(
|
||||
err,
|
||||
/domain "comment" should have been feed domain "post"/,
|
||||
'invalid feed msg'
|
||||
)
|
||||
})
|
||||
|
||||
test('MsgV3 invalid feed msg with non-alphabetical prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '1' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID1 = MsgV3.getMsgID(msg1)
|
||||
|
||||
const msg2 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '2' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID2 = MsgV3.getMsgID(msg2)
|
||||
|
||||
tangle.add(msgID1, msg1)
|
||||
tangle.add(msgID2, msg2)
|
||||
|
||||
const msg3 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '3' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID3 = MsgV3.getMsgID(msg3)
|
||||
|
||||
let prevMsgIDs = msg3.metadata.tangles[mootID].prev
|
||||
if (prevMsgIDs[0] < prevMsgIDs[1]) {
|
||||
prevMsgIDs = [prevMsgIDs[1], prevMsgIDs[0]]
|
||||
} else {
|
||||
prevMsgIDs = [prevMsgIDs[0], prevMsgIDs[1]]
|
||||
}
|
||||
msg3.metadata.tangles[mootID].prev = prevMsgIDs
|
||||
|
||||
const err = MsgV3.validate(msg3, tangle, pubkeys, msgID3, mootID)
|
||||
assert.ok(err, 'invalid 3rd msg throws')
|
||||
assert.match(
|
||||
err,
|
||||
/prev ".*" should have been alphabetically sorted/,
|
||||
'invalid error message'
|
||||
)
|
||||
})
|
||||
|
||||
test('MsgV3 invalid feed msg with duplicate prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '1' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID1 = MsgV3.getMsgID(msg1)
|
||||
|
||||
const [prevID] = msg1.metadata.tangles[mootID].prev
|
||||
msg1.metadata.tangles[mootID].prev = [prevID, prevID]
|
||||
|
||||
const err = MsgV3.validate(msg1, tangle, pubkeys, msgID1, mootID)
|
||||
assert.ok(err, 'invalid 1st msg throws')
|
||||
assert.match(err, /prev ".*" contains duplicates/, 'invalid error message')
|
||||
await t.test('Number not allowed in prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID1 = MsgV3.getMsgID(msg1)
|
||||
tangle.add(msgID1, msg1)
|
||||
|
||||
const msg2 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
msg2.metadata.tangles[mootID].depth = 1
|
||||
msg2.metadata.tangles[mootID].prev = [1234]
|
||||
const msgID2 = MsgV3.getMsgID(msg2)
|
||||
|
||||
const err = MsgV3.validate(msg2, tangle, pubkeys, msgID2, mootID)
|
||||
assert.ok(err, 'invalid 2nd msg throws')
|
||||
assert.match(
|
||||
err,
|
||||
/prev item ".*" should have been a string/,
|
||||
'invalid 2nd msg description'
|
||||
)
|
||||
})
|
||||
|
||||
await t.test('URI not allowed in prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID1 = MsgV3.getMsgID(msg1)
|
||||
tangle.add(msgID1, msg1)
|
||||
|
||||
const msg2 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID2 = MsgV3.getMsgID(msg2)
|
||||
const randBuf = Buffer.alloc(16).fill(16)
|
||||
const fakeMsgKey1 = `ppppp:message/v3/${base58.encode(randBuf)}`
|
||||
msg2.metadata.tangles[mootID].depth = 1
|
||||
msg2.metadata.tangles[mootID].prev = [fakeMsgKey1]
|
||||
|
||||
const err = MsgV3.validate(msg2, tangle, pubkeys, msgID2, mootID)
|
||||
assert.ok(err, 'invalid 2nd msg throws')
|
||||
assert.match(err, /prev item ".*" is a URI/, 'invalid 2nd msg description')
|
||||
})
|
||||
|
||||
await t.test('Locally unknown prev msgID', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID1 = MsgV3.getMsgID(msg1)
|
||||
tangle.add(msgID1, msg1)
|
||||
|
||||
const unknownMsg = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Alien' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const unknownMsgID = MsgV3.getMsgID(unknownMsg)
|
||||
|
||||
const fakeMootID = 'ABCDEabcde' + mootID.substring(10)
|
||||
const tangle2 = new MsgV3.Tangle(fakeMootID)
|
||||
tangle2.add(fakeMootID, moot)
|
||||
tangle2.add(unknownMsgID, unknownMsg)
|
||||
|
||||
const msg2 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle2,
|
||||
},
|
||||
})
|
||||
const msgID2 = MsgV3.getMsgID(msg2)
|
||||
|
||||
const err = MsgV3.validate(msg2, tangle, pubkeys, msgID2, mootID)
|
||||
assert.ok(err, 'invalid 2nd msg throws')
|
||||
assert.match(
|
||||
err,
|
||||
/all prev are locally unknown/,
|
||||
'invalid 2nd msg description'
|
||||
)
|
||||
})
|
||||
|
||||
await t.test('Feed msg with the wrong pubkey', (t) => {
|
||||
const keypairA = Keypair.generate('ed25519', 'alice')
|
||||
const keypairB = Keypair.generate('ed25519', 'bob')
|
||||
|
||||
const accountB = MsgV3.getMsgID(
|
||||
MsgV3.createAccount(keypairB, 'person', 'MYNONCE')
|
||||
)
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
const feedTangle = new MsgV3.Tangle(mootID)
|
||||
feedTangle.add(mootID, moot)
|
||||
|
||||
const msg = MsgV3.create({
|
||||
keypair: keypairB,
|
||||
data: { text: 'Hello world!' },
|
||||
account: accountB,
|
||||
accountTips: [accountB],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: feedTangle,
|
||||
},
|
||||
})
|
||||
const msgID = MsgV3.getMsgID(msg)
|
||||
|
||||
const err = MsgV3.validate(msg, feedTangle, pubkeys, msgID, mootID)
|
||||
assert.ok(err, 'invalid msg throws')
|
||||
assert.match(
|
||||
err,
|
||||
/pubkey ".*" should have been one of ".*" from the account ".*"/,
|
||||
'invalid msg'
|
||||
)
|
||||
})
|
||||
|
||||
await t.test('Feed msg with the wrong domain', (t) => {
|
||||
const keypairA = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
const feedTangle = new MsgV3.Tangle(mootID)
|
||||
feedTangle.add(mootID, moot)
|
||||
|
||||
const msg = MsgV3.create({
|
||||
keypair: keypairA,
|
||||
data: { text: 'Hello world!' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'comment',
|
||||
tangles: {
|
||||
[mootID]: feedTangle,
|
||||
},
|
||||
})
|
||||
const msgID = MsgV3.getMsgID(msg)
|
||||
|
||||
const err = MsgV3.validate(msg, feedTangle, pubkeys, msgID, mootID)
|
||||
assert.ok(err, 'invalid msg throws')
|
||||
assert.match(
|
||||
err,
|
||||
/domain "comment" should have been feed domain "post"/,
|
||||
'invalid feed msg'
|
||||
)
|
||||
})
|
||||
|
||||
await t.test('Feed msg with non-alphabetically sorted prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '1' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID1 = MsgV3.getMsgID(msg1)
|
||||
|
||||
const msg2 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '2' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID2 = MsgV3.getMsgID(msg2)
|
||||
|
||||
tangle.add(msgID1, msg1)
|
||||
tangle.add(msgID2, msg2)
|
||||
|
||||
const msg3 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '3' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID3 = MsgV3.getMsgID(msg3)
|
||||
|
||||
let prevMsgIDs = msg3.metadata.tangles[mootID].prev
|
||||
if (prevMsgIDs[0] < prevMsgIDs[1]) {
|
||||
prevMsgIDs = [prevMsgIDs[1], prevMsgIDs[0]]
|
||||
} else {
|
||||
prevMsgIDs = [prevMsgIDs[0], prevMsgIDs[1]]
|
||||
}
|
||||
msg3.metadata.tangles[mootID].prev = prevMsgIDs
|
||||
|
||||
const err = MsgV3.validate(msg3, tangle, pubkeys, msgID3, mootID)
|
||||
assert.ok(err, 'invalid 3rd msg throws')
|
||||
assert.match(
|
||||
err,
|
||||
/prev ".*" should have been alphabetically sorted/,
|
||||
'invalid error message'
|
||||
)
|
||||
})
|
||||
|
||||
await t.test('Feed msg with duplicate prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '1' },
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
})
|
||||
const msgID1 = MsgV3.getMsgID(msg1)
|
||||
|
||||
const [prevID] = msg1.metadata.tangles[mootID].prev
|
||||
msg1.metadata.tangles[mootID].prev = [prevID, prevID]
|
||||
|
||||
const err = MsgV3.validate(msg1, tangle, pubkeys, msgID1, mootID)
|
||||
assert.ok(err, 'invalid 1st msg throws')
|
||||
assert.match(err, /prev ".*" contains duplicates/, 'invalid error message')
|
||||
})
|
||||
})
|
||||
|
|
|
@ -3,165 +3,161 @@ const assert = require('node:assert')
|
|||
const Keypair = require('ppppp-keypair')
|
||||
const MsgV3 = require('../../lib/msg-v3')
|
||||
|
||||
test('MsgV3 validate root msg', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const account = MsgV3.getMsgID(
|
||||
MsgV3.createAccount(keypair, 'person', 'alice')
|
||||
)
|
||||
const pubkeys = new Set([keypair.public])
|
||||
test('MsgV3 validation', async (t) => {
|
||||
await t.test('Correct root msg', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const account = MsgV3.getMsgID(
|
||||
MsgV3.createAccount(keypair, 'person', 'alice')
|
||||
)
|
||||
const pubkeys = new Set([keypair.public])
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
|
||||
const err = MsgV3.validate(moot, tangle, pubkeys, mootID, mootID)
|
||||
assert.ifError(err, 'valid root msg')
|
||||
})
|
||||
|
||||
test('MsgV3 validate account tangle', (t) => {
|
||||
const pubkeys = new Set()
|
||||
const keypair1 = Keypair.generate('ed25519', 'alice')
|
||||
pubkeys.add(keypair1.public)
|
||||
|
||||
const accountMsg0 = MsgV3.createAccount(keypair1, 'person', 'alice')
|
||||
const account = MsgV3.getMsgID(accountMsg0)
|
||||
const accountMsg0ID = account
|
||||
|
||||
const tangle = new MsgV3.Tangle(account)
|
||||
tangle.add(accountMsg0ID, accountMsg0)
|
||||
|
||||
let err = MsgV3.validate(
|
||||
accountMsg0,
|
||||
tangle,
|
||||
pubkeys,
|
||||
accountMsg0ID,
|
||||
account
|
||||
)
|
||||
assert.ifError(err, 'valid account root msg')
|
||||
|
||||
tangle.add(account, accountMsg0)
|
||||
|
||||
const keypair2 = Keypair.generate('ed25519', 'bob')
|
||||
|
||||
const accountMsg1 = MsgV3.create({
|
||||
account: 'self',
|
||||
accountTips: null,
|
||||
domain: 'account',
|
||||
data: { add: keypair2.public },
|
||||
tangles: {
|
||||
[account]: tangle,
|
||||
},
|
||||
keypair: keypair1, // announcing keypair2 but signing with keypair1
|
||||
const err = MsgV3.validate(moot, tangle, pubkeys, mootID, mootID)
|
||||
assert.ifError(err, 'valid root msg')
|
||||
})
|
||||
const accountMsg1ID = MsgV3.getMsgID(accountMsg1)
|
||||
|
||||
err = MsgV3.validate(
|
||||
accountMsg1,
|
||||
tangle,
|
||||
pubkeys,
|
||||
accountMsg1ID,
|
||||
account
|
||||
)
|
||||
assert.ifError(err, 'valid account msg')
|
||||
})
|
||||
await t.test('Correct account tangle', (t) => {
|
||||
const pubkeys = new Set()
|
||||
const keypair1 = Keypair.generate('ed25519', 'alice')
|
||||
pubkeys.add(keypair1.public)
|
||||
|
||||
test('MsgV3 validate 2nd msg with existing root', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const account = MsgV3.getMsgID(
|
||||
MsgV3.createAccount(keypair, 'person', 'alice')
|
||||
)
|
||||
const pubkeys = new Set([keypair.public])
|
||||
const accountMsg0 = MsgV3.createAccount(keypair1, 'person', 'alice')
|
||||
const account = MsgV3.getMsgID(accountMsg0)
|
||||
const accountMsg0ID = account
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
const tangle = new MsgV3.Tangle(account)
|
||||
tangle.add(accountMsg0ID, accountMsg0)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data: { text: 'Hello world!' },
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
keypair,
|
||||
let err = MsgV3.validate(
|
||||
accountMsg0,
|
||||
tangle,
|
||||
pubkeys,
|
||||
accountMsg0ID,
|
||||
account
|
||||
)
|
||||
assert.ifError(err, 'valid account root msg')
|
||||
|
||||
tangle.add(account, accountMsg0)
|
||||
|
||||
const keypair2 = Keypair.generate('ed25519', 'bob')
|
||||
|
||||
const accountMsg1 = MsgV3.create({
|
||||
account: 'self',
|
||||
accountTips: null,
|
||||
domain: 'account',
|
||||
data: { add: keypair2.public },
|
||||
tangles: {
|
||||
[account]: tangle,
|
||||
},
|
||||
keypair: keypair1, // announcing keypair2 but signing with keypair1
|
||||
})
|
||||
const accountMsg1ID = MsgV3.getMsgID(accountMsg1)
|
||||
|
||||
err = MsgV3.validate(accountMsg1, tangle, pubkeys, accountMsg1ID, account)
|
||||
assert.ifError(err, 'valid account msg')
|
||||
})
|
||||
const msgID1 = MsgV3.getMsgID(msg1)
|
||||
tangle.add(msgID1, msg1)
|
||||
|
||||
const err = MsgV3.validate(msg1, tangle, pubkeys, msgID1, mootID)
|
||||
assert.ifError(err, 'valid 2nd msg')
|
||||
})
|
||||
await t.test('2nd msg correct with existing root', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const account = MsgV3.getMsgID(
|
||||
MsgV3.createAccount(keypair, 'person', 'alice')
|
||||
)
|
||||
const pubkeys = new Set([keypair.public])
|
||||
|
||||
test('MsgV3 validate 2nd forked msg', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const account = MsgV3.getMsgID(
|
||||
MsgV3.createAccount(keypair, 'person', 'alice')
|
||||
)
|
||||
const pubkeys = new Set([keypair.public])
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
const msg1 = MsgV3.create({
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data: { text: 'Hello world!' },
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
keypair,
|
||||
})
|
||||
const msgID1 = MsgV3.getMsgID(msg1)
|
||||
tangle.add(msgID1, msg1)
|
||||
|
||||
const msg1A = MsgV3.create({
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data: { text: 'Hello world!' },
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
keypair,
|
||||
const err = MsgV3.validate(msg1, tangle, pubkeys, msgID1, mootID)
|
||||
assert.ifError(err, 'valid 2nd msg')
|
||||
})
|
||||
const msgID1A = MsgV3.getMsgID(msg1A)
|
||||
|
||||
const msg1B = MsgV3.create({
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data: { text: 'Hello world!' },
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
keypair,
|
||||
await t.test('2nd forked msg correct', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const account = MsgV3.getMsgID(
|
||||
MsgV3.createAccount(keypair, 'person', 'alice')
|
||||
)
|
||||
const pubkeys = new Set([keypair.public])
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
|
||||
const msg1A = MsgV3.create({
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data: { text: 'Hello world!' },
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
keypair,
|
||||
})
|
||||
const msgID1A = MsgV3.getMsgID(msg1A)
|
||||
|
||||
const msg1B = MsgV3.create({
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data: { text: 'Hello world!' },
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
keypair,
|
||||
})
|
||||
const msgID1B = MsgV3.getMsgID(msg1B)
|
||||
|
||||
tangle.add(msgID1A, msg1A)
|
||||
tangle.add(msgID1B, msg1B)
|
||||
const err = MsgV3.validate(msg1B, tangle, pubkeys, msgID1B, mootID)
|
||||
assert.ifError(err, 'valid 2nd forked msg')
|
||||
})
|
||||
const msgID1B = MsgV3.getMsgID(msg1B)
|
||||
|
||||
tangle.add(msgID1A, msg1A)
|
||||
tangle.add(msgID1B, msg1B)
|
||||
const err = MsgV3.validate(msg1B, tangle, pubkeys, msgID1B, mootID)
|
||||
assert.ifError(err, 'valid 2nd forked msg')
|
||||
})
|
||||
await t.test('Correct erased msg', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const account = MsgV3.getMsgID(
|
||||
MsgV3.createAccount(keypair, 'person', 'alice')
|
||||
)
|
||||
const pubkeys = new Set([keypair.public])
|
||||
|
||||
test('MsgV3 validate erased msg', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const account = MsgV3.getMsgID(
|
||||
MsgV3.createAccount(keypair, 'person', 'alice')
|
||||
)
|
||||
const pubkeys = new Set([keypair.public])
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
|
||||
const moot = MsgV3.createMoot(account, 'post', keypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
const tangle = new MsgV3.Tangle(mootID)
|
||||
tangle.add(mootID, moot)
|
||||
const msg1 = MsgV3.create({
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data: { text: 'Hello world!' },
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
keypair,
|
||||
})
|
||||
msg1.data = null
|
||||
const msgID1 = MsgV3.getMsgID(msg1)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data: { text: 'Hello world!' },
|
||||
tangles: {
|
||||
[mootID]: tangle,
|
||||
},
|
||||
keypair,
|
||||
const err = MsgV3.validate(msg1, tangle, pubkeys, msgID1, mootID)
|
||||
assert.ifError(err, 'valid erased msg')
|
||||
})
|
||||
msg1.data = null
|
||||
const msgID1 = MsgV3.getMsgID(msg1)
|
||||
|
||||
const err = MsgV3.validate(msg1, tangle, pubkeys, msgID1, mootID)
|
||||
assert.ifError(err, 'valid erased msg')
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue