mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
test: clear music generate broad matchers
This commit is contained in:
@@ -124,6 +124,8 @@ function expectMusicGenerateTool(
|
||||
function resetMusicGenerateMocks() {
|
||||
vi.restoreAllMocks();
|
||||
vi.spyOn(musicGenerationRuntime, "listRuntimeMusicGenerationProviders").mockReturnValue([]);
|
||||
musicGenerationRuntimeMocks.generateMusic.mockReset();
|
||||
mediaStoreMocks.saveMediaBuffer.mockReset();
|
||||
taskRuntimeInternalMocks.listTasksForOwnerKey.mockReset();
|
||||
taskRuntimeInternalMocks.listTasksForOwnerKey.mockReturnValue([]);
|
||||
taskExecutorMocks.createRunningTaskRun.mockReset();
|
||||
@@ -132,6 +134,43 @@ function resetMusicGenerateMocks() {
|
||||
taskExecutorMocks.recordTaskRunProgressByRunId.mockReset();
|
||||
}
|
||||
|
||||
function detailsOf(result: { details?: unknown }): Record<string, unknown> {
|
||||
expect(typeof result.details).toBe("object");
|
||||
expect(result.details).not.toBeNull();
|
||||
return result.details as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function generateMusicOptions(
|
||||
callIndex = musicGenerationRuntimeMocks.generateMusic.mock.calls.length - 1,
|
||||
): Record<string, unknown> {
|
||||
const options = musicGenerationRuntimeMocks.generateMusic.mock.calls[callIndex]?.[0];
|
||||
expect(typeof options).toBe("object");
|
||||
expect(options).not.toBeNull();
|
||||
return options as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function taskProgressCall(callIndex = 0): Record<string, unknown> {
|
||||
const call = taskExecutorMocks.recordTaskRunProgressByRunId.mock.calls[callIndex]?.[0];
|
||||
expect(typeof call).toBe("object");
|
||||
expect(call).not.toBeNull();
|
||||
return call as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function taskCompleteCall(callIndex = 0): Record<string, unknown> {
|
||||
const call = taskExecutorMocks.completeTaskRunByRunId.mock.calls[callIndex]?.[0];
|
||||
expect(typeof call).toBe("object");
|
||||
expect(call).not.toBeNull();
|
||||
return call as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function wakeCompletionCall(callIndex = 0): Record<string, unknown> {
|
||||
const call =
|
||||
musicGenerateBackgroundMocks.wakeMusicGenerationTaskCompletion.mock.calls[callIndex]?.[0];
|
||||
expect(typeof call).toBe("object");
|
||||
expect(call).not.toBeNull();
|
||||
return call as Record<string, unknown>;
|
||||
}
|
||||
|
||||
describe("createMusicGenerateTool", () => {
|
||||
beforeEach(resetMusicGenerateMocks);
|
||||
|
||||
@@ -222,24 +261,16 @@ describe("createMusicGenerateTool", () => {
|
||||
throw new Error("expected music_generate tool");
|
||||
}
|
||||
|
||||
await expect(
|
||||
tool.execute("call-1", {
|
||||
prompt: "night-drive synthwave",
|
||||
instrumental: true,
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
details: {
|
||||
instrumental: true,
|
||||
provider: "google",
|
||||
paths: ["/tmp/generated-night-drive.mp3"],
|
||||
},
|
||||
const result = await tool.execute("call-1", {
|
||||
prompt: "night-drive synthwave",
|
||||
instrumental: true,
|
||||
});
|
||||
const details = detailsOf(result);
|
||||
expect(details.instrumental).toBe(true);
|
||||
expect(details.provider).toBe("google");
|
||||
expect(details.paths).toEqual(["/tmp/generated-night-drive.mp3"]);
|
||||
expect(listProviders).not.toHaveBeenCalled();
|
||||
expect(musicGenerationRuntime.generateMusic).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
autoProviderFallback: false,
|
||||
}),
|
||||
);
|
||||
expect(generateMusicOptions().autoProviderFallback).toBe(false);
|
||||
});
|
||||
|
||||
it("generates tracks, saves them, and emits MEDIA paths without a session-backed detach", async () => {
|
||||
@@ -308,18 +339,17 @@ describe("createMusicGenerateTool", () => {
|
||||
expect(text).toContain("Generated 1 track with google/lyria-3-clip-preview.");
|
||||
expect(text).toContain("Lyrics returned.");
|
||||
expect(text).toContain("MEDIA:/tmp/generated-night-drive.mp3");
|
||||
expect(result.details).toMatchObject({
|
||||
provider: "google",
|
||||
model: "lyria-3-clip-preview",
|
||||
count: 1,
|
||||
instrumental: true,
|
||||
lyrics: ["wake the city up"],
|
||||
media: {
|
||||
mediaUrls: ["/tmp/generated-night-drive.mp3"],
|
||||
},
|
||||
paths: ["/tmp/generated-night-drive.mp3"],
|
||||
metadata: { taskId: "music-task-1" },
|
||||
});
|
||||
const details = detailsOf(result);
|
||||
expect(details.provider).toBe("google");
|
||||
expect(details.model).toBe("lyria-3-clip-preview");
|
||||
expect(details.count).toBe(1);
|
||||
expect(details.instrumental).toBe(true);
|
||||
expect(details.lyrics).toEqual(["wake the city up"]);
|
||||
expect((details.media as { mediaUrls?: unknown }).mediaUrls).toEqual([
|
||||
"/tmp/generated-night-drive.mp3",
|
||||
]);
|
||||
expect(details.paths).toEqual(["/tmp/generated-night-drive.mp3"]);
|
||||
expect(details.metadata).toEqual({ taskId: "music-task-1" });
|
||||
expect(taskExecutorMocks.createRunningTaskRun).not.toHaveBeenCalled();
|
||||
expect(taskExecutorMocks.completeTaskRunByRunId).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -364,21 +394,17 @@ describe("createMusicGenerateTool", () => {
|
||||
});
|
||||
const text = (result.content?.[0] as { text: string } | undefined)?.text ?? "";
|
||||
|
||||
expect(generateSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
autoProviderFallback: false,
|
||||
timeoutMs: 10_000,
|
||||
}),
|
||||
);
|
||||
expect(generateSpy).toHaveBeenCalledTimes(1);
|
||||
expect(generateMusicOptions().autoProviderFallback).toBe(false);
|
||||
expect(generateMusicOptions().timeoutMs).toBe(10_000);
|
||||
expect(text).toContain("Timeout normalized: requested 1000ms; used 10000ms.");
|
||||
expect(result.details).toMatchObject({
|
||||
timeoutMs: 10_000,
|
||||
requestedTimeoutMs: 1000,
|
||||
timeoutNormalization: {
|
||||
requested: 1000,
|
||||
applied: 10_000,
|
||||
minimum: 10_000,
|
||||
},
|
||||
const details = detailsOf(result);
|
||||
expect(details.timeoutMs).toBe(10_000);
|
||||
expect(details.requestedTimeoutMs).toBe(1000);
|
||||
expect(details.timeoutNormalization).toEqual({
|
||||
requested: 1000,
|
||||
applied: 10_000,
|
||||
minimum: 10_000,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -451,51 +477,33 @@ describe("createMusicGenerateTool", () => {
|
||||
expect(text).toContain("Background task started for music generation (task-123).");
|
||||
expect(text).toContain("Do not call music_generate again for this request.");
|
||||
expect(text).toContain("Timeout normalized: requested 1000ms; used 10000ms.");
|
||||
expect(result.details).toMatchObject({
|
||||
async: true,
|
||||
status: "started",
|
||||
task: {
|
||||
taskId: "task-123",
|
||||
},
|
||||
instrumental: true,
|
||||
timeoutMs: 10_000,
|
||||
requestedTimeoutMs: 1000,
|
||||
timeoutNormalization: {
|
||||
requested: 1000,
|
||||
applied: 10_000,
|
||||
minimum: 10_000,
|
||||
},
|
||||
const details = detailsOf(result);
|
||||
expect(details.async).toBe(true);
|
||||
expect(details.status).toBe("started");
|
||||
expect((details.task as { taskId?: unknown }).taskId).toBe("task-123");
|
||||
expect(details.instrumental).toBe(true);
|
||||
expect(details.timeoutMs).toBe(10_000);
|
||||
expect(details.requestedTimeoutMs).toBe(1000);
|
||||
expect(details.timeoutNormalization).toEqual({
|
||||
requested: 1000,
|
||||
applied: 10_000,
|
||||
minimum: 10_000,
|
||||
});
|
||||
if (!scheduledWork) {
|
||||
throw new Error("expected scheduled music generation work");
|
||||
}
|
||||
await scheduledWork();
|
||||
expect(musicGenerationRuntime.generateMusic).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
autoProviderFallback: false,
|
||||
timeoutMs: 10_000,
|
||||
}),
|
||||
);
|
||||
expect(taskExecutorMocks.recordTaskRunProgressByRunId).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
runId: expect.stringMatching(/^tool:music_generate:/),
|
||||
progressSummary: "Generating music",
|
||||
}),
|
||||
);
|
||||
expect(taskExecutorMocks.completeTaskRunByRunId).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
runId: expect.stringMatching(/^tool:music_generate:/),
|
||||
}),
|
||||
);
|
||||
expect(wakeSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
handle: expect.objectContaining({
|
||||
taskId: "task-123",
|
||||
}),
|
||||
status: "ok",
|
||||
result: expect.stringContaining("MEDIA:/tmp/generated-night-drive.mp3"),
|
||||
}),
|
||||
);
|
||||
expect(generateMusicOptions().autoProviderFallback).toBe(false);
|
||||
expect(generateMusicOptions().timeoutMs).toBe(10_000);
|
||||
const progress = taskProgressCall();
|
||||
expect(String(progress.runId)).toMatch(/^tool:music_generate:/);
|
||||
expect(progress.progressSummary).toBe("Generating music");
|
||||
expect(String(taskCompleteCall().runId)).toMatch(/^tool:music_generate:/);
|
||||
expect(wakeSpy).toHaveBeenCalledTimes(1);
|
||||
const wake = wakeCompletionCall();
|
||||
expect((wake.handle as { taskId?: unknown }).taskId).toBe("task-123");
|
||||
expect(wake.status).toBe("ok");
|
||||
expect(wake.result).toContain("MEDIA:/tmp/generated-night-drive.mp3");
|
||||
});
|
||||
|
||||
it("lists provider capabilities", async () => {
|
||||
@@ -608,19 +616,17 @@ describe("createMusicGenerateTool", () => {
|
||||
expect(text).toContain(
|
||||
"Warning: Ignored unsupported overrides for google/lyria-3-clip-preview: durationSeconds=30, format=wav.",
|
||||
);
|
||||
expect(result).toMatchObject({
|
||||
details: {
|
||||
instrumental: true,
|
||||
warning:
|
||||
"Ignored unsupported overrides for google/lyria-3-clip-preview: durationSeconds=30, format=wav.",
|
||||
ignoredOverrides: [
|
||||
{ key: "durationSeconds", value: 30 },
|
||||
{ key: "format", value: "wav" },
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(result.details).not.toHaveProperty("durationSeconds");
|
||||
expect(result.details).not.toHaveProperty("format");
|
||||
const details = detailsOf(result);
|
||||
expect(details.instrumental).toBe(true);
|
||||
expect(details.warning).toBe(
|
||||
"Ignored unsupported overrides for google/lyria-3-clip-preview: durationSeconds=30, format=wav.",
|
||||
);
|
||||
expect(details.ignoredOverrides).toEqual([
|
||||
{ key: "durationSeconds", value: 30 },
|
||||
{ key: "format", value: "wav" },
|
||||
]);
|
||||
expect(details).not.toHaveProperty("durationSeconds");
|
||||
expect(details).not.toHaveProperty("format");
|
||||
});
|
||||
|
||||
it("surfaces normalized durations from runtime metadata", async () => {
|
||||
@@ -674,14 +680,13 @@ describe("createMusicGenerateTool", () => {
|
||||
const text = (result.content?.[0] as { text: string } | undefined)?.text ?? "";
|
||||
|
||||
expect(text).toContain("Duration normalized: requested 45s; used 30s.");
|
||||
expect(result.details).toMatchObject({
|
||||
durationSeconds: 30,
|
||||
requestedDurationSeconds: 45,
|
||||
normalization: {
|
||||
durationSeconds: {
|
||||
requested: 45,
|
||||
applied: 30,
|
||||
},
|
||||
const details = detailsOf(result);
|
||||
expect(details.durationSeconds).toBe(30);
|
||||
expect(details.requestedDurationSeconds).toBe(45);
|
||||
expect(details.normalization).toEqual({
|
||||
durationSeconds: {
|
||||
requested: 45,
|
||||
applied: 30,
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -737,12 +742,14 @@ describe("createMusicGenerateTool", () => {
|
||||
image: "http://198.18.0.153/reference.png",
|
||||
});
|
||||
|
||||
expect(webMedia.loadWebMedia).toHaveBeenCalledWith(
|
||||
"http://198.18.0.153/reference.png",
|
||||
expect.objectContaining({
|
||||
requestInit: expect.objectContaining({ signal: expect.any(AbortSignal) }),
|
||||
ssrfPolicy: { allowRfc2544BenchmarkRange: true },
|
||||
}),
|
||||
);
|
||||
expect(webMedia.loadWebMedia).toHaveBeenCalledTimes(1);
|
||||
const loadCall = vi.mocked(webMedia.loadWebMedia).mock.calls[0];
|
||||
expect(loadCall?.[0]).toBe("http://198.18.0.153/reference.png");
|
||||
const loadOptions = loadCall?.[1] as {
|
||||
requestInit?: { signal?: unknown };
|
||||
ssrfPolicy?: unknown;
|
||||
};
|
||||
expect(loadOptions.requestInit?.signal).toBeInstanceOf(AbortSignal);
|
||||
expect(loadOptions.ssrfPolicy).toEqual({ allowRfc2544BenchmarkRange: true });
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user