From f7335a5262807e061071dd9e2ee24e27073ddb67 Mon Sep 17 00:00:00 2001 From: "COMPUTER\\EDY" <249929363@qq.com> Date: Thu, 10 Sep 2026 18:32:51 +0800 Subject: [PATCH] fix(abtest): clarify admin token authentication errors --- .../laf-cloud/tests/ab-config-admin.test.mjs | 68 +++++++++++++++- server/laf-cloud/tests/ab-config-ui.test.mjs | 79 +++++++++++++++++++ server/xxwz.html | 15 +++- 3 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 server/laf-cloud/tests/ab-config-ui.test.mjs diff --git a/server/laf-cloud/tests/ab-config-admin.test.mjs b/server/laf-cloud/tests/ab-config-admin.test.mjs index 7c7428f..e7f6616 100644 --- a/server/laf-cloud/tests/ab-config-admin.test.mjs +++ b/server/laf-cloud/tests/ab-config-admin.test.mjs @@ -1,4 +1,4 @@ -import test from "node:test"; +import test, { afterEach, beforeEach } from "node:test"; import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import { registerHooks } from "node:module"; @@ -7,6 +7,7 @@ const functionUrl = new URL("../functions/abConfigAdmin.ts", import.meta.url); const state = { configs: [], nextId: 1, + collectionCalls: 0, }; function clone(value) { @@ -19,6 +20,7 @@ function matches(document, query) { function collection(name) { assert.equal(name, "ab_config"); + state.collectionCalls++; return { async get() { return { data: clone(state.configs) }; @@ -64,13 +66,29 @@ registerHooks({ } return nextResolve(specifier, context); }, + load(url, context, nextLoad) { + return nextLoad(url, url === functionUrl.href + ? { ...context, format: "module-typescript" } + : context); + }, }); const { default: abConfigAdmin } = await import(functionUrl); +let previousAdminToken; +beforeEach(() => { + previousAdminToken = process.env.AB_ADMIN_TOKEN; + delete process.env.AB_ADMIN_TOKEN; +}); +afterEach(() => { + if (previousAdminToken === undefined) delete process.env.AB_ADMIN_TOKEN; + else process.env.AB_ADMIN_TOKEN = previousAdminToken; +}); + function reset() { state.configs = []; state.nextId = 1; + state.collectionCalls = 0; } function config(extra = {}) { @@ -95,6 +113,54 @@ async function save(items) { }); } +test("the default admin token lists configs from body or query when no override is set", async () => { + reset(); + state.configs.push(config()); + + for (const source of ["body", "query"]) { + const result = await abConfigAdmin({ + [source]: { action: "list", adminToken: "abtest-admin-token" }, + }); + assert.deepEqual(result, { code: 1, data: state.configs, msg: "ok" }); + } + assert.equal(state.collectionCalls, 2); +}); + +test("AB_ADMIN_TOKEN overrides the default token for body and query requests", async () => { + reset(); + process.env.AB_ADMIN_TOKEN = "custom-test-admin-token"; + + for (const source of ["body", "query"]) { + const rejected = await abConfigAdmin({ + [source]: { action: "list", adminToken: "abtest-admin-token" }, + }); + assert.deepEqual(rejected, { code: 0, data: null, msg: "unauthorized" }); + } + assert.equal(state.collectionCalls, 0); + + for (const source of ["body", "query"]) { + const accepted = await abConfigAdmin({ + [source]: { action: "list", adminToken: "custom-test-admin-token" }, + }); + assert.deepEqual(accepted, { code: 1, data: [], msg: "ok" }); + } + assert.equal(state.collectionCalls, 2); +}); + +test("missing or incorrect tokens reject reads and writes before accessing the database", async () => { + reset(); + + for (const adminToken of [undefined, "incorrect-admin-token"]) { + for (const action of ["list", "save", "disable", "enable", "delete"]) { + const result = await abConfigAdmin({ + body: { action, adminToken, config: config(), experimentId: "exp_layer_1_001" }, + }); + assert.deepEqual(result, { code: 0, data: null, msg: "unauthorized" }); + } + } + assert.equal(state.collectionCalls, 0); +}); + test("resetVersion changes only on an enabled false-to-true transition", async () => { reset(); diff --git a/server/laf-cloud/tests/ab-config-ui.test.mjs b/server/laf-cloud/tests/ab-config-ui.test.mjs new file mode 100644 index 0000000..5ad38d3 --- /dev/null +++ b/server/laf-cloud/tests/ab-config-ui.test.mjs @@ -0,0 +1,79 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { readFile } from "node:fs/promises"; +import { runInNewContext } from "node:vm"; + +const html = await readFile(new URL("../../xxwz.html", import.meta.url), "utf8"); +const script = html.match(/