OverviewFilesCommitsIssuesDocsReleasesPeers

hypercore-kb / hyper-social / hyper-daemon / test / runtime.test.js

163 lines · javascript ref:
import test from 'brittle'
import { DaemonRuntime } from '../lib/runtime.js'
import { tmpdir } from 'os'
import { join } from 'path'
import { randomBytes } from 'crypto'

function tmpStorage () {
  return join(tmpdir(), 'hyper-daemon-test-' + randomBytes(8).toString('hex'))
}

test('DaemonRuntime - load and fire script', async (t) => {
  const logs = []
  const runtime = new DaemonRuntime(tmpStorage(), {
    onLog: (msg) => logs.push(msg)
  })
  await runtime.ready()

  let actionCalled = false

  await runtime.load('greet', {
    trigger: { type: 'message', filter: { contains: 'hello' } },
    actions: [{
      type: 'log',
      message: 'Greeting detected!'
    }],
    enabled: true
  })

  // Override action for testing — fire triggers the registered action
  const results = await runtime.fire('message', { text: 'hello world' })
  t.is(results.length, 1)
  t.ok(results[0].ok)

  t.ok(logs.some(l => l.includes('Loaded script: greet')))

  await runtime.close()
})

test('DaemonRuntime - list scripts', async (t) => {
  const runtime = new DaemonRuntime(tmpStorage(), { onLog: () => {} })
  await runtime.ready()

  await runtime.load('script-a', {
    trigger: { type: 'message' },
    actions: [{ type: 'log', message: 'a' }]
  })
  await runtime.load('script-b', {
    trigger: { type: 'file-change' },
    actions: [{ type: 'log', message: 'b' }]
  })

  const list = runtime.list()
  t.is(list.length, 2)
  t.ok(list.find(s => s.id === 'script-a'))
  t.ok(list.find(s => s.id === 'script-b'))

  await runtime.close()
})

test('DaemonRuntime - unload script', async (t) => {
  const runtime = new DaemonRuntime(tmpStorage(), { onLog: () => {} })
  await runtime.ready()

  await runtime.load('temp', {
    trigger: { type: 'message' },
    actions: [{ type: 'log', message: 'temp' }]
  })

  t.is(runtime.list().length, 1)

  await runtime.unload('temp')
  t.is(runtime.list().length, 0)

  // Verify no triggers fire
  const results = await runtime.fire('message', {})
  t.is(results.length, 0)

  await runtime.close()
})

test('DaemonRuntime - enable/disable', async (t) => {
  const runtime = new DaemonRuntime(tmpStorage(), { onLog: () => {} })
  await runtime.ready()

  await runtime.load('toggle', {
    trigger: { type: 'message' },
    actions: [{ type: 'log', message: 'toggled' }]
  })

  runtime.disable('toggle')
  const r1 = await runtime.fire('message', { text: 'test' })
  t.is(r1.length, 0)

  runtime.enable('toggle')
  const r2 = await runtime.fire('message', { text: 'test' })
  t.is(r2.length, 1)

  await runtime.close()
})

test('DaemonRuntime - filter matching', async (t) => {
  const runtime = new DaemonRuntime(tmpStorage(), { onLog: () => {} })
  await runtime.ready()

  await runtime.load('filtered', {
    trigger: { type: 'message', filter: { author: 'alice' } },
    actions: [{ type: 'log', message: 'alice said something' }]
  })

  const r1 = await runtime.fire('message', { author: 'alice', text: 'hi' })
  t.is(r1.length, 1)

  const r2 = await runtime.fire('message', { author: 'bob', text: 'hi' })
  t.is(r2.length, 0)

  await runtime.close()
})

test('DaemonRuntime - event logging', async (t) => {
  const runtime = new DaemonRuntime(tmpStorage(), { onLog: () => {} })
  await runtime.ready()

  await runtime.load('logged', {
    trigger: { type: 'message' },
    actions: [{ type: 'log', message: 'event' }]
  })

  await runtime.fire('message', { text: 'first' })
  await runtime.fire('message', { text: 'second' })

  const log = await runtime.getLog('logged')
  t.is(log.length, 2)
  t.ok(log[0].timestamp > 0)
  t.is(log[0].trigger, 'message')

  await runtime.close()
})

test('DaemonRuntime - persistence (loadAll)', async (t) => {
  const storage = tmpStorage()

  // Save scripts
  const rt1 = new DaemonRuntime(storage, { onLog: () => {} })
  await rt1.ready()
  await rt1.load('persistent', {
    trigger: { type: 'message' },
    actions: [{ type: 'log', message: 'persistent' }]
  })
  await rt1.close()

  // Reload
  const rt2 = new DaemonRuntime(storage, { onLog: () => {} })
  await rt2.ready()
  const loaded = await rt2.loadAll()
  t.is(loaded, 1)

  const list = rt2.list()
  t.is(list.length, 1)
  t.is(list[0].id, 'persistent')

  await rt2.close()
})