Changes
4 changed files (+355/-0)
-
-
@@ -0,0 +1,56 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only import { expect } from "bun:test"; import { create, fromBinary, toBinary, type MessageShape, type MessageInitShape, } from "@bufbuild/protobuf"; import { CreateRequestSchema } from "@yamori/proto/yamori/worker/v1/create_request_pb.js"; import { CreateResponseSchema } from "@yamori/proto/yamori/worker/v1/create_response_pb.js"; import { WorkerSchema } from "@yamori/proto/yamori/worker/v1/worker_pb.js"; import { WorkspaceSchema } from "@yamori/proto/yamori/workspace/v1/workspace_pb.js"; import { type Context } from "../../../../types"; import { workerService } from "./service"; export async function createWorker( ctx: Context, workspace: MessageInitShape<typeof WorkspaceSchema>, payload: MessageInitShape<typeof CreateRequestSchema> = { workspaceId: workspace.id, workerAddKey: workspace.workerAddKey, displayName: "Bar", }, ): Promise<MessageShape<typeof WorkerSchema>> { const resp = fromBinary( CreateResponseSchema, await workerService( { service: "yamori.worker.v1.WorkerService", method: "Create", data: toBinary(CreateRequestSchema, create(CreateRequestSchema, payload)), }, ctx, ), ); if (resp.result.case !== "ok") { expect.unreachable( `Expected "ok" for worker creation, got ${JSON.stringify(resp.result.case)}`, ); } if (!resp.result.value.worker) { expect.unreachable( `Expected Create method to return a created worker, got empty value`, ); } return resp.result.value.worker; }
-
-
-
@@ -0,0 +1,184 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only import "fake-indexeddb/auto"; import { beforeEach, expect, test } from "bun:test"; import { create, fromBinary, toBinary, type MessageInitShape, type MessageShape, } from "@bufbuild/protobuf"; import { GetRequestSchema } from "@yamori/proto/yamori/worker/v1/get_request_pb.js"; import { GetResponseSchema } from "@yamori/proto/yamori/worker/v1/get_response_pb.js"; import { WorkerSchema } from "@yamori/proto/yamori/worker/v1/worker_pb.js"; import { idbBackend } from "../../../../lib"; import { CONTEXT } from "../../../../symbols"; import { type Context } from "../../../../types"; import { createWorkspace } from "../../../workspace/v1/workspace_service/_test_utils"; import { createWorker } from "./_test_utils"; import { workerService } from "./service"; beforeEach(() => { indexedDB = new IDBFactory(); }); async function getWorker( ctx: Context, request: MessageInitShape<typeof GetRequestSchema>, ): Promise<MessageShape<typeof GetResponseSchema>> { return fromBinary( GetResponseSchema, await workerService( { service: "yamori.worker.v1.WorkerService", method: "Get", data: toBinary(GetRequestSchema, create(GetRequestSchema, request)), }, ctx, ), ); } test("Should return missing_field if workspace_id is missing", async () => { const { [CONTEXT]: ctx } = await idbBackend(); const workspace = await createWorkspace(ctx); const worker = await createWorker(ctx, workspace); const resp = await getWorker(ctx, { workerId: worker.id, }); if (resp.result.case !== "missingField") { expect.unreachable( `Expected "missing_field", got ${JSON.stringify(resp.result.case)}`, ); } expect(resp.result.value.path).toBe("workspace_id"); }); test("Should return missing_field if worker_id is missing", async () => { const { [CONTEXT]: ctx } = await idbBackend(); const workspace = await createWorkspace(ctx); await createWorker(ctx, workspace); const resp = await getWorker(ctx, { workspaceId: workspace.id, }); if (resp.result.case !== "missingField") { expect.unreachable( `Expected "missing_field", got ${JSON.stringify(resp.result.case)}`, ); } expect(resp.result.value.path).toBe("worker_id"); }); test("Should return not_found if workspace does not exist", async () => { const { [CONTEXT]: ctx } = await idbBackend(); const workspace = await createWorkspace(ctx); const worker = await createWorker(ctx, workspace); const resp = await getWorker(ctx, { workspaceId: { value: workspace.id?.value + "-000", }, workerId: worker.id, }); if (resp.result.case !== "notFound") { expect.unreachable(`Expected "notFound", got ${JSON.stringify(resp.result.case)}`); } expect(resp.result.value.typeName).toBe("yamori.workspace.v1.Workspace"); }); test("Should return not_found if worker does not exist", async () => { const { [CONTEXT]: ctx } = await idbBackend(); const workspace = await createWorkspace(ctx); const worker = await createWorker(ctx, workspace); const resp = await getWorker(ctx, { workspaceId: workspace.id, workerId: { value: worker.id?.value + "-000", }, }); if (resp.result.case !== "notFound") { expect.unreachable(`Expected "notFound", got ${JSON.stringify(resp.result.case)}`); } expect(resp.result.value.typeName).toBe("yamori.worker.v1.Worker"); }); test("Should return not_found for workers from another workspace", async () => { const { [CONTEXT]: ctx } = await idbBackend(); const foo = await createWorkspace(ctx); const bar = await createWorkspace(ctx); const worker = await createWorker(ctx, foo); const resp = await getWorker(ctx, { workspaceId: bar.id, workerId: worker.id, }); if (resp.result.case !== "notFound") { expect.unreachable(`Expected "notFound", got ${JSON.stringify(resp.result.case)}`); } expect(resp.result.value.typeName).toBe("yamori.worker.v1.Worker"); }); test("Should return worker", async () => { const { [CONTEXT]: ctx } = await idbBackend(); const workspace = await createWorkspace(ctx); const worker = await createWorker(ctx, workspace); const resp = await getWorker(ctx, { workspaceId: workspace.id, workerId: worker.id, }); if (resp.result.case !== "ok") { expect.unreachable(`Expected "ok", got ${JSON.stringify(resp.result.case)}`); } expect(resp.result.value.id).toEqual(worker.id!); expect(resp.result.value.displayName).toEqual(worker.displayName); }); test("Should mask fields", async () => { const { [CONTEXT]: ctx } = await idbBackend(); const workspace = await createWorkspace(ctx); const worker = await createWorker(ctx, workspace); const resp = await getWorker(ctx, { workspaceId: workspace.id, workerId: worker.id, readMask: { fields: [WorkerSchema.field.displayName.number], }, }); if (resp.result.case !== "ok") { expect.unreachable(`Expected "ok", got ${JSON.stringify(resp.result.case)}`); } expect(resp.result.value.id).toBeEmpty(); expect(resp.result.value.displayName).toEqual(worker.displayName); });
-
-
-
@@ -0,0 +1,112 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // SPDX-License-Identifier: AGPL-3.0-only import { create, fromBinary, toBinary, type MessageInitShape, type MessageShape, } from "@bufbuild/protobuf"; import { GetRequestSchema } from "@yamori/proto/yamori/worker/v1/get_request_pb.js"; import { GetResponseSchema } from "@yamori/proto/yamori/worker/v1/get_response_pb.js"; import { type Context, type YamoriDB } from "../../../../types"; import * as worker from "../worker"; function respond( result: Exclude< NonNullable<MessageInitShape<typeof GetResponseSchema>["result"]>, { case: undefined } >, ): Uint8Array { return toBinary(GetResponseSchema, create(GetResponseSchema, { result })); } export async function get(data: Uint8Array, { db }: Context): Promise<Uint8Array> { let req: MessageShape<typeof GetRequestSchema>; try { req = fromBinary(GetRequestSchema, data); } catch (error) { return respond({ case: "systemError", value: { code: "INVALID_MESSAGE", message: import.meta.env.NODE_ENV === "production" ? "Failed to parse request message" : `Request message does not conform schema: ${error}`, }, }); } if (!req.workspaceId) { return respond({ case: "missingField", value: { path: "workspace_id", }, }); } if (!req.workerId) { return respond({ case: "missingField", value: { path: "worker_id", }, }); } let workspace: YamoriDB["workspaces"]["value"] | undefined; try { workspace = await db.get("workspaces", req.workspaceId.value); if (!workspace) { return respond({ case: "notFound", value: { typeName: "yamori.workspace.v1.Workspace", }, }); } } catch (error) { return respond({ case: "systemError", value: { code: "IDB_ERROR", message: import.meta.env.NODE_ENV === "production" ? "An error occurred during workspace lookup" : `Exception thrown during workspace lookup: ${error}`, }, }); } try { const found = await db.get("workers", req.workerId.value); if (!found || found.workspaceId !== req.workspaceId.value) { return respond({ case: "notFound", value: { typeName: "yamori.worker.v1.Worker", }, }); } return respond({ case: "ok", value: worker.mask(req.readMask, worker.fromDBEntry(found)), }); } catch (error) { return respond({ case: "systemError", value: { code: "IDB_ERROR", message: import.meta.env.NODE_ENV === "production" ? "An error occurred during worker lookup" : `Exception thrown during worker lookup: ${error}`, }, }); } }
-
-
-
@@ -4,6 +4,7 @@import { type Context, type RPCMessage } from "../../../../types"; import { create } from "./create"; import { get } from "./get"; import { list } from "./list"; export async function workerService(
-
@@ -15,6 +16,8 @@ case "Create":return create(request.data, ctx); case "List": return list(request.data, ctx); case "Get": return get(request.data, ctx); default: throw new Error(`Unknown method "${request.method}" for ${request.service}`); }
-