OverviewFilesCommitsIssuesDocsReleasesPeers

pear-git-v3 / test / ref-reconciler-ref-activity.test.js

111 lines · javascript ref:
// RefReconciler reports the repo's newest REPLICATED ref timestamp.
//
// /repos orders on this instead of the local mtime — see
// services/repo-ref-activity.js for the full why. What matters here is that
// the reporting is FREE: _reconcileOnce already calls listRefs(), which is the
// `base.update()` plus ref range-scan the whole sweep-skip machinery exists to
// avoid repeating. Taking max(timestamp) off the array it already has adds no
// autobase work at all.
//
// It must also fire on a NO-OP pass. The value is a property of the view, not
// of whether this daemon's disk changed — on a mirror that is already in sync
// (the common case, and exactly the backend the LB fronts) every pass is a
// no-op, and gating on `changed` like onChange does would leave the ordering
// key permanently unset there.

import test from 'brittle'
import { mkdtempSync, writeFileSync } from '#node:fs'
import { join } from '#node:path'
import { tmpdir } from '#node:os'

import { RefReconciler } from '../lib/services/ref-reconciler.js'
import { execFileSync } from '../lib/_compat-exec.js'

function git (args, opts = {}) {
  return execFileSync('git', args, { encoding: 'utf8', ...opts }).toString().trim()
}

function fakeTracker (refs) {
  return {
    base: { on () {}, off () {} },
    async listRefs () { return refs.slice() }
  }
}

function makeRepo () {
  const dir = mkdtempSync(join(tmpdir(), 'pgv3-refact-rec-'))
  const bare = join(dir, 'repo.git')
  const work = join(dir, 'work')
  git(['init', '--bare', '-q', bare])
  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 o1 = git(['-C', work, 'rev-parse', 'HEAD'])
  git(['-C', work, 'push', '-q', bare, 'HEAD:refs/heads/main'])
  return { bare, o1 }
}

test('reports the newest ref timestamp across the view', async (t) => {
  const { bare, o1 } = makeRepo()
  const seen = []
  const tracker = fakeTracker([
    { ref: 'refs/heads/main', hash: o1, timestamp: 1000 },
    { ref: 'refs/heads/old', hash: o1, timestamp: 500 },
    { ref: 'refs/heads/new', hash: o1, timestamp: 7000 }
  ])
  const rec = new RefReconciler({
    tracker,
    repoPath: bare,
    onRefActivity: (ms) => seen.push(ms)
  })
  await rec.reconcile()
  t.alike(seen, [7000], 'the max, not the first or the last')
})

test('fires on a no-op pass — a synced mirror must still report', async (t) => {
  const { bare, o1 } = makeRepo()
  const seen = []
  // The bare repo is ALREADY at o1, so this pass changes nothing on disk.
  const tracker = fakeTracker([{ ref: 'refs/heads/main', hash: o1, timestamp: 4242 }])
  const rec = new RefReconciler({ tracker, repoPath: bare, onRefActivity: (ms) => seen.push(ms) })
  await rec.reconcile()
  t.is(git(['--git-dir', bare, 'rev-parse', 'refs/heads/main']), o1, 'nothing moved on disk')
  t.alike(seen, [4242], 'reported anyway')
})

test('stays silent when the view carries no usable timestamp', async (t) => {
  const { bare, o1 } = makeRepo()
  const seen = []
  // A ref-view written by a build that predates the timestamp field, or an
  // empty view. Reporting 0 would rank the repo below everything.
  const tracker = fakeTracker([{ ref: 'refs/heads/main', hash: o1 }])
  const rec = new RefReconciler({ tracker, repoPath: bare, onRefActivity: (ms) => seen.push(ms) })
  await rec.reconcile()
  t.alike(seen, [], 'no timestamp, no report')

  const empty = new RefReconciler({
    tracker: fakeTracker([]),
    repoPath: bare,
    onRefActivity: (ms) => seen.push(ms)
  })
  await empty.reconcile()
  t.alike(seen, [], 'empty view, no report')
})

test('a failing onRefActivity never breaks reconciliation', async (t) => {
  const { bare, o1 } = makeRepo()
  git(['--git-dir', bare, 'update-ref', '-d', 'refs/heads/main'])
  const rec = new RefReconciler({
    tracker: fakeTracker([{ ref: 'refs/heads/main', hash: o1, timestamp: 1 }]),
    repoPath: bare,
    onRefActivity: () => { throw new Error('index exploded') }
  })
  await rec.reconcile()
  t.is(git(['--git-dir', bare, 'rev-parse', 'refs/heads/main']), o1,
    'the ref was still materialized despite the hook throwing')
})