mirror of
https://github.com/modelstudioai/cli.git
synced 2026-09-14 19:49:23 +08:00
fix(knowledge): 验证并限制查询时间范围为过去时间
- 修改时间参数说明,明确要求起止时间必须为过去时间 - 添加起始时间未来时报错机制,避免无意义查询 - 截断结束时间未来时间至当前时间,保障监控接口正确响应 - 添加测试覆盖,验证时间范围边界行为及错误处理 - 补充对应端到端测试路由映射,完善测试用例组织结构
This commit is contained in:
@@ -21,12 +21,13 @@ const KB_STATS_FLAGS = {
|
||||
start: {
|
||||
type: "string",
|
||||
valueHint: "<time>",
|
||||
description: "Range start: Unix seconds or ISO date (default: 24 hours ago)",
|
||||
description:
|
||||
"Range start: Unix seconds or ISO date, must be in the past (default: 24 hours ago)",
|
||||
},
|
||||
end: {
|
||||
type: "string",
|
||||
valueHint: "<time>",
|
||||
description: "Range end: Unix seconds or ISO date (default: now)",
|
||||
description: "Range end: Unix seconds or ISO date, must be in the past (default: now)",
|
||||
},
|
||||
...WORKSPACE_FLAG,
|
||||
} satisfies FlagsDef;
|
||||
@@ -56,6 +57,7 @@ export default defineCommand({
|
||||
notes: [
|
||||
"Defaults to the last 24 hours when --start/--end are omitted.",
|
||||
"Timestamps are normalized to epoch seconds as required by the server.",
|
||||
"Future timestamps are rejected for --start and clamped to now for --end, since the monitor API only returns past data.",
|
||||
],
|
||||
exampleArgs: [
|
||||
"--index-id idx-xxx --workspace-id ws-xxx",
|
||||
@@ -70,7 +72,21 @@ export default defineCommand({
|
||||
const startTimestamp = flags.start
|
||||
? toEpochSecondsString(flags.start)
|
||||
: String(nowSeconds - 24 * 3600);
|
||||
const endTimestamp = flags.end ? toEpochSecondsString(flags.end) : String(nowSeconds);
|
||||
let endTimestamp = flags.end ? toEpochSecondsString(flags.end) : String(nowSeconds);
|
||||
|
||||
// The monitor API rejects future timestamps with a misleading
|
||||
// "missing or invalid" error — validate here with a clear message.
|
||||
if (Number(startTimestamp) > nowSeconds) {
|
||||
throw new BailianError(
|
||||
`Start time is in the future; the monitor API only accepts past or current timestamps.`,
|
||||
ExitCode.USAGE,
|
||||
"Use a start date/time at or before now, or omit --start to default to 24 hours ago.",
|
||||
);
|
||||
}
|
||||
const clampedEnd = Number(endTimestamp) > nowSeconds;
|
||||
if (clampedEnd) {
|
||||
endTimestamp = String(nowSeconds);
|
||||
}
|
||||
|
||||
const body = { indexId: flags.indexId, startTimestamp, endTimestamp };
|
||||
const endpoint = ragEndpoint(workspaceId, RAG_PATHS.indexMonitor);
|
||||
@@ -90,6 +106,9 @@ export default defineCommand({
|
||||
emitResult(response, format === "text" ? "json" : format);
|
||||
return;
|
||||
}
|
||||
if (clampedEnd) {
|
||||
emitBare("note: end time was in the future, clamped to now.");
|
||||
}
|
||||
// Shape verified against the live API: the monitor fields are objects, not arrays
|
||||
const storage = response.data?.storageMonitorData;
|
||||
const qps = response.data?.qpsMonitorData;
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import { describe, expect, test } from "vite-plus/test";
|
||||
import { parseStdoutJson, runCommandE2e } from "../helpers.ts";
|
||||
import { KNOWLEDGE_KB_STATS_ROUTES } from "../topic-routes.ts";
|
||||
|
||||
interface DryRunBody {
|
||||
endpoint?: string;
|
||||
request?: {
|
||||
indexId?: string;
|
||||
startTimestamp?: string;
|
||||
endTimestamp?: string;
|
||||
};
|
||||
}
|
||||
|
||||
describe("e2e: knowledge stats dry-run", () => {
|
||||
test("--dry-run 正常日期范围输出正确时间戳", async () => {
|
||||
const { stdout, stderr, exitCode } = await runCommandE2e(
|
||||
KNOWLEDGE_KB_STATS_ROUTES,
|
||||
[
|
||||
"knowledge",
|
||||
"stats",
|
||||
"--dry-run",
|
||||
"--index-id",
|
||||
"idx_test",
|
||||
"--start",
|
||||
"2026-07-30",
|
||||
"--end",
|
||||
"2026-08-10",
|
||||
"--workspace-id",
|
||||
"ws_test",
|
||||
"--output",
|
||||
"json",
|
||||
],
|
||||
{ DASHSCOPE_API_KEY: "sk-fake-for-dryrun" },
|
||||
);
|
||||
expect(exitCode, stderr).toBe(0);
|
||||
const data = parseStdoutJson<DryRunBody>(stdout);
|
||||
expect(data.endpoint).toMatch(/api\/v1\/indices\/rag\/index\/monitor/);
|
||||
expect(data.request?.indexId).toBe("idx_test");
|
||||
expect(data.request?.startTimestamp).toBe("1785369600"); // 2026-07-30 00:00:00 UTC
|
||||
expect(data.request?.endTimestamp).toBe("1786320000"); // 2026-08-10 00:00:00 UTC (11 days after start)
|
||||
});
|
||||
|
||||
test("--end 未来时间被截断为当前时间", async () => {
|
||||
const beforeRun = Math.floor(Date.now() / 1000);
|
||||
const { stdout, stderr, exitCode } = await runCommandE2e(
|
||||
KNOWLEDGE_KB_STATS_ROUTES,
|
||||
[
|
||||
"knowledge",
|
||||
"stats",
|
||||
"--dry-run",
|
||||
"--index-id",
|
||||
"idx_test",
|
||||
"--start",
|
||||
"2026-07-30",
|
||||
"--end",
|
||||
"2026-12-31",
|
||||
"--workspace-id",
|
||||
"ws_test",
|
||||
"--output",
|
||||
"json",
|
||||
],
|
||||
{ DASHSCOPE_API_KEY: "sk-fake-for-dryrun" },
|
||||
);
|
||||
const afterRun = Math.floor(Date.now() / 1000);
|
||||
expect(exitCode, stderr).toBe(0);
|
||||
const data = parseStdoutJson<DryRunBody>(stdout);
|
||||
expect(data.request?.startTimestamp).toBe("1785369600"); // 2026-07-30 unchanged
|
||||
// endTimestamp should be clamped to now, within the run window
|
||||
const endTs = Number(data.request?.endTimestamp);
|
||||
expect(endTs).toBeGreaterThanOrEqual(beforeRun);
|
||||
expect(endTs).toBeLessThanOrEqual(afterRun);
|
||||
});
|
||||
|
||||
test("--start 未来时间报用法错误 (exit 2)", async () => {
|
||||
const { stderr, exitCode } = await runCommandE2e(
|
||||
KNOWLEDGE_KB_STATS_ROUTES,
|
||||
[
|
||||
"knowledge",
|
||||
"stats",
|
||||
"--dry-run",
|
||||
"--index-id",
|
||||
"idx_test",
|
||||
"--start",
|
||||
"2026-12-31",
|
||||
"--workspace-id",
|
||||
"ws_test",
|
||||
"--output",
|
||||
"json",
|
||||
],
|
||||
{ DASHSCOPE_API_KEY: "sk-fake-for-dryrun" },
|
||||
);
|
||||
expect(exitCode).toBe(2);
|
||||
expect(stderr).toMatch(/future/i);
|
||||
});
|
||||
});
|
||||
@@ -244,6 +244,10 @@ export const KNOWLEDGE_DOC_TAG_ROUTES: E2eRouteExports = {
|
||||
"knowledge file delete": "knowledgeFileDelete", // live cleanup of data-center files
|
||||
};
|
||||
|
||||
export const KNOWLEDGE_KB_STATS_ROUTES: E2eRouteExports = {
|
||||
"knowledge stats": "knowledgeKbStats",
|
||||
};
|
||||
|
||||
export const KNOWLEDGE_SERVICE_ROUTES: E2eRouteExports = {
|
||||
"knowledge service list": "knowledgeServiceList",
|
||||
"knowledge service get": "knowledgeServiceGet",
|
||||
|
||||
@@ -1207,19 +1207,20 @@ bl knowledge service update --agent-id aid-xxx --agent-version 1 --version-desc
|
||||
|
||||
#### Flags
|
||||
|
||||
| Flag | Type | Required | Description |
|
||||
| --------------------- | ------ | -------- | --------------------------------------------------------------- |
|
||||
| `--index-id <id>` | string | yes | Knowledge base ID |
|
||||
| `--start <time>` | string | no | Range start: Unix seconds or ISO date (default: 24 hours ago) |
|
||||
| `--end <time>` | string | no | Range end: Unix seconds or ISO date (default: now) |
|
||||
| `--workspace-id <id>` | string | no | Workspace ID for API endpoint URL (or set BAILIAN_WORKSPACE_ID) |
|
||||
| `--api-key <key>` | string | no | API key |
|
||||
| `--base-url <url>` | string | no | API base URL |
|
||||
| Flag | Type | Required | Description |
|
||||
| --------------------- | ------ | -------- | ---------------------------------------------------------------------------------- |
|
||||
| `--index-id <id>` | string | yes | Knowledge base ID |
|
||||
| `--start <time>` | string | no | Range start: Unix seconds or ISO date, must be in the past (default: 24 hours ago) |
|
||||
| `--end <time>` | string | no | Range end: Unix seconds or ISO date, must be in the past (default: now) |
|
||||
| `--workspace-id <id>` | string | no | Workspace ID for API endpoint URL (or set BAILIAN_WORKSPACE_ID) |
|
||||
| `--api-key <key>` | string | no | API key |
|
||||
| `--base-url <url>` | string | no | API base URL |
|
||||
|
||||
#### Notes
|
||||
|
||||
- Defaults to the last 24 hours when --start/--end are omitted.
|
||||
- Timestamps are normalized to epoch seconds as required by the server.
|
||||
- Future timestamps are rejected for --start and clamped to now for --end, since the monitor API only returns past data.
|
||||
|
||||
#### Examples
|
||||
|
||||
|
||||
Reference in New Issue
Block a user