diff --git a/.ghjk/deno.lock b/.ghjk/deno.lock index 03b3224900..b5bce0a918 100644 --- a/.ghjk/deno.lock +++ b/.ghjk/deno.lock @@ -751,6 +751,7 @@ "https://deno.land/x/code_block_writer@12.0.0/utils/string_utils.ts": "60cb4ec8bd335bf241ef785ccec51e809d576ff8e8d29da43d2273b69ce2a6ff", "https://deno.land/x/convert_bytes@v2.1.1/mod.ts": "036bd2d9519c8ad44bd5a15d4e42123dc16843f793b3c81ca1fca905b21dd7df", "https://deno.land/x/convert_bytes@v2.1.1/src/utility.ts": "a94b4c50286910a23a90c0a0510e8191fa3311dec44d062a6d4fe3d5b7ff8176", + "https://deno.land/x/ctrlc@0.2.1/mod.ts": "b7895894c596f2e8355d3b181ed30fa74cb54b94c419b730f6cb6ff96b20ec8b", "https://deno.land/x/dax@0.38.0/mod.ts": "3a5d7e6ac12547feec5d3c0c96717f14276891a3802fbbc73e5901e4f20eb08d", "https://deno.land/x/dax@0.38.0/src/command.ts": "f20135ef7188a0fc9f773d50e88775dee8653044a7f536fb2fb885b293c26ec4", "https://deno.land/x/dax@0.38.0/src/command_handler.ts": "a9e40f0f1ec57318e62904b5785fede82dcdf1101922ebb3ebfad8f1c4d9c8df", diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8e7efd1ee0..787597bb88 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -283,7 +283,7 @@ jobs: ghjk x test-rust - ghjk x test-e2e --threads 1 -- --coverage=coverage + ghjk x test-e2e -- --coverage=coverage # FIXME: required due to https://github.com/denoland/deno/issues/21621#issuecomment-1887870712 deno cache --import-map typegate/import_map.json \ diff --git a/dev/deps.ts b/dev/deps.ts index f6fe6d7829..daf72a83a0 100644 --- a/dev/deps.ts +++ b/dev/deps.ts @@ -33,7 +33,13 @@ export { expandGlob, expandGlobSync, } from "https://deno.land/std@0.219.0/fs/mod.ts"; -export { cyan, green } from "https://deno.land/std@0.219.0/fmt/colors.ts"; +export { + cyan, + gray, + green, + red, + yellow, +} from "https://deno.land/std@0.219.0/fmt/colors.ts"; export { format as formatDuration } from "https://deno.land/std@0.219.0/fmt/duration.ts"; export { mergeReadableStreams, @@ -51,3 +57,4 @@ import Fuse from "https://deno.land/x/fuse@v6.4.1/dist/fuse.esm.min.js"; export { Fuse }; import bytes from "https://deno.land/x/convert_bytes@v2.1.1/mod.ts"; export { bytes }; +export * as ctrlc from "https://deno.land/x/ctrlc@0.2.1/mod.ts"; diff --git a/dev/test.ts b/dev/test.ts index f9b325a2bd..4f711c0069 100755 --- a/dev/test.ts +++ b/dev/test.ts @@ -24,25 +24,26 @@ import { $, + ctrlc, + cyan, Fuse, + gray, + green, mergeReadableStreams, parseArgs, + red, TextLineStream, + yellow, } from "./deps.ts"; import { projectDir } from "./utils.ts"; -export async function testE2e(args: { - files: string[]; - filter?: string; - threads?: number; - flags?: string[]; -}) { - const { filter, threads = 4, flags = [] } = args; - const wd = $.path(projectDir); - const testFiles = [] as string[]; - if (args.files.length > 0) { +const wd = $.path(projectDir); + +async function listTestFiles(filesArg: string[]): Promise { + if (filesArg.length > 0) { + const testFiles = [] as string[]; await $.co( - args.files.map(async (inPath) => { + filesArg.map(async (inPath) => { let path = wd.resolve(inPath); let stat = await path.stat(); if (!stat) { @@ -72,21 +73,35 @@ export async function testE2e(args: { } }), ); + return testFiles; } else { // run all the tests - testFiles.push( - ...( - await Array.fromAsync( - wd - .join("typegate/tests") - .expandGlob("**/*_test.ts", { globstar: true }), - ) - ).map((ent) => ent.path.toString()), - ); + return ( + await Array.fromAsync( + wd + .join("typegate/tests") + .expandGlob("**/*_test.ts", { globstar: true }), + ) + ).map((ent) => ent.path.toString()); } +} + +interface Result { + testFile: string; + duration: number; + success: boolean; +} + +interface Run { + promise: Promise; + output: ReadableStream | null; + done: boolean; +} + +function applyFilter(files: string[], filter: string | undefined): string[] { const prefixLength = `${projectDir}/typegate/tests/`.length; const fuse = new Fuse( - testFiles.map((f) => f.slice(prefixLength)), + files.map((f) => f.slice(prefixLength)), { includeScore: true, useExtendedSearch: true, @@ -94,9 +109,18 @@ export async function testE2e(args: { }, ); const filtered = filter ? fuse.search(filter) : null; - const filteredTestFiles = filtered?.map((res) => testFiles[res.refIndex]) ?? - testFiles; + return filtered?.map((res) => files[res.refIndex]) ?? files; +} +export async function testE2e(args: { + files: string[]; + filter?: string; + threads?: number; + flags?: string[]; +}) { + const { filter, threads = 4, flags = [] } = args; + const testFiles = await listTestFiles(args.files); + const filteredTestFiles = applyFilter(testFiles, filter); if (filteredTestFiles.length == 0) { throw new Error("No tests found to run"); } @@ -139,36 +163,26 @@ export async function testE2e(args: { const prefix = "[dev/test.ts]"; $.logStep(`${prefix} Testing with ${threads} threads`); - interface Result { - testFile: string; - duration: number; - success: boolean; - } - - interface Run { - promise: Promise; - output: ReadableStream; - done: boolean; - streamed: boolean; - } - const xtask = wd.join("target/debug/xtask"); const denoConfig = wd.join("typegate/deno.jsonc"); - function createRun(testFile: string): Run { + function createRun(testFile: string, streamed: boolean): Run { const start = Date.now(); + const outputOption = streamed ? "inherit" : "piped"; const child = $ .raw`${xtask} deno test --config=${denoConfig} ${testFile} ${flags}` .cwd(wd) .env(env) - .stdout("piped") - .stderr("piped") + .stdout(outputOption) + .stderr(outputOption) .noThrow() .spawn(); - const output = mergeReadableStreams(child.stdout(), child.stderr()) - .pipeThrough(new TextDecoderStream()) - .pipeThrough(new TextLineStream()); + const output = streamed + ? null + : mergeReadableStreams(child.stdout(), child.stderr()) + .pipeThrough(new TextDecoderStream()) + .pipeThrough(new TextLineStream()); const promise = child.then(({ code }) => { const end = Date.now(); @@ -179,94 +193,73 @@ export async function testE2e(args: { promise, output, done: false, - streamed: false, }; } - const queues = [...filteredTestFiles]; - const runs: Record = {}; - const globalStart = Date.now(); + const queue = [...filteredTestFiles]; $.logStep(`${prefix} Building xtask and meta-cli...`); await $`cargo build -p xtask -p meta-cli`.cwd(wd); - // launch a promise that doesnt get awaited - (async () => { - while (queues.length > 0) { - const current = Object.values(runs) - .filter((r) => !r.done) - .map((r) => r.promise); - if (current.length <= threads) { - const next = queues.shift()!; - runs[next] = createRun(next); - } else { - const result = await Promise.any(current); - runs[result.testFile].done = true; - } - } - })(); - - let nexts = Object.keys(runs); - do { - const file = nexts.find((f) => !runs[f].done) ?? nexts[0]; - const run = runs[file]; - run.streamed = true; - - $.logStep(`${prefix} Launched ${wd.relative(file)}`); - for await (const line of run.output) { - if (line.startsWith("warning: skipping duplicate package")) { - // https://github.com/rust-lang/cargo/issues/10752 - continue; - } - $.log(line); - } + $.logStep(`Discovered ${queue.length} test files to run`); - const { duration } = await run.promise; - $.logStep( - `${prefix} Completed ${wd.relative(file)} in ${duration / 1_000}s`, - ); - - nexts = Object.keys(runs).filter((f) => !runs[f].streamed); - } while (nexts.length > 0); - - const globalDuration = Date.now() - globalStart; - const finished = await Promise.all(Object.values(runs).map((r) => r.promise)); - const successes = finished.filter((r) => r.success); - const failures = finished.filter((r) => !r.success); - - $.log(); - $.log( - `Tests completed in ${Math.floor(globalDuration / 60_000)}m${ - Math.floor(globalDuration / 1_000) % 60 - }s:`, - ); + const threadCount = Math.min(threads, queue.length); - for (const run of finished.sort((a, b) => a.duration - b.duration)) { - $.log( - ` - ${Math.floor(run.duration / 60_000)}m${ - Math.floor(run.duration / 1_000) % 60 - }s -- ${run.success ? "" : "FAILED -"}${wd.relative(run.testFile)}`, - ); - } + const outputOptions: OutputOptions = { + streamed: threadCount === 1, + verbose: false, + }; + const logger = new Logger(queue, threadCount, outputOptions); + const results = new TestResultConsumer(logger); - $.log(` successes: ${successes.length}/${filteredTestFiles.length}`); - $.log(` failures: ${failures.length}/${filteredTestFiles.length}`); - const filteredOutCount = testFiles.length - filteredTestFiles.length; - if (filteredOutCount > 0) { - $.log(` ${filteredOutCount} test files were filtered out`); + const testThreads: TestThread[] = []; + for (let i = 0; i < threadCount; i++) { + testThreads.push(new TestThread(i + 1, queue, results, logger, createRun)); } - $.log(""); + let ctrlcCount = 0; + const _ctrlc = ctrlc.setHandler(() => { + ctrlcCount++; + switch (ctrlcCount) { + case 1: { + const remaining = queue.length; + queue.length = 0; + logger.cancelled(remaining); + results.setCancelledCount(remaining); + break; + } - if (failures.length > 0) { - $.logError("Errors were detected:"); - $.logGroup(() => { - for (const failure of failures) { - $.log(`- ${wd.relative(failure.testFile)}`); + case 2: { + console.log(`Killing ${testThreads.length} running tests...`); + for (const t of testThreads) { + if (t.testProcess) { + t.testProcess.kill("SIGKILL"); + } + } + break; } - }); - throw new Error("test errors detected"); + + case 3: + console.log("Force exiting..."); + Deno.exit(1); + break; + } + }); + + const runnerResults = await Promise.allSettled( + testThreads.map(async (t) => { + await t.run(); + return t; + }), + ); + for (const result of runnerResults) { + if (result.status === "rejected") { + console.error("Thread #${result.threadId} failed to run"); + console.error(result.reason); + } } + + return await results.finalize(); } export async function testE2eCli(argv: string[]) { @@ -274,7 +267,7 @@ export async function testE2eCli(argv: string[]) { "--": true, string: ["threads", "f", "filter"], }); - await testE2e({ + return await testE2e({ files: flags._.map((item) => item.toString()), threads: flags.threads ? parseInt(flags.threads) : undefined, filter: flags.filter ?? flags.f, @@ -283,5 +276,292 @@ export async function testE2eCli(argv: string[]) { } if (import.meta.main) { - await testE2eCli(Deno.args); + Deno.exit(await testE2eCli(Deno.args)); +} + +type TestThreadState = + | { status: "idle" } + | { status: "running"; testFile: string } + | { status: "finished" }; + +interface Counts { + success: number; + failure: number; + cancelled: number; +} + +class Logger { + private threadStates: Array; + private dynamic = Deno.stdout.isTerminal(); // TODO: make this configurable + + #print(...args: unknown[]) { + Deno.stdout.writeSync(new TextEncoder().encode(args.join(" "))); + } + #println(...args: unknown[]) { + this.#print(...args, "\n"); + } + + #counts: Counts = { + success: 0, + failure: 0, + cancelled: 0, + }; + + constructor( + private queue: string[], + private threadCount: number, + public readonly options: Readonly, + ) { + this.threadStates = Array.from({ length: threadCount }, () => ({ + status: "idle", + })); + + if (this.dynamic) { + this.#println(); + this.#displayThreadStates(); + } + } + + threadState(threadId: number, state: TestThreadState) { + this.threadStates[threadId - 1] = state; + if (!this.dynamic) { + this.#displayThreadState(threadId); + } else { + this.#clearThreadStates(); + this.#displayThreadStates(); + } + } + + updateCounts(counts: Partial) { + this.#counts = { + ...this.#counts, + ...counts, + }; + } + + #clearThreadStates() { + this.#print(`\x1b[${this.threadCount + 2}A\x1b[J`); + } + #displayThreadStates() { + this.#println(); + for (let i = 1; i <= this.threadCount; i++) { + this.#displayThreadState(i); + } + this.#displayCounts(); + } + + #displayCounts() { + const fields = []; + + const activeCount = this.threadStates.filter( + (s) => s.status === "running", + ).length; + fields.push(gray(`active=${activeCount}`)); + + fields.push(`pending=${this.queue.length}`); + + if (this.#counts.success) { + fields.push(green(`success=${this.#counts.success}`)); + } + + if (this.#counts.failure) { + fields.push(red(`failure=${this.#counts.failure}`)); + } + + if (this.#counts.cancelled) { + fields.push(gray(`cancelled=${this.#counts.cancelled}`)); + } + + this.#println(" ", ...fields); + } + + #displayThreadState(threadId: number) { + const state = this.threadStates[threadId - 1]; + let displayedState: string; + switch (state.status) { + case "idle": + case "finished": + displayedState = gray(state.status); + break; + case "running": + displayedState = state.testFile; + break; + } + this.#println(cyan(`thread #${threadId}`), displayedState); + } + + result(result: ExtendedResult, counts: Counts) { + this.updateCounts(counts); + const status = result.success ? green("passed") : red("failed"); + + this.#output(() => { + this.#println( + status, + result.testFile, + gray(`(${result.duration / 1_000}s)`), + gray(`#${result.runnerId}`), + ); + }); + } + + async resultOutputs(results: ExtendedResult[]) { + if (this.options.streamed) return; + for (const result of results) { + if (result.success && !this.options.verbose) continue; + await this.#resultOuput(result); + } + } + + async #resultOuput(result: ExtendedResult) { + this.#println(); + this.#println(gray("-- OUTPUT START"), result.testFile, gray("--")); + for await (const line of result.output!) { + this.#println(line); + } + this.#println(gray("-- OUTPUT END"), result.testFile, gray("--")); + } + + cancelled(count: number) { + this.#output(() => { + this.#println( + yellow(`cancelled ${count} pending tests...`), + "Press Ctrl-C again to stop current tests...", + ); + }); + } + + #output(outputFn: () => void) { + if (!this.dynamic) { + if (this.options.streamed) { + this.#println(); + } + outputFn(); + if (this.options.streamed) { + this.#println(); + } + } else { + this.#clearThreadStates(); + outputFn(); + this.#displayThreadStates(); + } + } +} + +interface ExtendedResult extends Result { + testFile: string; + output: ReadableStream | null; + runnerId: number; +} + +interface OutputOptions { + streamed: boolean; + verbose: boolean; +} + +class TestResultConsumer { + private results: ExtendedResult[] = []; + #counts: Counts = { + success: 0, + failure: 0, + // error: 0, + cancelled: 0, + }; + private startTime: number; + + constructor(private logger: Logger) { + this.startTime = Date.now(); + } + + consume(r: Omit, runner: TestThread) { + const result: ExtendedResult = { ...r, runnerId: runner.threadId }; + if (result.success) { + this.#counts.success++; + } else { + this.#counts.failure++; + } + + this.logger.result(result, this.#counts); + this.results.push(result); + } + + setCancelledCount(count: number) { + this.#counts.cancelled = count; + } + + async finalize(): Promise { + await this.logger.resultOutputs(this.results); + + const duration = Date.now() - this.startTime; + + console.log(); + if (this.#counts.cancelled > 0) { + console.log(`${this.#counts.cancelled} tests were cancelled`); + } + console.log( + `${this.results.length} tests completed in ${ + Math.floor( + duration / 60_000, + ) + }m${Math.floor(duration / 1_000)}s:`, + ); + console.log(` successes: ${this.#counts.success}/${this.results.length}`); + + console.log(` failures: ${this.#counts.failure}/${this.results.length}`); + + if (this.#counts.failure > 0) { + for (const res of this.results) { + if (!res.success) { + console.log(` - ${res.testFile}`); + } + } + } + + if (this.#counts.failure + this.#counts.cancelled > 0) { + return 1; + } else { + return 0; + } + } +} + +class TestThread { + currentRun: Run | null; + + constructor( + public threadId: number, + private queue: string[], + private results: TestResultConsumer, + private logger: Logger, + private createRun: (file: string, streamed: boolean) => Run, + ) {} + + async run() { + while (true) { + const testFile = this.queue.shift(); + if (!testFile) break; + + const pathPrefix = `${projectDir}/typegate/tests/`; + const relativePath = testFile.slice(pathPrefix.length); + + this.logger.threadState(this.threadId, { + status: "running", + testFile: relativePath, + }); + + this.currentRun = this.createRun(testFile, this.logger.options.streamed); + const result = await this.currentRun.promise; + + this.results.consume( + { + output: this.currentRun.output, + ...result, + testFile: relativePath, + }, + this, + ); + this.currentRun = null; + } + + this.logger.threadState(this.threadId, { status: "finished" }); + } } diff --git a/typegate/deno.lock b/typegate/deno.lock index 2d8ae51d20..49e178b4a8 100644 --- a/typegate/deno.lock +++ b/typegate/deno.lock @@ -1344,6 +1344,7 @@ "https://deno.land/x/convert_bytes@v2.1.1/src/unit.ts": "ebfa749b09d2f6cf16a3a6cae5ab6042ae66667b9780071cbb933fcbdcff9731", "https://deno.land/x/convert_bytes@v2.1.1/src/utility.ts": "a94b4c50286910a23a90c0a0510e8191fa3311dec44d062a6d4fe3d5b7ff8176", "https://deno.land/x/crc32@v0.2.0/mod.ts": "de7a3fa2d4ef24b96fc21e1cc4d2d65d1d2b1dcea92f63960e3e11bfa82df0fa", + "https://deno.land/x/ctrlc@0.2.1/mod.ts": "b7895894c596f2e8355d3b181ed30fa74cb54b94c419b730f6cb6ff96b20ec8b", "https://deno.land/x/dax@0.39.2/mod.ts": "309f96ce11fa8a1bb244fdfdcb60fa66f092200a72295402094aab88bdf02bdd", "https://deno.land/x/dax@0.39.2/src/command.ts": "01980353fec193bbc7f1c3690bb87472607d0b1b7d9844d17904920b907cd0de", "https://deno.land/x/dax@0.39.2/src/command_handler.ts": "a9e40f0f1ec57318e62904b5785fede82dcdf1101922ebb3ebfad8f1c4d9c8df", diff --git a/typegate/tests/metagen/typegraphs/identities/py/handlers_types.py b/typegate/tests/metagen/typegraphs/identities/py/handlers_types.py index 653acf9641..f6107c59dd 100644 --- a/typegate/tests/metagen/typegraphs/identities/py/handlers_types.py +++ b/typegate/tests/metagen/typegraphs/identities/py/handlers_types.py @@ -116,8 +116,8 @@ class CompositesArgs(Struct): @dataclass class Composites(Struct): opt: Union[str, None] - either: Union["Primitives", "Branch2"] - union: Union[int, str, List[str]] + either: Union["Branch2", "Primitives"] + union: Union[List[str], int, str] list: List[str] @@ -143,8 +143,8 @@ class Cycles1Args(Struct): @dataclass class Cycles1(Struct): phantom1: Union[str, None] - to2: Union[Union["Cycles1", Union["Branch33A", "Branch33B"]], None] - list3: Union[List[Union["Branch33A", "Branch33B"]], None] + to2: Union[Union[Union["Branch33B", "Branch33A"], "Cycles1"], None] + list3: Union[List[Union["Branch33B", "Branch33A"]], None] FORWARD_REFS["Cycles1"] = Cycles1 @@ -162,7 +162,7 @@ class Branch33A(Struct): @dataclass class Branch33B(Struct): phantom3b: Union[str, None] - to2: Union[Union[Union["Branch33B", "Branch33A"], "Cycles1"], None] + to2: Union[Union[Union["Branch33A", "Branch33B"], "Cycles1"], None] FORWARD_REFS["Branch33B"] = Branch33B @@ -209,10 +209,10 @@ def __repr(value: Any): return value -def typed_cycles(user_fn: Callable[[Cycles1Args], Cycles1]): +def typed_primitives(user_fn: Callable[[PrimitivesArgs], Primitives]): def exported_wrapper(raw_inp): - inp: Cycles1Args = Struct.new(Cycles1Args, raw_inp) - out: Cycles1 = user_fn(inp) + inp: PrimitivesArgs = Struct.new(PrimitivesArgs, raw_inp) + out: Primitives = user_fn(inp) if isinstance(out, list): return [__repr(v) for v in out] return __repr(out) @@ -231,10 +231,10 @@ def exported_wrapper(raw_inp): return exported_wrapper -def typed_simple_cycles(user_fn: Callable[[SimpleCycles1Args], SimpleCycles1]): +def typed_cycles(user_fn: Callable[[Cycles1Args], Cycles1]): def exported_wrapper(raw_inp): - inp: SimpleCycles1Args = Struct.new(SimpleCycles1Args, raw_inp) - out: SimpleCycles1 = user_fn(inp) + inp: Cycles1Args = Struct.new(Cycles1Args, raw_inp) + out: Cycles1 = user_fn(inp) if isinstance(out, list): return [__repr(v) for v in out] return __repr(out) @@ -242,10 +242,10 @@ def exported_wrapper(raw_inp): return exported_wrapper -def typed_primitives(user_fn: Callable[[PrimitivesArgs], Primitives]): +def typed_simple_cycles(user_fn: Callable[[SimpleCycles1Args], SimpleCycles1]): def exported_wrapper(raw_inp): - inp: PrimitivesArgs = Struct.new(PrimitivesArgs, raw_inp) - out: Primitives = user_fn(inp) + inp: SimpleCycles1Args = Struct.new(SimpleCycles1Args, raw_inp) + out: SimpleCycles1 = user_fn(inp) if isinstance(out, list): return [__repr(v) for v in out] return __repr(out) diff --git a/typegate/tests/metagen/typegraphs/identities/rs/mdk.rs b/typegate/tests/metagen/typegraphs/identities/rs/mdk.rs index 6193245511..71bdb9b45f 100644 --- a/typegate/tests/metagen/typegraphs/identities/rs/mdk.rs +++ b/typegate/tests/metagen/typegraphs/identities/rs/mdk.rs @@ -109,7 +109,7 @@ impl Router { } pub fn init(&self, args: InitArgs) -> Result { - static MT_VERSION: &str = "0.4.3-0"; + static MT_VERSION: &str = "0.4.4-0"; if args.metatype_version != MT_VERSION { return Err(InitError::VersionMismatch(MT_VERSION.into())); } diff --git a/typegate/tests/runtimes/python/python_sync_test.ts b/typegate/tests/runtimes/python/python_sync_test.ts index a0ec486799..da49b3871f 100644 --- a/typegate/tests/runtimes/python/python_sync_test.ts +++ b/typegate/tests/runtimes/python/python_sync_test.ts @@ -28,7 +28,7 @@ const syncConfig = { hostname: "localhost", port: 6379, password: "password", - db: 1, + db: 2, }, s3: { endpoint: "http://localhost:9000", @@ -66,21 +66,21 @@ Meta.test( assertEquals(s3Objects?.length, 4); await gql` - query { - identityDef(input: { a: "hello", b: [1, 2, "three"] }) { - a - b - } - identityLambda(input: { a: "hello", b: [1, 2, "three"] }) { - a - b - } - identityMod(input: { a: "hello", b: [1, 2, "three"] }) { - a - b + query { + identityDef(input: { a: "hello", b: [1, 2, "three"] }) { + a + b + } + identityLambda(input: { a: "hello", b: [1, 2, "three"] }) { + a + b + } + identityMod(input: { a: "hello", b: [1, 2, "three"] }) { + a + b + } } - } - ` + ` .expectData({ identityDef: { a: "hello", @@ -115,9 +115,7 @@ Meta.test( }, }, async (t) => { - const e = await t.engine( - "runtimes/python/python.py", - ); + const e = await t.engine("runtimes/python/python.py"); await t.should("work once (lambda)", async () => { await gql` @@ -216,9 +214,7 @@ Meta.test( }, async (t) => { const testMultipleReplica = async (instanceNumber: number) => { - const e = await t.engine( - "runtimes/python/python.py", - ); + const e = await t.engine("runtimes/python/python.py"); await sleep(5_000); @@ -226,10 +222,10 @@ Meta.test( `work on the typgate instance #${instanceNumber}`, async () => { await gql` - query { - testMod(name: "Loyd") - } - ` + query { + testMod(name: "Loyd") + } + ` .expectData({ testMod: `Hello Loyd`, }) @@ -320,18 +316,16 @@ Meta.test( }, }, async (t) => { - const e = await t.engine( - "runtimes/python/python_no_artifact.py", - ); + const e = await t.engine("runtimes/python/python_no_artifact.py"); await t.should( "work when there are no artifacts in the typegraph: python SDK, in sync mode", async () => { await gql` - query { - test_lambda(a: "test") - } - ` + query { + test_lambda(a: "test") + } + ` .expectData({ test_lambda: "test", }) @@ -360,17 +354,17 @@ Meta.test( "work when there are no artifacts in the typegraph: TS SDK, in sync mode", async () => { await gql` - query { - identityDef(input: { a: "hello", b: [1, 2, "three"] }) { - a - b - } - identityLambda(input: { a: "hello", b: [1, 2, "three"] }) { - a - b + query { + identityDef(input: { a: "hello", b: [1, 2, "three"] }) { + a + b + } + identityLambda(input: { a: "hello", b: [1, 2, "three"] }) { + a + b + } } - } - ` + ` .expectData({ identityDef: { a: "hello", @@ -401,19 +395,17 @@ Meta.test( }, }, async (t) => { - const e = await t.engine( - "runtimes/python/python_duplicate_artifact.py", - ); + const e = await t.engine("runtimes/python/python_duplicate_artifact.py"); await t.should( "work when there is duplicate artifacts uploads: Python SDK, in sync mode", async () => { await gql` - query { - testMod(name: "Loyd") - testModDuplicate(name: "Barney") - } - ` + query { + testMod(name: "Loyd") + testModDuplicate(name: "Barney") + } + ` .expectData({ testMod: "Hello Loyd", testModDuplicate: "Hello Barney", @@ -444,17 +436,17 @@ Meta.test( "work when there is duplicate artifacts uploads: TS SDK, in sync mode", async () => { await gql` - query { - identityMod(input: { a: "hello", b: [1, 2, "three"] }) { - a - b - }, - identityModDuplicate(input: { a: "hello", b: [1, 2, "three"] }) { - a - b + query { + identityMod(input: { a: "hello", b: [1, 2, "three"] }) { + a + b + } + identityModDuplicate(input: { a: "hello", b: [1, 2, "three"] }) { + a + b + } } - } - ` + ` .expectData({ identityMod: { a: "hello", @@ -486,9 +478,7 @@ Meta.test( await t.should( "work for deps specified with dir on Python SDK", async () => { - const engine = await t.engine( - "runtimes/python/python_dir.py", - ); + const engine = await t.engine("runtimes/python/python_dir.py"); await gql` query { @@ -542,9 +532,7 @@ Meta.test( await t.should( "work for deps specified with glob on Python SDK", async () => { - const engine = await t.engine( - "runtimes/python/python_globs.py", - ); + const engine = await t.engine("runtimes/python/python_globs.py"); await gql` query { diff --git a/typegate/tests/runtimes/wasm_reflected/rust/Cargo.lock b/typegate/tests/runtimes/wasm_reflected/rust/Cargo.lock index 8b1284b8ca..aa66b21c8f 100644 --- a/typegate/tests/runtimes/wasm_reflected/rust/Cargo.lock +++ b/typegate/tests/runtimes/wasm_reflected/rust/Cargo.lock @@ -114,7 +114,7 @@ dependencies = [ [[package]] name = "rust" -version = "0.4.3-0" +version = "0.4.4-0" dependencies = [ "wit-bindgen", ] diff --git a/typegate/tests/runtimes/wasm_reflected/wasm_sync_test.ts b/typegate/tests/runtimes/wasm_reflected/wasm_sync_test.ts index 30c728de31..6a24090bd4 100644 --- a/typegate/tests/runtimes/wasm_reflected/wasm_sync_test.ts +++ b/typegate/tests/runtimes/wasm_reflected/wasm_sync_test.ts @@ -27,7 +27,7 @@ const syncConfig = { hostname: "localhost", port: 6379, password: "password", - db: 1, + db: 3, }, s3: { endpoint: "http://localhost:9000", diff --git a/typegate/tests/runtimes/wasm_wire/rust/mdk.rs b/typegate/tests/runtimes/wasm_wire/rust/mdk.rs index 90af5cb14c..83b4a69635 100644 --- a/typegate/tests/runtimes/wasm_wire/rust/mdk.rs +++ b/typegate/tests/runtimes/wasm_wire/rust/mdk.rs @@ -109,7 +109,7 @@ impl Router { } pub fn init(&self, args: InitArgs) -> Result { - static MT_VERSION: &str = "0.4.3-0"; + static MT_VERSION: &str = "0.4.4-0"; if args.metatype_version != MT_VERSION { return Err(InitError::VersionMismatch(MT_VERSION.into())); } diff --git a/typegate/tests/runtimes/wasm_wire/wasm_sync_test.ts b/typegate/tests/runtimes/wasm_wire/wasm_sync_test.ts index 5ef88614e7..6d23ff5b46 100644 --- a/typegate/tests/runtimes/wasm_wire/wasm_sync_test.ts +++ b/typegate/tests/runtimes/wasm_wire/wasm_sync_test.ts @@ -27,7 +27,7 @@ const syncConfig = { hostname: "localhost", port: 6379, password: "password", - db: 1, + db: 4, }, s3: { endpoint: "http://localhost:9000", @@ -87,9 +87,7 @@ Meta.test( assertEquals((await listObjects(s3, syncConfig.s3Bucket))?.length, 3); - const engine = await metaTest.engine( - "runtimes/wasm_wire/wasm_wire.ts", - ); + const engine = await metaTest.engine("runtimes/wasm_wire/wasm_wire.ts"); await gql` query { @@ -104,9 +102,7 @@ Meta.test( .on(engine); // second engine on the other typegate instance - const engine2 = await metaTest.engine( - "runtimes/wasm_wire/wasm_wire.ts", - ); + const engine2 = await metaTest.engine("runtimes/wasm_wire/wasm_wire.ts"); await gql` query { diff --git a/typegate/tests/utils/metadev.ts b/typegate/tests/utils/metadev.ts index 7354cc7051..fa8bb790f7 100644 --- a/typegate/tests/utils/metadev.ts +++ b/typegate/tests/utils/metadev.ts @@ -54,13 +54,11 @@ export class MetaDev { async #fetchOutputLines( reader: ReadableStreamDefaultReader, param: FetchOutputLineParam, - timeoutMs: number = 5_000, + timeoutMs: number = 30_000, ) { - const next = timeoutMs == null ? () => reader.read() : () => - deadline( - reader.read(), - timeoutMs, - ); + const next = timeoutMs == null + ? () => reader.read() + : () => deadline(reader.read(), timeoutMs); let shouldContinue = true; while (shouldContinue) { const { value: line, done } = await next();