Download src/plugins/runtime/gateway-request-scope.test.ts from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 7.45 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/plugins/runtime/gateway-request-scope.test.ts
- Command line
-
hf download hf://SaylorTwift/openclaw/src/plugins/runtime/gateway-request-scope.test.ts
-
curl -L -o gateway-request-scope.test.ts https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/plugins/runtime/gateway-request-scope.test.ts
7.45 kB
| // Gateway request scope tests cover request-local plugin runtime context propagation. | |
| import { afterEach, describe, expect, it, vi } from "vitest"; | |
| import { createPluginMetadataSnapshotFixture } from "../plugin-metadata.test-support.js"; | |
| import { createEmptyPluginRegistry } from "../registry-empty.js"; | |
| import { | |
| requireActivePluginRegistry, | |
| resetPluginRuntimeStateForTest, | |
| setActivePluginRegistry, | |
| } from "../runtime.js"; | |
| import type { PluginRuntimeGatewayRequestScope } from "./gateway-request-scope.test-fixtures.js"; | |
| const TEST_SCOPE: PluginRuntimeGatewayRequestScope = { | |
| context: {} as PluginRuntimeGatewayRequestScope["context"], | |
| isWebchatConnect: (() => false) as PluginRuntimeGatewayRequestScope["isWebchatConnect"], | |
| }; | |
| describe("gateway request scope", () => { | |
| afterEach(() => { | |
| vi.doUnmock("../current-plugin-metadata-snapshot.js"); | |
| vi.resetModules(); | |
| resetPluginRuntimeStateForTest(); | |
| }); | |
| async function importGatewayRequestScopeModule() { | |
| return await import("./gateway-request-scope.js"); | |
| } | |
| async function withTestGatewayScope<T>( | |
| run: (runtimeScope: Awaited<ReturnType<typeof importGatewayRequestScopeModule>>) => Promise<T>, | |
| ) { | |
| const runtimeScope = await importGatewayRequestScopeModule(); | |
| return await runtimeScope.withPluginRuntimeGatewayRequestScope(TEST_SCOPE, async () => { | |
| return await run(runtimeScope); | |
| }); | |
| } | |
| function expectGatewayScope( | |
| runtimeScope: Awaited<ReturnType<typeof importGatewayRequestScopeModule>>, | |
| expected: PluginRuntimeGatewayRequestScope, | |
| ) { | |
| expect(runtimeScope.getPluginRuntimeGatewayRequestScope()).toEqual(expected); | |
| } | |
| async function expectPluginIdScopedGatewayScope(pluginId: string) { | |
| await withPluginIdScope(pluginId, async (runtimeScope) => { | |
| expectGatewayScope(runtimeScope, { | |
| ...TEST_SCOPE, | |
| pluginId, | |
| }); | |
| }); | |
| } | |
| async function withPluginIdScope( | |
| pluginId: string, | |
| run: ( | |
| runtimeScope: Awaited<ReturnType<typeof importGatewayRequestScopeModule>>, | |
| ) => Promise<void>, | |
| ) { | |
| await withTestGatewayScope(async (runtimeScope) => { | |
| await runtimeScope.withPluginRuntimePluginScope({ pluginId }, async () => { | |
| await run(runtimeScope); | |
| }); | |
| }); | |
| } | |
| it("does not import the plugin metadata control plane", async () => { | |
| vi.resetModules(); | |
| vi.doMock("../current-plugin-metadata-snapshot.js", () => { | |
| throw new Error("gateway request scope must remain lightweight"); | |
| }); | |
| const runtimeScope = await importGatewayRequestScopeModule(); | |
| expect(runtimeScope.withPluginRuntimeGatewayRequestScope).toBeTypeOf("function"); | |
| }); | |
| it("reuses AsyncLocalStorage across reloaded module instances", async () => { | |
| const first = await importGatewayRequestScopeModule(); | |
| await first.withPluginRuntimeGatewayRequestScope(TEST_SCOPE, async () => { | |
| vi.resetModules(); | |
| const second = await importGatewayRequestScopeModule(); | |
| expectGatewayScope(second, TEST_SCOPE); | |
| }); | |
| }); | |
| it("preserves host-issued Gateway resolver bindings across reloaded modules", async () => { | |
| const first = await importGatewayRequestScopeModule(); | |
| const owner = {}; | |
| const resolver = vi.fn(() => TEST_SCOPE.context!); | |
| first.bindGatewayContextResolver(owner, resolver); | |
| vi.resetModules(); | |
| const second = await importGatewayRequestScopeModule(); | |
| expect(second.getGatewayContextResolver(owner)).toBe(resolver); | |
| expect(second.getSharedGatewayContextResolver([owner])?.()).toBe(TEST_SCOPE.context); | |
| expect(second.getGatewayContextResolver({})).toBeUndefined(); | |
| second.clearGatewayContextResolver(owner); | |
| expect(first.getGatewayContextResolver(owner)).toBeUndefined(); | |
| }); | |
| it("attaches plugin id to the active scope", async () => { | |
| await expectPluginIdScopedGatewayScope("voice-call"); | |
| }); | |
| it("resolves the owned registry while preserving gateway request facts", async () => { | |
| const activeRegistry = createEmptyPluginRegistry(); | |
| const requestRegistry = createEmptyPluginRegistry(); | |
| setActivePluginRegistry(activeRegistry); | |
| await withTestGatewayScope(async (runtimeScope) => { | |
| await runtimeScope.withPluginRuntimeRegistryScope(requestRegistry, async () => { | |
| expect(requireActivePluginRegistry()).toBe(requestRegistry); | |
| expectGatewayScope(runtimeScope, { ...TEST_SCOPE, pluginRegistry: requestRegistry }); | |
| }); | |
| expect(requireActivePluginRegistry()).toBe(activeRegistry); | |
| }); | |
| }); | |
| it("drops generation ownership for re-admission and restores the caller afterward", async () => { | |
| const generation = await import("./generation-scope.js"); | |
| const registry = createEmptyPluginRegistry(); | |
| const metadataSnapshot = createPluginMetadataSnapshotFixture({ | |
| plugins: [{ id: "fixture", providers: ["fixture-provider"] }], | |
| }); | |
| await withTestGatewayScope(async (runtimeScope) => { | |
| await generation.withPluginRuntimeGenerationScope( | |
| { metadataSnapshot, pluginRegistry: registry }, | |
| async () => { | |
| const original = runtimeScope.getPluginRuntimeGatewayRequestScope(); | |
| expect(original?.declaredProviderOwners).toBe(metadataSnapshot.declaredProviderOwners); | |
| await generation.runOutsidePluginRuntimeGenerationScope(async () => { | |
| await Promise.resolve(); | |
| expect(generation.getPluginRuntimeGenerationRegistry()).toBeUndefined(); | |
| expectGatewayScope(runtimeScope, { | |
| ...TEST_SCOPE, | |
| pluginRegistry: undefined, | |
| declaredProviderOwners: undefined, | |
| }); | |
| }); | |
| expect(runtimeScope.getPluginRuntimeGatewayRequestScope()).toBe(original); | |
| expect(generation.getPluginRuntimeGenerationRegistry()).toBe(registry); | |
| }, | |
| ); | |
| }); | |
| }); | |
| it("isolates combined plugin identities across concurrent registry scopes", async () => { | |
| const runtimeScope = await importGatewayRequestScopeModule(); | |
| const parent = { | |
| ...TEST_SCOPE, | |
| pluginId: "parent", | |
| pluginSource: "parent-source", | |
| pluginOrigin: "bundled" as const, | |
| pluginTrustedOfficialInstall: true, | |
| }; | |
| const registries = [createEmptyPluginRegistry(), createEmptyPluginRegistry()]; | |
| await runtimeScope.withPluginRuntimeGatewayRequestScope(parent, async () => { | |
| await Promise.all( | |
| registries.map((registry, index) => | |
| runtimeScope.withPluginRuntimePluginScope( | |
| { pluginId: `child-${index}` }, | |
| async () => { | |
| await Promise.resolve(); | |
| const scoped = runtimeScope.getPluginRuntimeGatewayRequestScope()!; | |
| expect(scoped).toEqual({ | |
| ...TEST_SCOPE, | |
| pluginId: `child-${index}`, | |
| pluginRegistry: registry, | |
| declaredProviderOwners: undefined, | |
| }); | |
| expect(Object.hasOwn(scoped, "pluginSource")).toBe(false); | |
| expect(Object.hasOwn(scoped, "pluginOrigin")).toBe(false); | |
| expect(Object.hasOwn(scoped, "pluginTrustedOfficialInstall")).toBe(false); | |
| scoped.pluginSource = "child-only"; | |
| expect(parent.pluginSource).toBe("parent-source"); | |
| expect(requireActivePluginRegistry()).toBe(registry); | |
| }, | |
| registry, | |
| ), | |
| ), | |
| ); | |
| expectGatewayScope(runtimeScope, parent); | |
| }); | |
| }); | |
| }); | |