340 lines · 9.6 KB · TypeScript
RawDownload
import {  createServer,} from "node:http";import type {  AddressInfo,} from "node:net";import {  FileSystem,} from "@effect/platform";import {  NodeFileSystem,} from "@effect/platform-node";import {  describe,  expect,  it,} from "@effect/vitest";import * as Effect from "effect/Effect"; import {  createLocalExecutorEffect,} from "@executor/platform-sdk-file/effect";import {  ExecutionIdSchema,} from "../../schema";import {  RuntimeExecutionResolverService,} from "../execution/scope/environment";import {  openApiSdkPlugin,} from "../../../../../../plugins/openapi/sdk";import {  localSecretStoreSdkPlugin,} from "../../../../../../plugins/local-secret-store/sdk"; const staticOpenApiDocument = JSON.stringify({  openapi: "3.1.0",  info: {    title: "Demo API",    version: "1.0.0",  },  servers: [    {      url: "https://api.example.test",    },  ],  paths: {    "/widgets": {      get: {        operationId: "listWidgets",        responses: {          "200": {            description: "ok",          },        },      },    },  },}); const startStaticSpecServer = async () => {  let lastAuthorizationHeader: string | null = null;  const server = createServer((request, response) => {    if (request.url === "/openapi.json") {      response.writeHead(200, {        "content-type": "application/json; charset=utf-8",      });      response.end(staticOpenApiDocument);      return;    }     if (request.url === "/widgets") {      lastAuthorizationHeader = request.headers.authorization ?? null;      response.writeHead(200, {        "content-type": "application/json; charset=utf-8",      });      response.end(JSON.stringify([{ id: "widget_1" }]));      return;    }     {      response.writeHead(404);      response.end("Not Found");    }  });   await new Promise<void>((resolve, reject) => {    server.once("error", reject);    server.listen(0, "127.0.0.1", () => {      server.off("error", reject);      resolve();    });  });   const address = server.address();  if (!address || typeof address === "string") {    server.close();    throw new Error("Failed to determine OpenAPI test server address.");  }   return {    baseUrl: `http://127.0.0.1:${(address as AddressInfo).port}`,    specUrl: `http://127.0.0.1:${(address as AddressInfo).port}/openapi.json`,    lastAuthorizationHeader: () => lastAuthorizationHeader,    close: () =>      new Promise<void>((resolve, reject) => {        server.close((error) => {          if (error) {            reject(error);            return;          }           resolve();        });      }),  };}; const resolveExecutionEnvironment = (executor: {  scopeId: string;  actorScopeId: string;  runtime: {    runtimeLayer: any;  };}) =>  Effect.gen(function* () {    const resolver = yield* RuntimeExecutionResolverService;    return yield* resolver({      scopeId: executor.scopeId,      actorScopeId: executor.actorScopeId,      executionId: ExecutionIdSchema.make("exec_executor_tools_test"),    });  }).pipe(Effect.provide(executor.runtime.runtimeLayer)); describe("executor internal tools", () => {  it.scoped("registers plugin-owned executor.openapi tools and delegates generic remove through them", () =>    Effect.gen(function* () {      const fs = yield* FileSystem.FileSystem;      const workspaceRoot = yield* fs.makeTempDirectory({        prefix: "executor-internal-tools-",      });      const stored = new Map<string, Record<string, unknown>>();      const specServer = yield* Effect.acquireRelease(        Effect.tryPromise({          try: () => startStaticSpecServer(),          catch: (cause) =>            cause instanceof Error ? cause : new Error(String(cause)),        }),        (server) =>          Effect.promise(() => server.close()).pipe(Effect.orDie),      );      const executor = yield* Effect.acquireRelease(        createLocalExecutorEffect({          localDataDir: ":memory:",          workspaceRoot,          plugins: [            openApiSdkPlugin({              storage: {                get: ({ sourceId }) =>                  Effect.succeed((stored.get(sourceId) as any) ?? null),                put: ({ sourceId, value }) =>                  Effect.sync(() => {                    stored.set(sourceId, value as any);                  }),                remove: ({ sourceId }) =>                  Effect.sync(() => {                    stored.delete(sourceId);                  }),              },            }),          ] as const,        }),        (openedExecutor) =>          Effect.promise(() => openedExecutor.close()).pipe(            Effect.orDie,            Effect.zipRight(              fs.remove(workspaceRoot, {                recursive: true,                force: true,              }),            ),          ),      );       const environment = yield* resolveExecutionEnvironment(executor);      expect(environment.catalog).toBeDefined();       const createTool = yield* environment.catalog!.getToolByPath({        path: "executor.openapi.createSource",        includeSchemas: false,      });      const previewTool = yield* environment.catalog!.getToolByPath({        path: "executor.openapi.previewDocument",        includeSchemas: false,      });       expect(createTool?.path).toBe("executor.openapi.createSource");      expect(previewTool?.path).toBe("executor.openapi.previewDocument");       const preview = yield* environment.toolInvoker.invoke({        path: "executor.openapi.previewDocument",        args: {          specUrl: specServer.specUrl,        },      });      expect(preview).toMatchObject({        title: "Demo API",        operationCount: 1,      });       const created = yield* environment.toolInvoker.invoke({        path: "executor.openapi.createSource",        args: {          name: "Demo API",          specUrl: specServer.specUrl,          baseUrl: null,          auth: {            kind: "none",          },        },      });       expect((created as { kind: string }).kind).toBe("openapi");      expect(stored.has((created as { id: string }).id)).toBe(true);       const removed = yield* environment.toolInvoker.invoke({        path: "executor.sources.remove",        args: {          sourceId: (created as { id: string }).id,        },      });       expect(removed).toEqual({        removed: true,      });      expect(stored.has((created as { id: string }).id)).toBe(false);    }).pipe(Effect.provide(NodeFileSystem.layer)),  );   it.scoped("invokes persisted OpenAPI source tools outside the runtime layer", () =>    Effect.gen(function* () {      const fs = yield* FileSystem.FileSystem;      const workspaceRoot = yield* fs.makeTempDirectory({        prefix: "executor-openapi-source-tools-",      });      const stored = new Map<string, Record<string, unknown>>();      const specServer = yield* Effect.acquireRelease(        Effect.tryPromise({          try: () => startStaticSpecServer(),          catch: (cause) =>            cause instanceof Error ? cause : new Error(String(cause)),        }),        (server) =>          Effect.promise(() => server.close()).pipe(Effect.orDie),      );      const executor = yield* Effect.acquireRelease(        createLocalExecutorEffect({          localDataDir: ":memory:",          workspaceRoot,          plugins: [            localSecretStoreSdkPlugin,            openApiSdkPlugin({              storage: {                get: ({ sourceId }) =>                  Effect.succeed((stored.get(sourceId) as any) ?? null),                put: ({ sourceId, value }) =>                  Effect.sync(() => {                    stored.set(sourceId, value as any);                  }),                remove: ({ sourceId }) =>                  Effect.sync(() => {                    stored.delete(sourceId);                  }),              },            }),          ] as const,        }),        (openedExecutor) =>          Effect.promise(() => openedExecutor.close()).pipe(            Effect.orDie,            Effect.zipRight(              fs.remove(workspaceRoot, {                recursive: true,                force: true,              }),            ),          ),      );       const tokenRef = yield* executor.secrets.create({        name: "OpenAPI Token",        purpose: "auth_material",        value: "token-from-secret-store",      }).pipe(Effect.map((secret) => ({ secretId: secret.id })));      const environment = yield* resolveExecutionEnvironment(executor);       const created = yield* environment.toolInvoker.invoke({        path: "executor.openapi.createSource",        args: {          name: "Demo API",          specUrl: specServer.specUrl,          baseUrl: specServer.baseUrl,          auth: {            kind: "bearer",            tokenSecretRef: tokenRef,            headerName: null,            prefix: null,          },        },      });       expect((created as { kind: string }).kind).toBe("openapi");       const response = yield* environment.toolInvoker.invoke({        path: "demo-api.widgets.listWidgets",        args: {},      });       expect(response).toMatchObject({        data: [{ id: "widget_1" }],        error: null,        status: 200,      });      expect(specServer.lastAuthorizationHeader()).toBe("Bearer token-from-secret-store");       const executed = yield* environment.executor.execute(        'return await tools["demo-api.widgets.listWidgets"]({ limit: 100 });',        environment.toolInvoker,      );       expect(executed).toMatchObject({        result: {          data: [{ id: "widget_1" }],          error: null,          status: 200,        },      });    }).pipe(Effect.provide(NodeFileSystem.layer)),  );});

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t