OverviewFilesCommitsIssuesDocsReleasesPeers

pear-git-v3 / test / gip-producer-wiring.test.js

78 lines · javascript ref:
// gip-overlay P3d — the producer is wired into ref-update-observed.
//
// Boot a real daemon, create a bare repo with a commit, fire the
// ref-update-observed RPC (as the post-receive hook does), and assert the
// gip producer projected it: the per-repo autobase has the ref + bundle-chain
// entry, and a bundle file was spooled. Proves the live hot-path wiring, not
// just the unit (covered by gip-publish-roundtrip).

import test from 'brittle'
import { mkdtempSync, mkdirSync, writeFileSync, existsSync, readdirSync } from '#node:fs'
import { join } from '#node:path'
import { tmpdir } from '#node:os'
import { Client } from 'hyper-svc'

import { startPearGit } from '../index.js'
import { execFileSync } from '../lib/_compat-exec.js'

const ZERO = '0000000000000000000000000000000000000000'

function git (args, opts = {}) {
  return execFileSync('git', args, { encoding: 'utf8', ...opts }).toString().trim()
}
function tmpStorage () { return mkdtempSync(join(tmpdir(), 'pgv3-gipw-')) }
function tmpSock () { return join(mkdtempSync(join(tmpdir(), 'pgv3-gipw-sock-')), 'svc.sock') }

async function until (fn, ms = 5000) {
  for (let waited = 0; waited < ms; waited += 100) {
    const v = await fn()
    if (v) return v
    await new Promise(r => setTimeout(r, 100))
  }
  return null
}

test('ref-update-observed publishes the ref + bundle into the per-repo autobase', async (t) => {
  const storage = tmpStorage()
  const node = await startPearGit({ storage, uds: tmpSock(), http: { port: 0 }, swarm: false, autoImportSSH: false })
  t.teardown(async () => { try { await node.close() } catch {} })

  // create a bare repo in the daemon's reposDir + a commit on main
  const reposDir = node.svc._reposDir
  mkdirSync(reposDir, { recursive: true })
  const bare = join(reposDir, 'gip-test.git')
  git(['init', '--bare', '-q', bare])
  const work = join(storage, 'work')
  git(['init', '-q', work])
  git(['-C', work, 'config', 'user.email', 't@t'])
  git(['-C', work, 'config', 'user.name', 'T'])
  git(['-C', work, 'config', 'commit.gpgsign', 'false'])
  writeFileSync(join(work, 'a.txt'), 'one\n')
  git(['-C', work, 'add', '.'])
  git(['-C', work, 'commit', '-q', '-m', 'c1'])
  const oid = git(['-C', work, 'rev-parse', 'HEAD'])
  git(['-C', work, 'push', '-q', bare, 'HEAD:refs/heads/main'])

  // fire the RPC the post-receive hook posts
  const client = await Client.discover({ uds: node.svc.uds.path })
  const res = await client.call('ref-update-observed', { name: 'gip-test', ref: 'refs/heads/main', oldSha: ZERO, newSha: oid })
  t.ok(res && res.ok, 'ref-update-observed accepted')

  // producer is fire-and-forget — wait for the autobase to reflect it
  const tracker = await node.svc.issueRegistry.getForRepo('gip-test')
  const ref = await until(async () => {
    const r = await tracker.getRef('refs/heads/main')
    return r && r.hash === oid ? r : null
  })
  t.ok(ref, 'ref published into the per-repo autobase at the pushed oid')

  const bundle = await tracker.getBundle(oid)
  t.ok(bundle && bundle.contentHash, 'bundle-chain entry recorded with a content hash')
  t.is(bundle.baseOid, ZERO, 'creation bundle baseOid is ZERO')

  const spool = join(storage, 'gip-bundles', 'gip-test')
  t.ok(existsSync(spool) && readdirSync(spool).some(f => f.endsWith('.bundle')), 'a bundle file was spooled')

  try { await client.close() } catch {}
})