Files
story/test/load/provider-callbacks.js
T

75 lines
2.7 KiB
JavaScript
Raw Normal View History

2026-08-26 06:41:07 +08:00
import http from "k6/http";
import crypto from "k6/crypto";
import exec from "k6/execution";
import { check } from "k6";
const baseURL = __ENV.CALLBACK_URL || "http://host.docker.internal:58081";
const secret = __ENV.PROVIDER_CALLBACK_SECRET;
const fixtureText = __ENV.PROVIDER_FIXTURES || `${__ENV.CONVERSATION_ID || ""}|${__ENV.PROVIDER_TASK_REF || ""}`;
const fixtures = fixtureText.split(",").filter(Boolean).map((item) => {
const [conversationID, taskRef] = item.split("|");
return { conversationID, taskRef };
});
const smoke = (__ENV.PROFILE || "acceptance").toLowerCase() === "smoke";
const targetRate = Number(__ENV.RATE || (smoke ? 25 : 500));
const duration = __ENV.DURATION || (smoke ? "10s" : "10m");
const duplicateWindow = Number(__ENV.DUPLICATE_WINDOW || (smoke ? 100 : 300000));
const occurredAt = __ENV.OCCURRED_AT || new Date().toISOString();
if (!secret || !fixtures.length || fixtures.some((item) => !item.conversationID || !item.taskRef)) {
throw new Error("PROVIDER_CALLBACK_SECRET and valid PROVIDER_FIXTURES are required");
}
export const options = {
scenarios: {
provider_notifications: {
executor: "constant-arrival-rate",
rate: targetRate,
timeUnit: "1s",
duration,
preAllocatedVUs: smoke ? 50 : 600,
maxVUs: smoke ? 150 : 1500,
gracefulStop: "30s",
},
},
thresholds: {
http_req_failed: [smoke ? "rate<0.01" : "rate<0.001"],
http_req_duration: ["p(95)<200", "p(99)<1000"],
checks: ["rate>0.999"],
},
};
function base64URL(value) {
return value.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
}
export default function () {
const eventNumber = exec.scenario.iterationInTest % duplicateWindow;
const fixture = fixtures[eventNumber % fixtures.length];
const body = JSON.stringify({
provider: "mock",
event_id: `load-started-${eventNumber}`,
task_ref: fixture.taskRef,
conversation_id: fixture.conversationID,
event_type: "voice_chat.started",
status: "ACTIVE",
occurred_at: occurredAt,
});
const timestamp = new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
const digest = crypto.sha256(body, "hex");
const signature = base64URL(crypto.hmac("sha256", secret, `${timestamp}\n${digest}`, "base64"));
const response = http.post(`${baseURL}/callbacks/v1/vertc/voice-chat`, body, {
headers: {
"Content-Type": "application/json",
"X-Provider-Timestamp": timestamp,
"X-Provider-Signature": signature,
},
tags: { operation: "provider_callback" },
timeout: "3s",
});
check(response, {
"callback acknowledged": (item) => item.status === 200,
"callback response is correlated": (item) => item.status === 200 && item.body.includes('"request_id"'),
});
}