diff --git a/tests/workflow-tengo/src/exec/large-workdir.test.ts b/tests/workflow-tengo/src/exec/large-workdir.test.ts new file mode 100644 index 0000000000..8ac5872c74 --- /dev/null +++ b/tests/workflow-tengo/src/exec/large-workdir.test.ts @@ -0,0 +1,35 @@ +import { Pl } from "@milaboratories/pl-middle-layer"; +import { tplTest } from "@platforma-sdk/test"; + +/* + * End-to-end check for the E2BIG failure on large working directories + * (fixed in Platforma 4.3.2): a command must start and complete when its + * working directory holds more files than the old inline expected-items list + * could carry (~7300 entries). + * + * `exec.run.large_workdir` fills the working directory with 10000 files and + * runs `hello-world` in it. The software has both a binary and a docker + * distribution, so the same test covers the local exec runner and the k8s + * runner. + * + * The message carries a random suffix on purpose: an exec step with a stable + * CID is deduplicated by the backend, and a cached result would never start a + * job at all. + */ +tplTest.concurrent( + "run-in-workdir-with-10k-files", + async ({ helper, expect }) => { + const helloText = `Hello from a workdir with 10000 files (${Math.random()})`; + + const result = await helper.renderTemplate(false, "exec.run.large_workdir", ["main"], (tx) => ({ + text: tx.createValue(Pl.JsonObject, JSON.stringify(helloText)), + })); + const mainResult = result.computeOutput("main", (a) => a?.getDataAsString()); + + expect(await mainResult.awaitStableValue()).eq(helloText + "\n"); + }, + // Building 10000 workdir entries means 10000 value resources plus the map + // that holds them, all in one transaction. That is slow on the backend, so + // the default 15s test timeout is not enough. + 300_000, +); diff --git a/tests/workflow-tengo/src/exec/run/large_workdir.tpl.tengo b/tests/workflow-tengo/src/exec/run/large_workdir.tpl.tengo new file mode 100644 index 0000000000..797f857527 --- /dev/null +++ b/tests/workflow-tengo/src/exec/run/large_workdir.tpl.tengo @@ -0,0 +1,49 @@ +/** + * Regression test for the E2BIG failure on large working directories + * (fixed in Platforma 4.3.2). + * + * The k8s runner used to pass the expected-workdir-item list to the job + * inline. Above roughly 7300 entries the argument list got larger than the + * kernel limit, `execve` returned E2BIG and the job failed before the + * container started. The list now goes to the job by path + * (`.pl/expected_items` inside the workdir, see + * `util/k8s/job_params.go: DefaultExpectedItemsFileName` in the backend). + * + * The template fills the working directory with 10000 files, which is + * comfortably above the ~7300 threshold, then runs a command in it. Do not + * lower the count below ~7300: under that number the test passes on the + * buggy runner too and gives no coverage. Every file holds one byte, because + * the item *count* is what matters here, not the payload size. + */ + +self := import("@platforma-sdk/workflow-tengo:tpl") +assets := import("@platforma-sdk/workflow-tengo:assets") +exec := import("@platforma-sdk/workflow-tengo:exec") + +self.defineOutputs(["main"]) + +sw := assets.importSoftware("@platforma-open/milaboratories.software-test-utils:hello-world") + +// Number of files to put into the working directory. +// Keep it above the ~7300 entries that used to break `execve`. +workdirFileCount := 10000 + +self.body(func(inputs) { + builder := exec.builder(). + cpu(1).ram("50Mi"). + software(sw). + arg(inputs.text). + saveStdoutContent() + + // `writeFile` is the cheapest way to reach the file count: it needs no + // blob, no upload and no signature, only a small value resource. + for i := 0; i < workdirFileCount; i++ { + builder.writeFile("filler/" + string(i) + ".txt", "x") + } + + run := builder.run() + + return { + main: run.getStdoutContent() + } +})