OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-note / test / instance-linker.test.js

96 lines · javascript ref:
import test from 'brittle'
import Corestore from 'corestore'
import Hyperswarm from 'hyperswarm'
import createTestnet from 'hyperdht/testnet'
import os from 'bare-os'
import path from 'bare-path'
import { randomBytes } from 'hypercore-crypto'
import { SharedRegistry } from '../lib/multiwriter/shared-registry.js'
import { InstanceLinker } from '../lib/multiwriter/instance-linker.js'

function createStore () {
  const tmp = path.join(os.tmpdir(), 'hypernote-linker-test-' + randomBytes(16).toString('hex'))
  return new Corestore(tmp)
}

test('createInvite returns hex invite', async (t) => {
  const testnet = await createTestnet(3)
  const bootstrap = testnet.bootstrap

  const store = createStore()
  const reg = new SharedRegistry(store)
  await reg.ready()

  const swarm = new Hyperswarm({ bootstrap })
  const linker = new InstanceLinker(reg, { swarm })

  const result = await linker.createInvite()

  t.ok(result.invite, 'invite buffer exists')
  t.ok(result.inviteHex, 'inviteHex exists')
  t.is(typeof result.inviteHex, 'string', 'inviteHex is a string')
  t.ok(result.inviteHex.length > 0, 'inviteHex is non-empty')
  t.is(typeof result.waitForPeer, 'function', 'waitForPeer is a function')

  await linker.destroy()
  await swarm.destroy()
  await reg.close()
  await store.close()
  await testnet.destroy()
})

test('full link flow between two instances', async (t) => {
  const testnet = await createTestnet(3)
  const bootstrap = testnet.bootstrap

  // Create two stores and registries
  const store1 = createStore()
  const reg1 = new SharedRegistry(store1)
  await reg1.ready()

  const store2 = createStore()
  const reg2 = new SharedRegistry(store2)
  await reg2.ready()

  // Add a user on registry 1
  await reg1.createUser({ userId: 'admin1', name: 'Admin', role: 'admin' })

  // Create swarms with testnet bootstrap
  const swarm1 = new Hyperswarm({ bootstrap })
  const swarm2 = new Hyperswarm({ bootstrap })

  const linker1 = new InstanceLinker(reg1, { swarm: swarm1 })
  const linker2 = new InstanceLinker(reg2, { swarm: swarm2 })

  // Instance 1 creates invite
  const inviteResult = await linker1.createInvite()
  t.ok(inviteResult.inviteHex, 'invite created')

  // Instance 2 joins with invite, while instance 1 waits for peer
  const [joinResult, joinerInfo] = await Promise.all([
    linker2.joinWithInvite(inviteResult.inviteHex),
    inviteResult.waitForPeer()
  ])

  // Verify join result has the source's keys
  t.ok(joinResult.bootstrapKey, 'joinResult has bootstrapKey')
  t.is(joinResult.bootstrapKey, reg1.bootstrapKey.toString('hex'), 'bootstrapKey matches reg1')
  t.ok(joinResult.writerKey, 'joinResult has writerKey')
  t.is(joinResult.writerKey, reg1.localWriterKey.toString('hex'), 'writerKey matches reg1 local writer')

  // Verify the member (instance 1) got the joiner's info
  t.ok(joinerInfo, 'joinerInfo received by member')
  t.is(joinerInfo.writerKey, reg2.localWriterKey.toString('hex'), 'joinerInfo writerKey matches reg2')

  // Cleanup
  await linker1.destroy()
  await linker2.destroy()
  await swarm1.destroy()
  await swarm2.destroy()
  await reg1.close()
  await reg2.close()
  await store1.close()
  await store2.close()
  await testnet.destroy()
})