OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-rooms / test / resilience.test.js

44 lines · javascript ref:
import test from 'brittle'
import Corestore from 'corestore'
import { mkdtempSync } from 'fs'
import { join } from 'path'
import { tmpdir } from 'os'
import { Room, jsonSchema } from '../index.js'

function tmp () { return mkdtempSync(join(tmpdir(), 'rooms-resil-')) }

const schema = jsonSchema({
  validate () {},
  async apply (batch, op) { if (op.type === 'put') await batch.put('k:' + op.id, { v: op.v }) }
})

// pear-git #3 Increment 1: a tracker autobase 'error' must be ISOLATED (logged +
// re-emitted as 'base-error'), never fatal. autobase routes drain/apply failures
// through _onError -> emit('error'); with no listener EventEmitter re-throws and
// SIGABRTs the whole daemon. This proves the Room's handler catches it.
test('tracker autobase error is isolated, not fatal (#3 resilience)', async (t) => {
  const store = new Corestore(tmp())
  const room = new Room(store, { schema, namespace: 'resil-test', bootstrapKey: null })
  await room.ready()

  t.is(room.errored, null, 'not errored initially')

  let reEmitted = null
  room.on('base-error', (err) => { reEmitted = err })

  const boom = new Error('simulated drain failure (null view)')
  t.execution(() => room._base.emit('error', boom), 'emitting base error does NOT throw')

  t.is(room.errored, boom, 'room.errored records the error')
  t.is(reEmitted, boom, "'base-error' re-emitted to consumers")

  let warned = null
  room.on('base-warning', (err) => { warned = err })
  const warn = new Error('simulated warning')
  t.execution(() => room._base.emit('warning', warn), 'emitting base warning does NOT throw')
  t.is(warned, warn, "'base-warning' re-emitted to consumers")

  await room.close()
  await store.close()
})