// Phase B: mountOrgGroupedRepos fans out to exactly the repos in an org's
// resourceKeys map (scoped), binding each tracker key, opening it,
// rendezvousing on its room topic, and kicking off materialization. A
// name-only resource (no key) is skipped, and the call is idempotent.
//
// Deps are mocked so this runs deterministically without a live swarm —
// the cross-machine swarm path is proven separately by the e2e.
import test from 'brittle'
import { mountOrgGroupedRepos } from '../lib/services/org-grouped-repos.js'
function mockDeps (org) {
const calls = { bound: [], opened: [], activated: [], ensured: [] }
const deps = {
getOrg: async () => org,
activateRoom: (dk) => calls.activated.push(dk),
refReconcilers: { ensureFor: (name) => { calls.ensured.push(name); return Promise.resolve() } },
issueRegistry: {
bindRepoBootstrapKey: (name, key) => calls.bound.push([name, key]),
getForRepo: async (name) => { calls.opened.push(name); return { discoveryKey: 'dk:' + name } }
}
}
return { deps, calls }
}
test('mounts exactly the repos in resourceKeys (scoped), binding + opening + materializing each', async (t) => {
const org = {
name: 'alpha',
resources: ['r1', 'r2', 'r3'],
resourceKeys: { r1: 'k1'.padEnd(64, '1'), r2: 'k2'.padEnd(64, '2') } // r3 has NO key
}
const { deps, calls } = mockDeps(org)
const mounted = await mountOrgGroupedRepos('alpha', deps)
t.alike([...mounted].sort(), ['r1', 'r2'], 'mounted exactly the keyed repos (r3 skipped)')
t.alike(calls.bound.map(b => b[0]).sort(), ['r1', 'r2'], 'bound r1 + r2 bootstrap keys')
t.alike(calls.opened.sort(), ['r1', 'r2'], 'opened r1 + r2 trackers')
t.alike(calls.activated.sort(), ['dk:r1', 'dk:r2'], 'rendezvous on each repo room topic')
t.alike(calls.ensured.sort(), ['r1', 'r2'], 'materialization kicked off for each')
t.absent(calls.bound.find(b => b[0] === 'r3'), 'name-only r3 never bound (no key)')
})
test('idempotent: a second sweep with the same mounted set does nothing', async (t) => {
const org = { name: 'alpha', resources: ['r1'], resourceKeys: { r1: 'k1'.padEnd(64, '1') } }
const { deps, calls } = mockDeps(org)
const mounted = new Set()
await mountOrgGroupedRepos('alpha', { ...deps, mounted })
await mountOrgGroupedRepos('alpha', { ...deps, mounted })
t.is(calls.opened.length, 1, 'r1 opened only once across two sweeps')
})
test('no resourceKeys / missing org → no-op, returns empty', async (t) => {
const { deps: d1 } = mockDeps({ name: 'x', resources: [] }) // no resourceKeys field (legacy)
t.is((await mountOrgGroupedRepos('x', d1)).size, 0, 'legacy record (no resourceKeys) → nothing mounted')
const { deps: d2 } = mockDeps(null) // org not replicated yet
t.is((await mountOrgGroupedRepos('x', d2)).size, 0, 'missing org → nothing mounted')
})
test('one repo failing does not abort the others', async (t) => {
const org = { name: 'alpha', resources: ['r1', 'r2'], resourceKeys: { r1: 'k1'.padEnd(64, '1'), r2: 'k2'.padEnd(64, '2') } }
const { deps, calls } = mockDeps(org)
const errors = []
deps.issueRegistry.getForRepo = async (name) => {
if (name === 'r1') throw new Error('boom')
calls.opened.push(name)
return { discoveryKey: 'dk:' + name }
}
const mounted = await mountOrgGroupedRepos('alpha', { ...deps, onError: (n, e) => errors.push([n, e.message]) })
t.alike([...mounted], ['r2'], 'r2 still mounted despite r1 throwing')
t.alike(errors, [['r1', 'boom']], 'r1 error surfaced to onError')
})