mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
9b3d37ea29
Wires the registry into the host and takes the first domain across, so the kit lands with a worked example rather than as scaffolding nobody uses yet. The registry is an additive, optional fourth constructor parameter on PluginRpcHost, so all 107 existing construction sites keep compiling untouched; that is what makes the rest of the rollout a per-domain move instead of a big-bang one. bindInto runs LAST in the constructor, so a method still owned by one of the has() blocks collides loudly instead of being silently overridden. tags is the right pilot: four methods, a service that is already DI-native, and it exercises the read/write permission split, the userless refusal and a BadParams write. Handler bodies and messages are verbatim; only deps.foo(...) became this.tags... and uid became ctx.actingUserId. dispatch now strips the supervisor's _inv marker. The supervisor resolves the acting user from it before dispatch and then passes the request on untouched, so it has been visible to every handler and is in effect a reserved param name. Nothing reads it: auditResource takes named fields only, and the one handler that touches the params object as a whole (packing.setBagMembers) reads a named field off it. Dropping it keeps a future strict parse from rejecting calls every shipped plugin makes. Two tests carry the rollout from here. rpc-coverage.test.ts derives both owner sets from the code and proves they partition the method vocabulary exactly, so a PR that moves a method and forgets to delete the legacy registration fails in CI. And because a decorated class that no module registers is invisible to discovery, with every call to it coming back PERMISSION_DENIED and no other symptom, tags.rpc.test.ts asserts TagsRpc is actually listed in providers.
65 lines
3.1 KiB
TypeScript
65 lines
3.1 KiB
TypeScript
/**
|
|
* The coverage ledger: the anchor for the whole decorator rollout.
|
|
*
|
|
* Every wire method is owned exactly once, either by the legacy router blocks in
|
|
* rpc-host.ts or by a decorated *.rpc.ts class in the registry. Both sets are derived
|
|
* by construction, so no list is maintained by hand and the test cannot drift.
|
|
*
|
|
* It fails the moment a migration PR moves a method and forgets to delete the legacy
|
|
* registration, deletes one without adding it, or forgets to list a new *.rpc.ts class
|
|
* in allRpcControllers().
|
|
*/
|
|
import { describe, it, expect } from 'vitest';
|
|
import { PluginRpcHost } from '../../../src/nest/plugins/host/rpc-host';
|
|
import { createTestPluginRegistry } from '../../../src/nest/plugins/host/rpc-kit/testing';
|
|
import {
|
|
KNOWN_METHODS,
|
|
KNOWN_PERMISSIONS,
|
|
UNCONDITIONAL_METHODS,
|
|
} from '../../../src/nest/plugins/protocol/envelope';
|
|
import { allRpcControllers, makeDeps } from '../../helpers/rpc-host-deps';
|
|
|
|
/** Reads the router's private dispatch map. That map IS the thing under test. */
|
|
const boundMethods = (host: PluginRpcHost): Set<string> =>
|
|
new Set((host as unknown as { methods: Map<string, unknown> }).methods.keys());
|
|
|
|
describe('plugin RPC coverage ledger', () => {
|
|
const registry = createTestPluginRegistry(allRpcControllers());
|
|
// Every permission granted, so the router registers everything it can.
|
|
const host = new PluginRpcHost('probe', new Set<string>(KNOWN_PERMISSIONS), makeDeps(), registry);
|
|
const all = boundMethods(host);
|
|
const fromRegistry = registry.methodNames();
|
|
const legacy = new Set([...all].filter((m) => !fromRegistry.has(m)));
|
|
|
|
it('RPCLEDGER-001 no method is owned by both the registry and the legacy router', () => {
|
|
expect([...fromRegistry].filter((m) => legacy.has(m))).toEqual([]);
|
|
});
|
|
|
|
it('RPCLEDGER-002 every registered method is one the wire protocol knows', () => {
|
|
const vocabulary = new Set<string>([...KNOWN_METHODS, ...UNCONDITIONAL_METHODS]);
|
|
expect([...all].filter((m) => !vocabulary.has(m))).toEqual([]);
|
|
});
|
|
|
|
it('RPCLEDGER-003 no method in the vocabulary is orphaned', () => {
|
|
const vocabulary = new Set<string>([...KNOWN_METHODS, ...UNCONDITIONAL_METHODS]);
|
|
expect([...vocabulary].filter((m) => !all.has(m))).toEqual([]);
|
|
});
|
|
|
|
it('RPCLEDGER-004 the two owner sets partition the vocabulary exactly', () => {
|
|
expect(all).toEqual(new Set<string>([...KNOWN_METHODS, ...UNCONDITIONAL_METHODS]));
|
|
expect(fromRegistry.size + legacy.size).toBe(all.size);
|
|
});
|
|
|
|
it('RPCLEDGER-005 the migration ledger reads as expected for this PR', () => {
|
|
// Update these two numbers in every rollout PR. They make the diff state the size
|
|
// of the move out loud, which is the number a reviewer wants to see.
|
|
const total = KNOWN_METHODS.length + UNCONDITIONAL_METHODS.length;
|
|
expect(fromRegistry.size).toBe(4); // tags.list / create / update / delete
|
|
expect(legacy.size).toBe(total - 4);
|
|
});
|
|
|
|
it('RPCLEDGER-006 the migrated methods are exactly the ones this PR claims', () => {
|
|
expect([...fromRegistry].sort()).toEqual(['tags.create', 'tags.delete', 'tags.list', 'tags.update']);
|
|
});
|
|
});
|