mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 12:28:37 +00:00
test: expand talk config contract fixtures
This commit is contained in:
@@ -14,6 +14,7 @@ import org.junit.Test
|
|||||||
@Serializable
|
@Serializable
|
||||||
private data class TalkConfigContractFixture(
|
private data class TalkConfigContractFixture(
|
||||||
@SerialName("selectionCases") val selectionCases: List<SelectionCase>,
|
@SerialName("selectionCases") val selectionCases: List<SelectionCase>,
|
||||||
|
@SerialName("timeoutCases") val timeoutCases: List<TimeoutCase>,
|
||||||
) {
|
) {
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SelectionCase(
|
data class SelectionCase(
|
||||||
@@ -29,6 +30,15 @@ private data class TalkConfigContractFixture(
|
|||||||
val provider: String,
|
val provider: String,
|
||||||
val normalizedPayload: Boolean,
|
val normalizedPayload: Boolean,
|
||||||
val voiceId: String? = null,
|
val voiceId: String? = null,
|
||||||
|
val apiKey: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class TimeoutCase(
|
||||||
|
val id: String,
|
||||||
|
val fallback: Long,
|
||||||
|
val expectedTimeoutMs: Long,
|
||||||
|
val talk: JsonObject,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,10 +62,24 @@ class TalkModeConfigContractTest {
|
|||||||
expected.voiceId,
|
expected.voiceId,
|
||||||
(selection?.config?.get("voiceId") as? JsonPrimitive)?.content,
|
(selection?.config?.get("voiceId") as? JsonPrimitive)?.content,
|
||||||
)
|
)
|
||||||
|
assertEquals(
|
||||||
|
fixture.id,
|
||||||
|
expected.apiKey,
|
||||||
|
(selection?.config?.get("apiKey") as? JsonPrimitive)?.content,
|
||||||
|
)
|
||||||
assertEquals(fixture.id, true, fixture.payloadValid)
|
assertEquals(fixture.id, true, fixture.payloadValid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun timeoutFixtures() {
|
||||||
|
for (fixture in loadFixtures().timeoutCases) {
|
||||||
|
val timeout = TalkModeGatewayConfigParser.resolvedSilenceTimeoutMs(fixture.talk)
|
||||||
|
assertEquals(fixture.id, fixture.expectedTimeoutMs, timeout)
|
||||||
|
assertEquals(fixture.id, TalkDefaults.defaultSilenceTimeoutMs, fixture.fallback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadFixtures(): TalkConfigContractFixture {
|
private fun loadFixtures(): TalkConfigContractFixture {
|
||||||
val fixturePath = findFixtureFile()
|
val fixturePath = findFixtureFile()
|
||||||
return json.decodeFromString(File(fixturePath).readText())
|
return json.decodeFromString(File(fixturePath).readText())
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import Testing
|
|||||||
|
|
||||||
private struct TalkConfigContractFixture: Decodable {
|
private struct TalkConfigContractFixture: Decodable {
|
||||||
let selectionCases: [SelectionCase]
|
let selectionCases: [SelectionCase]
|
||||||
|
let timeoutCases: [TimeoutCase]
|
||||||
|
|
||||||
struct SelectionCase: Decodable {
|
struct SelectionCase: Decodable {
|
||||||
let id: String
|
let id: String
|
||||||
@@ -17,6 +18,14 @@ private struct TalkConfigContractFixture: Decodable {
|
|||||||
let provider: String
|
let provider: String
|
||||||
let normalizedPayload: Bool
|
let normalizedPayload: Bool
|
||||||
let voiceId: String?
|
let voiceId: String?
|
||||||
|
let apiKey: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TimeoutCase: Decodable {
|
||||||
|
let id: String
|
||||||
|
let fallback: Int
|
||||||
|
let expectedTimeoutMs: Int
|
||||||
|
let talk: [String: AnyCodable]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,10 +60,21 @@ struct TalkConfigContractTests {
|
|||||||
#expect(selection?.provider == expected.provider)
|
#expect(selection?.provider == expected.provider)
|
||||||
#expect(selection?.normalizedPayload == expected.normalizedPayload)
|
#expect(selection?.normalizedPayload == expected.normalizedPayload)
|
||||||
#expect(selection?.config["voiceId"]?.stringValue == expected.voiceId)
|
#expect(selection?.config["voiceId"]?.stringValue == expected.voiceId)
|
||||||
|
#expect(selection?.config["apiKey"]?.stringValue == expected.apiKey)
|
||||||
} else {
|
} else {
|
||||||
#expect(selection == nil)
|
#expect(selection == nil)
|
||||||
}
|
}
|
||||||
#expect(fixture.payloadValid == (selection != nil))
|
#expect(fixture.payloadValid == (selection != nil))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test func timeoutFixtures() throws {
|
||||||
|
for fixture in try TalkConfigContractFixtureLoader.load().timeoutCases {
|
||||||
|
#expect(
|
||||||
|
TalkConfigParsing.resolvedSilenceTimeoutMs(
|
||||||
|
fixture.talk,
|
||||||
|
fallback: fixture.fallback) == fixture.expectedTimeoutMs,
|
||||||
|
"\(fixture.id)")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { buildTalkConfigResponse } from "../../config/talk.js";
|
||||||
import { validateTalkConfigResult } from "./index.js";
|
import { validateTalkConfigResult } from "./index.js";
|
||||||
|
|
||||||
type ExpectedSelection = {
|
type ExpectedSelection = {
|
||||||
provider: string;
|
provider: string;
|
||||||
normalizedPayload: boolean;
|
normalizedPayload: boolean;
|
||||||
voiceId?: string;
|
voiceId?: string;
|
||||||
|
apiKey?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SelectionContractCase = {
|
type SelectionContractCase = {
|
||||||
@@ -16,8 +18,16 @@ type SelectionContractCase = {
|
|||||||
talk: Record<string, unknown>;
|
talk: Record<string, unknown>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type TimeoutContractCase = {
|
||||||
|
id: string;
|
||||||
|
fallback: number;
|
||||||
|
expectedTimeoutMs: number;
|
||||||
|
talk: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
|
||||||
type TalkConfigContractFixture = {
|
type TalkConfigContractFixture = {
|
||||||
selectionCases: SelectionContractCase[];
|
selectionCases: SelectionContractCase[];
|
||||||
|
timeoutCases: TimeoutContractCase[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const fixturePath = new URL("../../../test-fixtures/talk-config-contract.json", import.meta.url);
|
const fixturePath = new URL("../../../test-fixtures/talk-config-contract.json", import.meta.url);
|
||||||
@@ -42,9 +52,11 @@ describe("talk.config contract fixtures", () => {
|
|||||||
provider?: string;
|
provider?: string;
|
||||||
config?: {
|
config?: {
|
||||||
voiceId?: string;
|
voiceId?: string;
|
||||||
|
apiKey?: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
voiceId?: string;
|
voiceId?: string;
|
||||||
|
apiKey?: string;
|
||||||
};
|
};
|
||||||
expect(talk.resolved?.provider ?? fixture.defaultProvider).toBe(
|
expect(talk.resolved?.provider ?? fixture.defaultProvider).toBe(
|
||||||
fixture.expectedSelection.provider,
|
fixture.expectedSelection.provider,
|
||||||
@@ -52,6 +64,14 @@ describe("talk.config contract fixtures", () => {
|
|||||||
expect(talk.resolved?.config?.voiceId ?? talk.voiceId).toBe(
|
expect(talk.resolved?.config?.voiceId ?? talk.voiceId).toBe(
|
||||||
fixture.expectedSelection.voiceId,
|
fixture.expectedSelection.voiceId,
|
||||||
);
|
);
|
||||||
|
expect(talk.resolved?.config?.apiKey ?? talk.apiKey).toBe(fixture.expectedSelection.apiKey);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const fixture of fixtures.timeoutCases) {
|
||||||
|
it(`timeout:${fixture.id}`, () => {
|
||||||
|
const payload = buildTalkConfigResponse(fixture.talk);
|
||||||
|
expect(payload?.silenceTimeoutMs ?? fixture.fallback).toBe(fixture.expectedTimeoutMs);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,22 +7,26 @@
|
|||||||
"expectedSelection": {
|
"expectedSelection": {
|
||||||
"provider": "elevenlabs",
|
"provider": "elevenlabs",
|
||||||
"normalizedPayload": true,
|
"normalizedPayload": true,
|
||||||
"voiceId": "voice-resolved"
|
"voiceId": "voice-resolved",
|
||||||
|
"apiKey": "resolved-key"
|
||||||
},
|
},
|
||||||
"talk": {
|
"talk": {
|
||||||
"resolved": {
|
"resolved": {
|
||||||
"provider": "elevenlabs",
|
"provider": "elevenlabs",
|
||||||
"config": {
|
"config": {
|
||||||
"voiceId": "voice-resolved"
|
"voiceId": "voice-resolved",
|
||||||
|
"apiKey": "resolved-key"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"provider": "elevenlabs",
|
"provider": "elevenlabs",
|
||||||
"providers": {
|
"providers": {
|
||||||
"elevenlabs": {
|
"elevenlabs": {
|
||||||
"voiceId": "voice-normalized"
|
"voiceId": "voice-normalized",
|
||||||
|
"apiKey": "normalized-key"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"voiceId": "voice-legacy"
|
"voiceId": "voice-legacy",
|
||||||
|
"apiKey": "legacy-key"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -77,12 +81,63 @@
|
|||||||
"expectedSelection": {
|
"expectedSelection": {
|
||||||
"provider": "elevenlabs",
|
"provider": "elevenlabs",
|
||||||
"normalizedPayload": false,
|
"normalizedPayload": false,
|
||||||
"voiceId": "voice-legacy"
|
"voiceId": "voice-legacy",
|
||||||
|
"apiKey": "legacy-key"
|
||||||
},
|
},
|
||||||
"talk": {
|
"talk": {
|
||||||
"voiceId": "voice-legacy",
|
"voiceId": "voice-legacy",
|
||||||
"apiKey": "xxxxx"
|
"apiKey": "xxxxx"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"timeoutCases": [
|
||||||
|
{
|
||||||
|
"id": "integer_timeout_kept",
|
||||||
|
"fallback": 700,
|
||||||
|
"expectedTimeoutMs": 1500,
|
||||||
|
"talk": {
|
||||||
|
"silenceTimeoutMs": 1500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "integer_like_double_timeout_kept",
|
||||||
|
"fallback": 700,
|
||||||
|
"expectedTimeoutMs": 1500,
|
||||||
|
"talk": {
|
||||||
|
"silenceTimeoutMs": 1500.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "zero_timeout_falls_back",
|
||||||
|
"fallback": 700,
|
||||||
|
"expectedTimeoutMs": 700,
|
||||||
|
"talk": {
|
||||||
|
"silenceTimeoutMs": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "boolean_timeout_falls_back",
|
||||||
|
"fallback": 700,
|
||||||
|
"expectedTimeoutMs": 700,
|
||||||
|
"talk": {
|
||||||
|
"silenceTimeoutMs": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "string_timeout_falls_back",
|
||||||
|
"fallback": 700,
|
||||||
|
"expectedTimeoutMs": 700,
|
||||||
|
"talk": {
|
||||||
|
"silenceTimeoutMs": "1500"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "fractional_timeout_falls_back",
|
||||||
|
"fallback": 700,
|
||||||
|
"expectedTimeoutMs": 700,
|
||||||
|
"talk": {
|
||||||
|
"silenceTimeoutMs": 1500.5
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user