Compare commits

...

2 Commits

Author SHA1 Message Date
Ruben Fiszel
fc781f0c51 Merge branch 'main' into tests/flow-preview 2024-11-02 19:45:07 +01:00
yacine Bouraroui
ce504178c6 api tests for preview flows 2024-10-07 20:08:07 +02:00
5 changed files with 191 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
# Api integration tests
You'll need deno to be installed and a windmill api endpoint.
By default the tests use the local environment endpoint <http://localhost:8000>. You can override it using `BASE_URL` environment variable.
By default the api authentication uses default local env user credentials. You can override api token using `WM_TOKEN` environment variable.
## Running the api tests
`deno test --allow-env --allow-net`

View File

@@ -0,0 +1,9 @@
{
"tasks": {
"dev": "deno run --watch main.ts",
"test": "deno test --allow-env --allow-net"
},
"imports": {
"@std/assert": "jsr:@std/assert@1"
}
}

40
backend/tests/api/deno.lock generated Normal file
View File

@@ -0,0 +1,40 @@
{
"version": "3",
"packages": {
"specifiers": {
"jsr:@std/assert": "jsr:@std/assert@1.0.6",
"jsr:@std/assert@1": "jsr:@std/assert@1.0.6",
"jsr:@std/internal@^1.0.4": "jsr:@std/internal@1.0.4"
},
"jsr": {
"@std/assert@1.0.6": {
"integrity": "1904c05806a25d94fe791d6d883b685c9e2dcd60e4f9fc30f4fc5cf010c72207",
"dependencies": [
"jsr:@std/internal@^1.0.4"
]
},
"@std/internal@1.0.4": {
"integrity": "62e8e4911527e5e4f307741a795c0b0a9e6958d0b3790716ae71ce085f755422"
}
}
},
"redirects": {
"https://cdn.skypack.dev/human-id@3.0.0": "https://cdn.skypack.dev/new/human-id@v3.0.0/dist=es2019",
"https://cdn.skypack.dev/new/human-id@v3.0.0/dist=es2019": "https://cdn.skypack.dev/error/build:human-id@v3.0.0-ktOXHm1YV4tQ5io95RTp",
"https://deno.land/x/nanoid/mod.ts": "https://deno.land/x/nanoid@v3.0.0/mod.ts"
},
"remote": {
"https://cdn.skypack.dev/error/build:human-id@v3.0.0-ktOXHm1YV4tQ5io95RTp": "54c50c8a33ab04f2a14c966809df583d6c59f0f8b549c270d1127afc8d4c652b",
"https://deno.land/x/nanoid@v3.0.0/customAlphabet.ts": "1cfd7cfd2f07ca8d78a7e7855fcc9f59abf01ef2a127484ef94328fadf940ead",
"https://deno.land/x/nanoid@v3.0.0/customRandom.ts": "af56e19038c891a4b4ef2be931554c27579bd407ee5bbea5cb64f6ee1347cbe3",
"https://deno.land/x/nanoid@v3.0.0/mod.ts": "3ead610e40c58d8fdca21d5da9ec661445a2b82526e19c34d05de5f90be8a1be",
"https://deno.land/x/nanoid@v3.0.0/nanoid.ts": "8d119bc89a0f34e7bbe0c2dbdc280d01753e431af553d189663492310a31085d",
"https://deno.land/x/nanoid@v3.0.0/random.ts": "4da71d5f72f2bfcc6a4ee79b5d4e72f48dcf4fe4c3835fd5ebab08b9f33cd598",
"https://deno.land/x/nanoid@v3.0.0/urlAlphabet.ts": "8b1511deb1ecb23c66202b6000dc10fb68f9a96b5550c6c8cef5009324793431"
},
"workspace": {
"dependencies": [
"jsr:@std/assert@1"
]
}
}

View File

@@ -0,0 +1,80 @@
import { assertEquals } from "jsr:@std/assert";
import type { FlowPreview } from "../../../cli/gen/index.ts";
import * as api from "../../../cli/gen/index.ts";
import { awaitJobCompletion, setup } from "./utils.ts";
const flowPreview: FlowPreview = {
"args": {
"a": 4,
"b": 9
},
"value": {
"modules": [
{
"id": "a",
"value": {
"type": "rawscript",
"content": "// import * as wmill from \"windmill-client\"\n\nexport async function main(a: number, b : number) {\n return a + b\n}\n",
"language": "bun",
"input_transforms": {
"a": {
"type": "javascript",
"expr": "flow_input.a"
},
"b": {
"type": "javascript",
"expr": "flow_input.b"
}
},
"tag": ""
}
},
{
"id": "b",
"value": {
"type": "rawscript",
"content": "// import * as wmill from \"windmill-client\"\n\nexport async function main(n: number) {\n return n / 2.0\n}\n",
"language": "bun",
"input_transforms": {
"n": {
"type": "javascript",
"expr": "results.a"
}
},
"tag": ""
}
}
]
},
"path": "u/admin/beauteous_flow"
};
Deno.test("Run a flow preview and check its completion", async () => {
const { workspace } = await setup()
const id = await api.runFlowPreview({
workspace,
requestBody: flowPreview
});
const result = await awaitJobCompletion({ id, workspace, timeoutMs: 2000 });
assertEquals(result.result, 6.5);
assertEquals(result.canceled, false);
assertEquals(result.success, true);
});
Deno.test("Run a flow preview - Immediately cancel and check cancellation status", async () => {
const { workspace } = await setup()
const id = await api.runFlowPreview({
workspace,
requestBody: flowPreview
});
await api.cancelQueuedJob({ id, workspace, requestBody: { reason: "test cancellation"}});
const result = await awaitJobCompletion({ id, workspace, timeoutMs: 200});
assertEquals(result.canceled, true);
assertEquals(result.success, false);
});

View File

@@ -0,0 +1,51 @@
import { OpenAPI, createWorkspace, getJob, login } from "../../../cli/gen/index.ts";
// Setup method for each api test
export async function setup() {
await generateApiToken()
const workspace = await genTestWorkspace();
return { workspace }
}
async function generateApiToken() {
// if WM_TOKEN env variable not set
if (!OpenAPI.TOKEN) {
const email = Deno.env.get("LOGIN_WM_EMAIL") || "admin@windmill.dev";
const password = Deno.env.get("LOGIN_WM_PASSWORD") || "changeme";
const token = await login({ requestBody: { email, password } });
OpenAPI.TOKEN = token;
}
}
/**
* Ensure a workspace named "api-tests" is created
*/
async function genTestWorkspace() {
const id = "api-tests"
await createWorkspace({ requestBody: { id, name: id}}).catch(()=> null)
return id
}
/**
*
* @returns The job result
*/
export async function awaitJobCompletion(data: { workspace: string, id: string, timeoutMs: number }) {
const start = Date.now();
while (true) {
const result = await getJob(data).catch(()=> null);
if (!!result && result.type === "CompletedJob") {
return result;
}
if ((Date.now() - start) > data.timeoutMs) {
throw new Error("Job did not finish before the specified timeout: " + data.timeoutMs)
}
}
}