Skip to content

Commit

Permalink
working tests!
Browse files Browse the repository at this point in the history
  • Loading branch information
sprutton1 committed Dec 23, 2024
1 parent 7d0ba7b commit 85f6c59
Show file tree
Hide file tree
Showing 25 changed files with 261 additions and 262 deletions.
6 changes: 5 additions & 1 deletion bin/lang-js/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ deno_compile(
name = "bin",
main = "src/index.ts",
out = "lang-js",
srcs = glob([
"src/**/*.ts",
"src/**/*.js",
]),
permissions = [
"allow-all",
],
Expand All @@ -59,7 +63,7 @@ deno_format(
)

deno_test(
name = "test",
name = "test-unit",
srcs = glob(["**/*_test.ts", "**/*.test.ts"]),
ignore = ["node_modules"],
)
Expand Down
7 changes: 3 additions & 4 deletions bin/lang-js/src/debug.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import process from "node:process";

export type Debugger = (msg: any) => void;
export type Debugger = (msg: unknown) => void;

export function Debug(namespace: string): Debugger {
const debugActive = process.env.SI_LANG_JS_LOG || process.env.SI_LOG;
return (msg: any) => {
return (msg: unknown) => {
if (debugActive) {
try {
const safeStringify = (obj: any): string => {
const safeStringify = (obj: unknown): string => {
const seen = new WeakSet();
return JSON.stringify(obj, (_, value) => {
// Handle functions
Expand Down Expand Up @@ -41,7 +41,6 @@ export function Debug(namespace: string): Debugger {
process.stderr.write(`${namespace} ${line}\n`);
}
} catch {
// Fallback if stringify fails completely
process.stderr.write(
`${namespace} [Debug Error: Unable to stringify message]\n`,
);
Expand Down
42 changes: 9 additions & 33 deletions bin/lang-js/src/function.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as _ from "lodash-es";
import process from "node:process";
import { base64Decode } from "./base64.ts";
import { ctxFromRequest, Request, RequestCtx } from "./request.ts";
import joi_validation, {
Expand All @@ -15,10 +14,10 @@ import schema_variant_definition, {
import management_run, { ManagementFunc } from "./function_kinds/management.ts";
import action_run, { ActionRunFunc } from "./function_kinds/action_run.ts";
import before from "./function_kinds/before.ts";
import { rawStorage, rawStorageRequest } from "./sandbox/requestStorage.ts";
import { Debug, Debugger } from "./debug.ts";
import { rawStorage } from "./sandbox/requestStorage.ts";
import { Debugger } from "./debug.ts";
import { transpile } from "jsr:@deno/emit";
import * as w from "./worker.js";
import * as _worker from "./worker.js";

export enum FunctionKind {
ActionRun = "actionRun",
Expand All @@ -36,7 +35,6 @@ export function functionKinds(): Array<string> {
export type Parameters = Record<string, unknown>;

export interface Func {
handler: string;
codeBase64: string;
}

Expand Down Expand Up @@ -102,13 +100,6 @@ export async function executeFunction(

for (const beforeFunction of request.before || []) {
await executor(ctx, beforeFunction, timeout, before);
// Set process environment variables, set from requestStorage
{
const requestStorageEnv = rawStorageRequest().env();
for (const key in requestStorageEnv) {
process.env[key] = requestStorageEnv[key];
}
}
}

// TODO Create Func types instead of casting request objs
Expand Down Expand Up @@ -184,20 +175,6 @@ export async function executeFunction(
console.log(JSON.stringify(result));
}

class TimeoutError extends Error {
constructor(seconds: number) {
super(`function timed out after ${seconds} seconds`);
this.name = "TimeoutError";
}
}

function timer(seconds: number): Promise<never> {
const ms = seconds * 1000;
return new Promise((_, reject) => {
setTimeout(() => reject(new TimeoutError(seconds)), ms);
});
}

export async function executor<F extends Func, Result>(
ctx: RequestCtx,
func: F,
Expand All @@ -213,6 +190,7 @@ export async function executor<F extends Func, Result>(
ctx: RequestCtx,
func: F,
code: string,
timeout: number,
) => Promise<JoiValidationResult | Result>;
},
) {
Expand All @@ -224,10 +202,7 @@ export async function executor<F extends Func, Result>(
const code = wrapCode(originalCode);

// Following section throws on timeout or execution error
const result = await Promise.race([
execute(ctx, func, code),
timer(timeout),
]);
const result = await execute(ctx, func, code, timeout);
debug({ result });
return result;
}
Expand All @@ -236,9 +211,9 @@ export async function runCode(
code: string,
func_kind: FunctionKind,
execution_id: string,
timeout: number,
with_arg?: Record<string, unknown>,
): Promise<Record<string, unknown>> {
const debug = Debug("runCode");
code = await bundleCode(code);
const currentEnv = rawStorage().env;

Expand All @@ -263,13 +238,14 @@ export async function runCode(
func_kind,
execution_id,
with_arg,
env: currentEnv ?? {}
env: currentEnv ?? {},
timeout,
});

worker.onmessage = (event) => {
const { result, env } = event.data;
if (env) {
Object.assign(rawStorage().env, env);
rawStorage().env = { ...env };
}
resolve(result);
worker.terminate();
Expand Down
2 changes: 2 additions & 0 deletions bin/lang-js/src/function_kinds/action_run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ async function execute(
{ executionId }: RequestCtx,
{ args }: ActionRunFunc,
code: string,
timeout: number,
): Promise<ActionRunResult> {
try {
const actionRunResult = await runCode(
code,
FunctionKind.ActionRun,
executionId,
timeout,
args as Record<string, unknown>,
);

Expand Down
2 changes: 2 additions & 0 deletions bin/lang-js/src/function_kinds/before.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ async function execute(
{ executionId }: RequestCtx,
{ arg }: BeforeFunc,
code: string,
timeout: number,
): Promise<BeforeResult> {
try {
await runCode(
code,
FunctionKind.Before,
executionId,
timeout,
arg as Record<string, unknown>,
);
} catch (err) {
Expand Down
33 changes: 26 additions & 7 deletions bin/lang-js/src/function_kinds/joi_validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ async function execute(
{ executionId }: RequestCtx,
args: JoiValidationFunc,
code: string,
timeout: number,
): Promise<JoiValidationResult> {
try {
// NOTE(victor): Joi treats null as a value, so even if .required()
Expand All @@ -46,8 +47,26 @@ async function execute(
code,
FunctionKind.Validation,
executionId,
timeout,
parsedArgs,
);

if (
result.err && typeof result.err === "object" && "name" in result.err &&
"message" in result.err
) {
return {
protocol: "result",
status: "failure",
executionId,
error: {
kind: {
UserCodeException: result.err.name as string,
},
message: result.err.message as string,
},
};
}
debug({ result });
return {
protocol: "result",
Expand All @@ -63,25 +82,25 @@ async function execute(
const wrapCode = (_: string) => `
async function run({ value, validationFormat }) {
let definition;
let message;
try {
definition = JSON.parse(validationFormat);
} catch (e) {
e.name = "JoiValidationJsonParsingError";
message = e;
const error = new Error('Invalid JSON format');
error.name = 'JoiValidationJsonParsingError';
throw error;
}
let schema;
try {
schema = Joi.build(definition);
} catch (e) {
e.name = "JoiValidationFormatError";
e.message = e.message.replace("\\"value\\"", "validationFormat");
message = e;
const error = new Error('validationFormat must be of type object');
error.name = 'JoiValidationFormatError';
throw error;
}
const { error } = schema.validate(value);
return { "err": error };
return { err: error ? error.message : undefined };
}`;

export default {
Expand Down
2 changes: 2 additions & 0 deletions bin/lang-js/src/function_kinds/management.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,15 @@ async function execute(
{ executionId }: RequestCtx,
{ thisComponent, components, currentView }: ManagementFunc,
code: string,
timeout: number,
): Promise<ManagementFuncResult> {
let managementResult: Record<string, unknown> | undefined | null;
try {
managementResult = await runCode(
code,
FunctionKind.Management,
executionId,
timeout,
{ thisComponent, components, currentView },
);
} catch (err) {
Expand Down
2 changes: 2 additions & 0 deletions bin/lang-js/src/function_kinds/resolver_function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,15 @@ async function execute(
{ executionId }: RequestCtx,
{ component, responseType }: ResolverFunc,
code: string,
timeout: number,
): Promise<ResolverFunctionResult> {
let resolverFunctionResult: Record<string, unknown>;
try {
resolverFunctionResult = await runCode(
code,
FunctionKind.ResolverFunction,
executionId,
timeout,
component.data.properties,
);
} catch (err) {
Expand Down
2 changes: 2 additions & 0 deletions bin/lang-js/src/function_kinds/schema_variant_definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ async function execute(
{ executionId }: RequestCtx,
_: SchemaVariantDefinitionFunc,
code: string,
timeout: number,
): Promise<SchemaVariantDefinitionResult> {
let result: Record<string, unknown>;
try {
result = await runCode(
code,
FunctionKind.SchemaVariantDefinition,
executionId,
timeout,
{},
);
debug({ result: JSON.stringify(result) });
Expand Down
1 change: 0 additions & 1 deletion bin/lang-js/src/sandbox/console.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { OutputLine } from "../function.ts";
import { Debug } from "../debug.ts";

const normalizeMessage = (msg: unknown[]): string => {
return msg
Expand Down
21 changes: 0 additions & 21 deletions bin/lang-js/src/vm.ts

This file was deleted.

Loading

0 comments on commit 85f6c59

Please sign in to comment.