mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-21 22:46:32 +00:00
refactor(plugins): async DB-touching methods; transactions through UnitOfWork
This commit is contained in:
@@ -260,7 +260,7 @@ describe('PluginRuntimeService (M2 end-to-end)', () => {
|
||||
testDb.prepare("INSERT INTO plugins (id, status, enabled, granted_permissions, config) VALUES ('booter','error',1,'[]','{}')").run();
|
||||
|
||||
const rt = await createPluginRuntime(new DatabaseService(dbConn));
|
||||
rt.onApplicationBootstrap(); // fire-and-forget spawn
|
||||
await rt.onApplicationBootstrap(); // fire-and-forget spawn
|
||||
for (let i = 0; i < 40 && !rt.isActive('booter'); i++) await new Promise((r) => setTimeout(r, 50));
|
||||
expect(rt.isActive('booter')).toBe(true);
|
||||
await rt.deactivate('booter');
|
||||
@@ -272,7 +272,7 @@ describe('PluginRuntimeService (M2 end-to-end)', () => {
|
||||
testDb.prepare("INSERT INTO plugins (id, status, enabled, granted_permissions, config) VALUES ('sleeper','inactive',0,'[]','{}')").run();
|
||||
|
||||
const rt = await createPluginRuntime(new DatabaseService(dbConn));
|
||||
rt.onApplicationBootstrap();
|
||||
await rt.onApplicationBootstrap();
|
||||
await new Promise((r) => setTimeout(r, 300));
|
||||
expect(rt.isActive('sleeper')).toBe(false);
|
||||
});
|
||||
@@ -280,8 +280,8 @@ describe('PluginRuntimeService (M2 end-to-end)', () => {
|
||||
it('outboundHostsOf extracts declared http:outbound hosts', async () => {
|
||||
testDb.prepare("INSERT INTO plugins (id, status, granted_permissions, config) VALUES ('net','inactive','[\"db:own\",\"http:outbound:api.x.com\",\"http:outbound:*.y.com\"]','{}')").run();
|
||||
const rt = await createPluginRuntime(new DatabaseService(dbConn));
|
||||
expect(rt.outboundHostsOf('net')).toEqual(['api.x.com', '*.y.com']);
|
||||
expect(rt.outboundHostsOf('missing')).toEqual([]);
|
||||
expect(await rt.outboundHostsOf('net')).toEqual(['api.x.com', '*.y.com']);
|
||||
expect(await rt.outboundHostsOf('missing')).toEqual([]);
|
||||
});
|
||||
|
||||
it('uninstall removes the code, DB rows, settings and (with deleteData) data', async () => {
|
||||
@@ -525,9 +525,9 @@ describe('PluginRuntimeService inter-plugin (exports + events)', () => {
|
||||
await expect(runtime.callPlugin('consumer', 'lib', 'nope', {}, 7)).rejects.toThrow(/does not export/);
|
||||
});
|
||||
|
||||
it('emitPluginEvent validates the declared event and fans out without throwing', () => {
|
||||
expect(() => runtime.emitPluginEvent('lib', 'ping', { x: 1 })).not.toThrow();
|
||||
expect(() => runtime.emitPluginEvent('lib', 'not-declared', {})).toThrow(/does not declare event/);
|
||||
it('emitPluginEvent validates the declared event and fans out without throwing', async () => {
|
||||
await expect(runtime.emitPluginEvent('lib', 'ping', { x: 1 })).resolves.toBeUndefined();
|
||||
await expect(runtime.emitPluginEvent('lib', 'not-declared', {})).rejects.toThrow(/does not declare event/);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -431,13 +431,13 @@ describe('PluginRegistryService', () => {
|
||||
});
|
||||
|
||||
// ── Sideload (upload your own plugin) ────────────────────────────────────────
|
||||
it('sideload: stage + commit installs an uploaded plugin INACTIVE as local:upload', () => {
|
||||
it('sideload: stage + commit installs an uploaded plugin INACTIVE as local:upload', async () => {
|
||||
const zip = makeArtifact({ id: 'my-upload', name: 'Uploaded', version: '2.0.0', type: 'widget', permissions: ['db:own'] });
|
||||
const staged = svc.stageUpload(zip);
|
||||
expect(staged.id).toBe('my-upload');
|
||||
expect(staged.version).toBe('2.0.0');
|
||||
|
||||
svc.commitUpload(staged);
|
||||
await svc.commitUpload(staged);
|
||||
|
||||
const row = testDb.prepare('SELECT status, source_repo, reviewed_at, version FROM plugins WHERE id = ?').get('my-upload') as
|
||||
{ status: string; source_repo: string | null; reviewed_at: string | null; version: string } | undefined;
|
||||
@@ -458,11 +458,11 @@ describe('PluginRegistryService', () => {
|
||||
expect(() => svc.stageUpload(empty)).toThrow(/trek-plugin\.json/);
|
||||
});
|
||||
|
||||
it('sideload: forces INACTIVE even when replacing a plugin that was active', () => {
|
||||
it('sideload: forces INACTIVE even when replacing a plugin that was active', async () => {
|
||||
const zip = () => makeArtifact({ id: 'my-upload', name: 'Uploaded', version: '2.0.0', type: 'widget', permissions: ['db:own'] });
|
||||
svc.commitUpload(svc.stageUpload(zip())); // first install
|
||||
await svc.commitUpload(svc.stageUpload(zip())); // first install
|
||||
testDb.prepare("UPDATE plugins SET status = 'active', enabled = 1 WHERE id = 'my-upload'").run(); // admin activated it
|
||||
svc.commitUpload(svc.stageUpload(zip())); // re-upload replaces the code
|
||||
await svc.commitUpload(svc.stageUpload(zip())); // re-upload replaces the code
|
||||
const row = testDb.prepare('SELECT status, enabled FROM plugins WHERE id = ?').get('my-upload') as { status: string; enabled: number };
|
||||
expect(row.status).toBe('inactive'); // discoverPlugins keeps the old status; commitUpload floors it back to inactive
|
||||
expect(row.enabled).toBe(0);
|
||||
@@ -1076,7 +1076,7 @@ describe('an update block does not outlive the registry relationship', () => {
|
||||
|
||||
// The admin now uploads the plugin by hand.
|
||||
const upload = makeArtifact({ id: 'flight-tracker', name: 'Flight', version: '9.9.9', type: 'widget', permissions: ['db:own'] });
|
||||
svc.commitUpload(svc.stageUpload(upload));
|
||||
await svc.commitUpload(svc.stageUpload(upload));
|
||||
|
||||
const row = testDb.prepare("SELECT source_repo, author_pubkey, update_block_code, update_block_version FROM plugins WHERE id='flight-tracker'").get() as Record<string, unknown>;
|
||||
expect(row.source_repo).toBe('local:upload');
|
||||
|
||||
@@ -43,7 +43,7 @@ function makeSupervisor(events: Array<{ topic: string; data: unknown }>, tuning:
|
||||
const deps: HostDeps = {
|
||||
data: new PluginDataDb(id),
|
||||
callPlugin: async () => undefined,
|
||||
emitPluginEvent: (event, payload) => broadcasts.push({ id, event, payload }),
|
||||
emitPluginEvent: async (event, payload) => { broadcasts.push({ id, event, payload }); },
|
||||
};
|
||||
// Only db.* is exercised from a child here; the rest of the surface has its own
|
||||
// unit suites and would drag every domain service into this integration test.
|
||||
|
||||
Reference in New Issue
Block a user