/** * The registry-poll capability gate (celilo#1361): a consumer upgrade whose * required capability no deployed provider serves must be DEFERRED before any * state changes, not deployed into a provider that rejects its calls. * * celilo-website burned six release revisions (+1 through +6) on exactly * this: every poll attempt updated the stored version, failed in the publish * hook ("sourceDir is required" against an old caddy), recorded the new * version beside the old VERIFIED state, and re-triggered on the next poll. */ import { describe, expect, test } from 'bun:test'; import { type DeployedCapabilityProvider, unservedCapabilityRequirements, } from './capability-compat'; function provider( capabilityName: string, moduleId: string, version: string, ): DeployedCapabilityProvider { return { capabilityName, moduleId, version }; } describe('unservedCapabilityRequirements', () => { test('a requirement any deployed provider serves is not a blocker', () => { const providers = [provider('public_web', 'caddy', '4.0.0')]; expect( unservedCapabilityRequirements([{ name: 'public_web', version: '4.0.0' }], providers), ).toEqual([]); }); test('a major the deployed provider has not reached is a blocker, naming it', () => { const providers = [provider('public_web', 'caddy', '3.1.0')]; const result = unservedCapabilityRequirements( [{ name: 'public_web', version: '4.0.0' }], providers, ); expect(result).toHaveLength(1); expect(result[0].providerModuleId).toBe('caddy'); expect(result[0].providerVersion).toBe('3.1.0'); expect(result[0].reason).toBe('major_mismatch_higher'); expect(result[0].message).toContain('public_web@4.0.0'); expect(result[0].message).toContain('caddy'); }); test('no provider at all is a blocker with its own reason', () => { const result = unservedCapabilityRequirements([{ name: 'public_web', version: '4.0.0' }], []); expect(result).toHaveLength(1); expect(result[0].reason).toBe('no_provider'); expect(result[0].providerModuleId).toBeNull(); }); test('ANY compatible provider serves the requirement (zone-scoped providers)', () => { const providers = [ provider('dns_registrar', 'namecheap', '4.0.0'), provider('dns_registrar', 'bind-internal', '3.0.0'), ]; expect( unservedCapabilityRequirements([{ name: 'dns_registrar', version: '4.0.0' }], providers), ).toEqual([]); }); test('a newer minor than the provider ships is caller_minor_too_old', () => { const providers = [provider('public_web', 'caddy', '4.0.0')]; const result = unservedCapabilityRequirements( [{ name: 'public_web', version: '4.1.0' }], providers, ); expect(result[0]?.reason).toBe('caller_minor_too_old'); }); test('a consumer behind the provider is compatible (framework back-compat)', () => { const providers = [provider('public_web', 'caddy', '4.0.0')]; expect( unservedCapabilityRequirements([{ name: 'public_web', version: '4.0.0' }], providers), ).toEqual([]); }); test('privileged capabilities are skipped (not provider-backed)', () => { expect( unservedCapabilityRequirements([{ name: 'cross_module_read', version: '9.9.9' }], []), ).toEqual([]); }); test('undefined requirements yield no blockers', () => { expect(unservedCapabilityRequirements(undefined, [])).toEqual([]); }); });