mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-11-03 22:45:32 +08:00
96 lines
5.0 KiB
Java
96 lines
5.0 KiB
Java
package vip.mate.tts.provider;
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
import vip.mate.system.model.SystemSettingsDTO;
|
|
import vip.mate.tts.TtsRequest;
|
|
|
|
import java.net.URI;
|
|
import java.net.http.HttpClient;
|
|
import java.net.http.WebSocket;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.Arrays;
|
|
import java.util.concurrent.CompletableFuture;
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|
import static org.mockito.ArgumentMatchers.*;
|
|
import static org.mockito.Mockito.*;
|
|
|
|
class EdgeTtsProviderTest {
|
|
@Test
|
|
void hashesWindowsFileTimeInFiveMinuteBuckets() throws Exception {
|
|
assertEquals("492D7694A183A45E-56E821F95D4579C5B7C7E33DC7303FF379EC36D510213555BBBB9EB17EF15876",
|
|
EdgeTtsProvider.securityToken(java.time.Instant.ofEpochSecond(1791888000)));
|
|
assertEquals(EdgeTtsProvider.securityToken(java.time.Instant.EPOCH),
|
|
EdgeTtsProvider.securityToken(java.time.Instant.ofEpochSecond(299)));
|
|
assertNotEquals(EdgeTtsProvider.securityToken(java.time.Instant.EPOCH),
|
|
EdgeTtsProvider.securityToken(java.time.Instant.ofEpochSecond(300)));
|
|
}
|
|
|
|
@Test
|
|
void matchesUpstreamV2ReferenceVectors() {
|
|
// Values produced by upstream edge_tts.drm.generate_sec_ms_gec_v2.
|
|
assertEquals("52BC7A17B50DFEC9-28C4394775C8751CD2F6859C030C06DB1489ACAB3B3A7651831FC26895177ED6",
|
|
EdgeTtsProvider.securityToken(java.time.Instant.EPOCH));
|
|
assertEquals("F7535A20A262E331-28675BF85C7106BBF20035A78FCB0B6890813EAD5C3B983EF3424931B720BABB",
|
|
EdgeTtsProvider.securityToken(java.time.Instant.ofEpochSecond(300)));
|
|
assertEquals("2CD23A2CA0B2595A-F3C846C370E05F9CC83ACC5F995C5F5D87A4D0F14CE8936A0F902E64099E38A2",
|
|
EdgeTtsProvider.securityToken(java.time.Instant.ofEpochSecond(1700000000)));
|
|
}
|
|
|
|
@Test
|
|
void reportsHandshakeStatusWithoutExposingResponseUri() {
|
|
java.net.http.HttpResponse<?> response = mock(java.net.http.HttpResponse.class);
|
|
when(response.statusCode()).thenReturn(403);
|
|
var failure = new java.util.concurrent.CompletionException(
|
|
new java.net.http.WebSocketHandshakeException(response));
|
|
String message = EdgeTtsProvider.failureMessage(failure);
|
|
assertTrue(message.contains("HTTP 403"));
|
|
assertTrue(message.contains("系统时间"));
|
|
assertFalse(message.contains("TrustedClientToken"));
|
|
assertFalse(message.contains("Sec-MS-GEC"));
|
|
verify(response, never()).uri();
|
|
}
|
|
|
|
@Test
|
|
void usesCurrentHandshakeAndPreservesFragmentedAudio() {
|
|
HttpClient.Builder httpBuilder = mock(HttpClient.Builder.class, RETURNS_SELF);
|
|
HttpClient client = mock(HttpClient.class);
|
|
WebSocket.Builder wsBuilder = mock(WebSocket.Builder.class, RETURNS_SELF);
|
|
WebSocket socket = mock(WebSocket.class);
|
|
when(httpBuilder.build()).thenReturn(client);
|
|
when(client.newWebSocketBuilder()).thenReturn(wsBuilder);
|
|
AtomicReference<URI> endpoint = new AtomicReference<>();
|
|
AtomicReference<WebSocket.Listener> listener = new AtomicReference<>();
|
|
when(wsBuilder.buildAsync(any(), any())).thenAnswer(inv -> {
|
|
endpoint.set(inv.getArgument(0));
|
|
listener.set(inv.getArgument(1));
|
|
return CompletableFuture.completedFuture(socket);
|
|
});
|
|
when(socket.sendText(anyString(), eq(true))).thenAnswer(inv -> {
|
|
if (inv.<String>getArgument(0).contains("Path:ssml")) {
|
|
byte[] headers = "Path:audio\r\nContent-Type:audio/mpeg\r\n".getBytes(StandardCharsets.UTF_8);
|
|
byte[] packet = ByteBuffer.allocate(2 + headers.length + 4)
|
|
.putShort((short) headers.length).put(headers).put(new byte[]{1, 2, 3, 4}).array();
|
|
listener.get().onBinary(socket, ByteBuffer.wrap(Arrays.copyOfRange(packet, 0, 1)), false);
|
|
listener.get().onBinary(socket, ByteBuffer.wrap(Arrays.copyOfRange(packet, 1, packet.length)), true);
|
|
listener.get().onText(socket, "Path:turn.end\r\n", true);
|
|
}
|
|
return CompletableFuture.completedFuture(socket);
|
|
});
|
|
try (var clients = mockStatic(HttpClient.class)) {
|
|
clients.when(HttpClient::newBuilder).thenReturn(httpBuilder);
|
|
var result = new EdgeTtsProvider().synthesize(
|
|
TtsRequest.builder().text("Hello").build(), new SystemSettingsDTO());
|
|
assertEquals("/consumer/speech/synthesize/readaloud/edge/v1", endpoint.get().getPath());
|
|
assertTrue(endpoint.get().getQuery().matches(".*Sec-MS-GEC=[A-F0-9]{16}-[A-F0-9]{64}.*"));
|
|
assertTrue(endpoint.get().getQuery().contains("Sec-MS-GEC-Version=2-"));
|
|
assertTrue(result.isSuccess(), result.getErrorMessage());
|
|
assertArrayEquals(new byte[]{1, 2, 3, 4}, result.getAudioData());
|
|
verify(socket).abort();
|
|
verify(client).close();
|
|
}
|
|
}
|
|
}
|