diff --git a/sdk/transcription/azure-ai-speech-transcription/assets.json b/sdk/transcription/azure-ai-speech-transcription/assets.json index 5c6f05bf06f2..0678580b84a5 100644 --- a/sdk/transcription/azure-ai-speech-transcription/assets.json +++ b/sdk/transcription/azure-ai-speech-transcription/assets.json @@ -1 +1,6 @@ -{"AssetsRepo":"Azure/azure-sdk-assets","AssetsRepoPrefixPath":"java","TagPrefix":"java/transcription/azure-ai-speech-transcription","Tag": "java/transcription/azure-ai-speech-transcription_c82ca4aec0"} +{ + "AssetsRepo": "Azure/azure-sdk-assets", + "AssetsRepoPrefixPath": "java", + "TagPrefix": "java/transcription/azure-ai-speech-transcription", + "Tag": "java/transcription/azure-ai-speech-transcription_c82ca4aec0" +} diff --git a/sdk/transcription/azure-ai-speech-transcription/pom.xml b/sdk/transcription/azure-ai-speech-transcription/pom.xml index 993a6f6163eb..95f0578d6489 100644 --- a/sdk/transcription/azure-ai-speech-transcription/pom.xml +++ b/sdk/transcription/azure-ai-speech-transcription/pom.xml @@ -68,4 +68,23 @@ Code generated by Microsoft (R) TypeSpec Code Generator. test + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.5.3 + + + + + 300000 + 300000 + 300000 + + + + + diff --git a/sdk/transcription/azure-ai-speech-transcription/src/test/java/com/azure/ai/speech/transcription/TranscriptionAsyncClientTest.java b/sdk/transcription/azure-ai-speech-transcription/src/test/java/com/azure/ai/speech/transcription/TranscriptionAsyncClientTest.java index 2d46371ee25d..c7caaaf99383 100644 --- a/sdk/transcription/azure-ai-speech-transcription/src/test/java/com/azure/ai/speech/transcription/TranscriptionAsyncClientTest.java +++ b/sdk/transcription/azure-ai-speech-transcription/src/test/java/com/azure/ai/speech/transcription/TranscriptionAsyncClientTest.java @@ -6,19 +6,30 @@ import com.azure.ai.speech.transcription.models.ProfanityFilterMode; import com.azure.ai.speech.transcription.models.TranscriptionDiarizationOptions; import com.azure.ai.speech.transcription.models.TranscriptionOptions; +import com.azure.ai.speech.transcription.models.TranscriptionResult; import com.azure.core.exception.HttpResponseException; import com.azure.core.http.HttpHeaderName; import com.azure.core.http.rest.RequestOptions; +import com.azure.core.util.BinaryData; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import reactor.test.StepVerifier; import java.util.Arrays; +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.fail; /** * Tests for TranscriptionAsyncClient (asynchronous client). */ class TranscriptionAsyncClientTest extends TranscriptionClientTestBase { + private TranscriptionAsyncClient client; - private final Boolean sync = false; // All tests in this file use the async client + @BeforeEach + public void setupTest() { + this.client = configureBuilder(true, true).buildAsyncClient(); + } /*********************************************************************************** * @@ -28,184 +39,95 @@ class TranscriptionAsyncClientTest extends TranscriptionClientTestBase { @Test public void testTranscribeAsyncBasicFromFile() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options = new TranscriptionOptions((String) null); - - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeAsyncBasicFromFile", fromAudioFile()); } @Test public void testTranscribeAsyncWithLanguageFromFile() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options = new TranscriptionOptions((String) null).setLocales(Arrays.asList("en-US")); - - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeAsyncWithLanguageFromFile", + fromAudioFile().setLocales(Collections.singletonList("en-US"))); } @Test public void testTranscribeAsyncWithMultipleLanguagesFromFile() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options - = new TranscriptionOptions((String) null).setLocales(Arrays.asList("en-US", "es-ES", "fr-FR")); - - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeAsyncWithMultipleLanguagesFromFile", + fromAudioFile().setLocales(Arrays.asList("en-US", "es-ES", "fr-FR"))); } @Test public void testTranscribeAsyncWithDiarizationFromFile() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionDiarizationOptions diarizationOptions = new TranscriptionDiarizationOptions().setMaxSpeakers(5); - - TranscriptionOptions options - = new TranscriptionOptions((String) null).setDiarizationOptions(diarizationOptions); - - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeAsyncWithDiarizationFromFile", + fromAudioFile().setDiarizationOptions(new TranscriptionDiarizationOptions().setMaxSpeakers(5))); } @Test public void testTranscribeAsyncWithProfanityFilterFromFile() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options - = new TranscriptionOptions((String) null).setProfanityFilterMode(ProfanityFilterMode.MASKED); - - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeAsyncWithProfanityFilterFromFile", + fromAudioFile().setProfanityFilterMode(ProfanityFilterMode.MASKED)); } @Test public void testTranscribeAsyncWithChannelsFromFile() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options = new TranscriptionOptions((String) null).setActiveChannels(Arrays.asList(0)); - - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeAsyncWithChannelsFromFile", + fromAudioFile().setActiveChannels(Collections.singletonList(0))); } @Test public void testTranscribeAsyncAllOptionsFromFile() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionDiarizationOptions diarizationOptions = new TranscriptionDiarizationOptions().setMaxSpeakers(5); - - TranscriptionOptions options = new TranscriptionOptions((String) null).setLocales(Arrays.asList("en-US")) - .setDiarizationOptions(diarizationOptions) + TranscriptionOptions options = fromAudioFile().setLocales(Collections.singletonList("en-US")) + .setDiarizationOptions(new TranscriptionDiarizationOptions().setMaxSpeakers(5)) .setProfanityFilterMode(ProfanityFilterMode.MASKED) - .setActiveChannels(Arrays.asList(0)); + .setActiveChannels(Collections.singletonList(0)); - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeAsyncAllOptionsFromFile", options); } @Test public void testTranscribeAsyncBasicFromFileWithResponse() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options = new TranscriptionOptions((String) null); - RequestOptions requestOptions - = new RequestOptions().addHeader(HttpHeaderName.fromString("x-custom-header"), "custom-value"); - - doTranscription(methodName, sync, true, audioFile, options, requestOptions); + transcribeAndVerifyResponse("testTranscribeAsyncBasicFromFileWithResponse", fromAudioFile(), + new RequestOptions().addHeader(HttpHeaderName.fromString("x-custom-header"), "custom-value")); } @Test public void testTranscribeAsyncWithAllOptionsFromFileWithResponse() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionDiarizationOptions diarizationOptions = new TranscriptionDiarizationOptions().setMaxSpeakers(5); - - TranscriptionOptions options - = new TranscriptionOptions((String) null).setLocales(Arrays.asList("en-US", "es-ES")) - .setDiarizationOptions(diarizationOptions) - .setProfanityFilterMode(ProfanityFilterMode.REMOVED) - .setActiveChannels(Arrays.asList(0, 1)); + TranscriptionOptions options = fromAudioFile().setLocales(Arrays.asList("en-US", "es-ES")) + .setDiarizationOptions(new TranscriptionDiarizationOptions().setMaxSpeakers(5)) + .setProfanityFilterMode(ProfanityFilterMode.REMOVED) + .setActiveChannels(Arrays.asList(0, 1)); RequestOptions requestOptions = new RequestOptions().addHeader(HttpHeaderName.fromString("x-custom-header"), "custom-value") .addQueryParam("test-param", "test-value"); - doTranscription(methodName, sync, true, audioFile, options, requestOptions); + transcribeAndVerifyResponse("testTranscribeAsyncWithAllOptionsFromFileWithResponse", options, requestOptions); } @Test public void testTranscribeAsyncWithAudioUrl() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - // Using a publicly accessible sample audio file from Azure samples String audioUrl = "https://raw.githubusercontent.com/Azure-Samples/cognitive-services-speech-sdk/master/sampledata/audiofiles/aboutSpeechSdk.wav"; - TranscriptionOptions options = new TranscriptionOptions(audioUrl).setLocales(Arrays.asList("en-US")); - // For URL-based transcription, we don't pass the local audio file path - doTranscriptionWithUrl(methodName, sync, options); + transcribeAndVerifyResult("testTranscribeAsyncWithAudioUrl", + new TranscriptionOptions(audioUrl).setLocales(Collections.singletonList("en-US"))); } @Test public void testTranscribeAsyncWithProfanityModeMasked() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options - = new TranscriptionOptions((String) null).setProfanityFilterMode(ProfanityFilterMode.MASKED); - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeAsyncWithProfanityModeMasked", + fromAudioFile().setProfanityFilterMode(ProfanityFilterMode.MASKED)); } @Test public void testTranscribeAsyncWithProfanityModeRemoved() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options - = new TranscriptionOptions((String) null).setProfanityFilterMode(ProfanityFilterMode.REMOVED); - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeAsyncWithProfanityModeTags", + fromAudioFile().setProfanityFilterMode(ProfanityFilterMode.REMOVED)); } @Test public void testTranscribeAsyncWithProfanityModeTags() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options - = new TranscriptionOptions((String) null).setProfanityFilterMode(ProfanityFilterMode.TAGS); - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeAsyncWithProfanityModeTags", + fromAudioFile().setProfanityFilterMode(ProfanityFilterMode.TAGS)); } /*********************************************************************************** @@ -216,58 +138,47 @@ public void testTranscribeAsyncWithProfanityModeTags() { @Test public void testTranscribeAsyncWithEmptyAudioData() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - // Test with minimal audio data - service should handle gracefully - TranscriptionOptions options = new TranscriptionOptions((String) null); - - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeAsyncWithEmptyAudioData", fromAudioFile()); } @Test public void testTranscribeAsyncWithInvalidLanguageCode() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - // Use invalid language code to trigger service error - TranscriptionOptions options - = new TranscriptionOptions((String) null).setLocales(Arrays.asList("invalid-locale-code")); + TranscriptionOptions options = fromAudioFile().setLocales(Collections.singletonList("invalid-locale-code")); // The service should return a 400 error for invalid locale // doTranscription wraps exceptions in RuntimeException, so we catch that - try { - doTranscription(methodName, sync, false, audioFile, options, null); - // Should not reach here - the above should throw an exception - throw new AssertionError("Expected RuntimeException with HttpResponseException cause but none was thrown"); - } catch (RuntimeException e) { + StepVerifier.create(client.transcribe(options)).verifyErrorSatisfies(e -> { // Expected behavior - verify the cause is HttpResponseException with 400 status - if (!(e.getCause() instanceof HttpResponseException)) { - throw new AssertionError( - "Expected RuntimeException cause to be HttpResponseException but got: " + e.getCause().getClass()); + if (!(e instanceof HttpResponseException)) { + fail("Expected RuntimeException cause to be HttpResponseException but got: " + e.getClass()); } - HttpResponseException httpException = (HttpResponseException) e.getCause(); + HttpResponseException httpException = (HttpResponseException) e; if (httpException.getResponse().getStatusCode() != 400) { - throw new AssertionError( - "Expected 400 status code but got: " + httpException.getResponse().getStatusCode()); + fail("Expected 400 status code but got: " + httpException.getResponse().getStatusCode()); } - } + }); } @Test public void testTranscribeAsyncCancellation() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - // Test cancellation behavior with a normal transcription request - TranscriptionOptions options = new TranscriptionOptions((String) null); + transcribeAndVerifyResult("testTranscribeAsyncCancellation", fromAudioFile()); + } + + private void transcribeAndVerifyResult(String testName, TranscriptionOptions options) { + StepVerifier.create(client.transcribe(options)) + .assertNext(result -> validateTranscriptionResult(testName, result)) + .verifyComplete(); + } - doTranscription(methodName, sync, false, audioFile, options, null); + private void transcribeAndVerifyResponse(String testName, TranscriptionOptions options, + RequestOptions requestOptions) { + BinaryData multipartBody = createMultipartBody(options, requestOptions); + StepVerifier.create(client.transcribeWithResponse(multipartBody, requestOptions)).assertNext(response -> { + printHttpRequestAndResponse(response); + validateTranscriptionResult(testName, response.getValue().toObject(TranscriptionResult.class)); + }).verifyComplete(); } } diff --git a/sdk/transcription/azure-ai-speech-transcription/src/test/java/com/azure/ai/speech/transcription/TranscriptionClientTest.java b/sdk/transcription/azure-ai-speech-transcription/src/test/java/com/azure/ai/speech/transcription/TranscriptionClientTest.java index 0d9b261ccf44..bfa8eea77130 100644 --- a/sdk/transcription/azure-ai-speech-transcription/src/test/java/com/azure/ai/speech/transcription/TranscriptionClientTest.java +++ b/sdk/transcription/azure-ai-speech-transcription/src/test/java/com/azure/ai/speech/transcription/TranscriptionClientTest.java @@ -6,11 +6,16 @@ import com.azure.ai.speech.transcription.models.ProfanityFilterMode; import com.azure.ai.speech.transcription.models.TranscriptionDiarizationOptions; import com.azure.ai.speech.transcription.models.TranscriptionOptions; +import com.azure.ai.speech.transcription.models.TranscriptionResult; import com.azure.core.http.HttpHeaderName; import com.azure.core.http.rest.RequestOptions; +import com.azure.core.http.rest.Response; +import com.azure.core.util.BinaryData; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.util.Arrays; +import java.util.Collections; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -18,8 +23,12 @@ * Tests for TranscriptionClient (synchronous client). */ class TranscriptionClientTest extends TranscriptionClientTestBase { + private TranscriptionClient client; - private final Boolean sync = true; // All tests in this file use the sync client + @BeforeEach + public void setupTest() { + this.client = configureBuilder(true, true).buildClient(); + } /*********************************************************************************** * @@ -29,161 +38,84 @@ class TranscriptionClientTest extends TranscriptionClientTestBase { @Test public void testTranscribeSyncBasicFromFile() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options = new TranscriptionOptions((String) null); - - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeSyncBasicFromFile", fromAudioFile()); } @Test public void testTranscribeSyncWithLanguageFromFile() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options = new TranscriptionOptions((String) null).setLocales(Arrays.asList("en-US")); - - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeSyncWithLanguageFromFile", + fromAudioFile().setLocales(Collections.singletonList("en-US"))); } @Test public void testTranscribeSyncWithMultipleLanguagesFromFile() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options - = new TranscriptionOptions((String) null).setLocales(Arrays.asList("en-US", "es-ES", "fr-FR")); - - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeSyncWithMultipleLanguagesFromFile", + fromAudioFile().setLocales(Arrays.asList("en-US", "es-ES", "fr-FR"))); } @Test public void testTranscribeSyncWithDiarizationFromFile() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionDiarizationOptions diarizationOptions = new TranscriptionDiarizationOptions().setMaxSpeakers(5); - - TranscriptionOptions options - = new TranscriptionOptions((String) null).setDiarizationOptions(diarizationOptions); - - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeSyncWithDiarizationFromFile", + fromAudioFile().setDiarizationOptions(new TranscriptionDiarizationOptions().setMaxSpeakers(5))); } @Test public void testTranscribeSyncWithProfanityFilterFromFile() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options - = new TranscriptionOptions((String) null).setProfanityFilterMode(ProfanityFilterMode.MASKED); - - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeSyncWithProfanityFilterFromFile", + fromAudioFile().setProfanityFilterMode(ProfanityFilterMode.MASKED)); } @Test public void testTranscribeSyncWithChannelsFromFile() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options = new TranscriptionOptions((String) null).setActiveChannels(Arrays.asList(0)); - - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeSyncWithChannelsFromFile", + fromAudioFile().setActiveChannels(Collections.singletonList(0))); } @Test public void testTranscribeSyncAllOptionsFromFile() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionDiarizationOptions diarizationOptions = new TranscriptionDiarizationOptions().setMaxSpeakers(5); - - TranscriptionOptions options = new TranscriptionOptions((String) null).setLocales(Arrays.asList("en-US")) - .setDiarizationOptions(diarizationOptions) + TranscriptionOptions options = fromAudioFile().setLocales(Collections.singletonList("en-US")) + .setDiarizationOptions(new TranscriptionDiarizationOptions().setMaxSpeakers(5)) .setProfanityFilterMode(ProfanityFilterMode.MASKED) - .setActiveChannels(Arrays.asList(0)); + .setActiveChannels(Collections.singletonList(0)); - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeSyncAllOptionsFromFile", options); } @Test public void testTranscribeSyncBasicFromFileWithResponse() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options = new TranscriptionOptions((String) null); - RequestOptions requestOptions - = new RequestOptions().addHeader(HttpHeaderName.fromString("x-custom-header"), "custom-value"); - - doTranscription(methodName, sync, true, audioFile, options, requestOptions); + transcribeAndVerifyResponse("testTranscribeSyncBasicFromFileWithResponse", fromAudioFile(), + new RequestOptions().addHeader(HttpHeaderName.fromString("x-custom-header"), "custom-value")); } @Test public void testTranscribeSyncWithAllOptionsFromFileWithResponse() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionDiarizationOptions diarizationOptions = new TranscriptionDiarizationOptions().setMaxSpeakers(5); - - TranscriptionOptions options - = new TranscriptionOptions((String) null).setLocales(Arrays.asList("en-US", "es-ES")) - .setDiarizationOptions(diarizationOptions) - .setProfanityFilterMode(ProfanityFilterMode.REMOVED) - .setActiveChannels(Arrays.asList(0, 1)); + TranscriptionOptions options = fromAudioFile().setLocales(Arrays.asList("en-US", "es-ES")) + .setDiarizationOptions(new TranscriptionDiarizationOptions().setMaxSpeakers(5)) + .setProfanityFilterMode(ProfanityFilterMode.REMOVED) + .setActiveChannels(Arrays.asList(0, 1)); RequestOptions requestOptions = new RequestOptions().addHeader(HttpHeaderName.fromString("x-custom-header"), "custom-value") .addQueryParam("test-param", "test-value"); - doTranscription(methodName, sync, true, audioFile, options, requestOptions); + transcribeAndVerifyResponse("testTranscribeSyncWithAllOptionsFromFileWithResponse", options, requestOptions); } @Test public void testTranscribeSyncWithMultipleChannels() { // Test with multiple channel indices - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - - TranscriptionOptions options = new TranscriptionOptions((String) null).setActiveChannels(Arrays.asList(0, 1)); - - doTranscription(methodName, sync, false, audioFile, options, null); + transcribeAndVerifyResult("testTranscribeSyncWithMultipleChannels", + fromAudioFile().setActiveChannels(Arrays.asList(0, 1))); } @Test public void testTranscribeSyncWithAudioUrl() { - createClient(true, true, sync); - - String methodName = new Object() { - }.getClass().getEnclosingMethod().getName(); - // Using a publicly accessible sample audio file from Azure samples String audioUrl = "https://raw.githubusercontent.com/Azure-Samples/cognitive-services-speech-sdk/master/sampledata/audiofiles/aboutSpeechSdk.wav"; - TranscriptionOptions options = new TranscriptionOptions(audioUrl).setLocales(Arrays.asList("en-US")); - // For URL-based transcription, we don't pass the local audio file path - doTranscriptionWithUrl(methodName, sync, options); + transcribeAndVerifyResult("testTranscribeSyncWithAudioUrl", + new TranscriptionOptions(audioUrl).setLocales(Collections.singletonList("en-US"))); } /*********************************************************************************** @@ -194,18 +126,13 @@ public void testTranscribeSyncWithAudioUrl() { @Test public void testTranscribeSyncWithNullOptions() { - createClient(true, true, sync); - // Test that null options throws appropriate exception - assertThrows(NullPointerException.class, () -> { - getClient().transcribe((TranscriptionOptions) null); - }, "Transcribe should throw NullPointerException when options is null"); + assertThrows(NullPointerException.class, () -> client.transcribe((TranscriptionOptions) null), + "Transcribe should throw NullPointerException when options is null"); } @Test public void testTranscribeSyncWithEmptyAudioData() { - createClient(true, true, sync); - // Test with empty audio data - this should result in a service error // Note: Depending on service behavior, this may throw HttpResponseException // The exact behavior should be validated based on actual service responses @@ -213,8 +140,6 @@ public void testTranscribeSyncWithEmptyAudioData() { @Test public void testTranscribeSyncWithInvalidLanguageCode() { - createClient(true, true, sync); - // Note: This test requires actual service call to verify behavior // In PLAYBACK mode, this would replay the recorded error response // Example implementation: @@ -223,4 +148,16 @@ public void testTranscribeSyncWithInvalidLanguageCode() { // doTranscription(methodName, sync, false, audioFile, options, null); // The service should return an error for invalid locale } + + private void transcribeAndVerifyResult(String testName, TranscriptionOptions options) { + validateTranscriptionResult(testName, client.transcribe(options)); + } + + private void transcribeAndVerifyResponse(String testName, TranscriptionOptions options, + RequestOptions requestOptions) { + BinaryData multipartBody = createMultipartBody(options, requestOptions); + Response response = client.transcribeWithResponse(multipartBody, requestOptions); + printHttpRequestAndResponse(response); + validateTranscriptionResult(testName, response.getValue().toObject(TranscriptionResult.class)); + } } diff --git a/sdk/transcription/azure-ai-speech-transcription/src/test/java/com/azure/ai/speech/transcription/TranscriptionClientTestBase.java b/sdk/transcription/azure-ai-speech-transcription/src/test/java/com/azure/ai/speech/transcription/TranscriptionClientTestBase.java index 7a8b8c1ec0f8..10f0417e118b 100644 --- a/sdk/transcription/azure-ai-speech-transcription/src/test/java/com/azure/ai/speech/transcription/TranscriptionClientTestBase.java +++ b/sdk/transcription/azure-ai-speech-transcription/src/test/java/com/azure/ai/speech/transcription/TranscriptionClientTestBase.java @@ -3,6 +3,7 @@ package com.azure.ai.speech.transcription; +import com.azure.ai.speech.transcription.implementation.MultipartFormDataHelper; import com.azure.ai.speech.transcription.models.AudioFileDetails; import com.azure.ai.speech.transcription.models.TranscriptionOptions; import com.azure.ai.speech.transcription.models.TranscriptionResult; @@ -13,16 +14,13 @@ import com.azure.core.http.policy.HttpLogOptions; import com.azure.core.http.rest.RequestOptions; import com.azure.core.http.rest.Response; -import com.azure.core.test.TestMode; import com.azure.core.test.TestProxyTestBase; import com.azure.core.util.BinaryData; import com.azure.core.util.Configuration; -import com.azure.core.util.logging.ClientLogger; import com.azure.identity.DefaultAzureCredentialBuilder; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Paths; @@ -35,52 +33,34 @@ * Supports both API Key (KeyCredential) and Entra ID (TokenCredential) authentication. */ class TranscriptionClientTestBase extends TestProxyTestBase { - private static final ClientLogger LOGGER = new ClientLogger(TranscriptionClientTestBase.class); + private static final boolean PRINT_RESULTS = false; // Set to true to print results to console window - final Boolean printResults = false; // Set to true to print results to console window + private static final String SAMPLE_WAV_FILE_NAME = "sample.wav"; + private static final byte[] SAMPLE_WAV; - // Sample audio file for testing - final String audioFile = "./src/test/java/com/azure/ai/speech/transcription/sample.wav"; - - // The clients that will be used for tests - private TranscriptionClient client = null; - private TranscriptionAsyncClient asyncClient = null; - - /** - * Sets up the test resources before each test. - */ - @BeforeEach - public void setupTest() { - // Reset clients before each test to ensure clean state - client = null; - asyncClient = null; - } - - /** - * Cleans up test resources after each test. - */ - @AfterEach - public void cleanupTest() { - // Clean up any resources if needed - // Note: The clients don't require explicit cleanup as they are managed by the test framework + static { + try { + SAMPLE_WAV = Files.readAllBytes(Paths + .get(TranscriptionClientTestBase.class.getClassLoader().getResource(SAMPLE_WAV_FILE_NAME).toURI())); + } catch (URISyntaxException | IOException ex) { + throw new RuntimeException("Failed to load audio file for testing.", ex); + } } /** - * Creates a client for testing. + * Configures a {@link TranscriptionClientBuilder} that will be used to create the specific sync or async client for + * testing. * * @param useKeyAuth Whether to use key-based authentication (true) or token-based authentication (false) * @param useRealKey Whether to use a real key from environment variables (true) or a fake key (false). * Only applies when useKeyAuth is true. - * @param sync Whether to create a synchronous client (true) or asynchronous client (false) */ - protected void createClient(Boolean useKeyAuth, Boolean useRealKey, Boolean sync) { - TestMode testMode = getTestMode(); - + protected TranscriptionClientBuilder configureBuilder(boolean useKeyAuth, boolean useRealKey) { // Define endpoint and auth credentials String endpoint = "https://fake-resource-name.cognitiveservices.azure.com"; String key = "00000000000000000000000000000000"; - if (testMode == TestMode.LIVE || testMode == TestMode.RECORD) { + if (!interceptorManager.isPlaybackMode()) { endpoint = Configuration.getGlobalConfiguration().get("SPEECH_ENDPOINT"); assertTrue(endpoint != null && !endpoint.isEmpty(), "Endpoint URL is required to run live tests."); @@ -95,7 +75,7 @@ protected void createClient(Boolean useKeyAuth, Boolean useRealKey, Boolean sync .httpLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS)); // Update the client builder with credentials and recording/playback policies - if (getTestMode() == TestMode.LIVE) { + if (interceptorManager.isLiveMode()) { if (useKeyAuth) { transcriptionClientBuilder.credential(new KeyCredential(key)); } else { @@ -103,7 +83,7 @@ protected void createClient(Boolean useKeyAuth, Boolean useRealKey, Boolean sync TokenCredential credential = new DefaultAzureCredentialBuilder().build(); transcriptionClientBuilder.credential(credential); } - } else if (getTestMode() == TestMode.RECORD) { + } else if (interceptorManager.isRecordMode()) { transcriptionClientBuilder.addPolicy(interceptorManager.getRecordPolicy()); if (useKeyAuth) { transcriptionClientBuilder.credential(new KeyCredential(key)); @@ -111,7 +91,7 @@ protected void createClient(Boolean useKeyAuth, Boolean useRealKey, Boolean sync TokenCredential credential = new DefaultAzureCredentialBuilder().build(); transcriptionClientBuilder.credential(credential); } - } else if (getTestMode() == TestMode.PLAYBACK) { + } else if (interceptorManager.isPlaybackMode()) { transcriptionClientBuilder.httpClient(interceptorManager.getPlaybackClient()); // In playback mode, use a fake key regardless of authentication method transcriptionClientBuilder.credential(new KeyCredential(key)); @@ -126,129 +106,23 @@ protected void createClient(Boolean useKeyAuth, Boolean useRealKey, Boolean sync interceptorManager.removeSanitizers("AZSDK2003", "AZSDK2030", "AZSDK3430", "AZSDK3493"); } - if (sync) { - client = transcriptionClientBuilder.buildClient(); - } else { - asyncClient = transcriptionClientBuilder.buildAsyncClient(); - } + return transcriptionClientBuilder; } - /** - * Performs transcription with audio URL and validates the result. - * - * @param testName A label that uniquely defines the test. Used in console printout. - * @param sync 'true' to use synchronous client, 'false' to use asynchronous client. - * @param options TranscriptionOptions with audioUrl set - */ - protected void doTranscriptionWithUrl(String testName, Boolean sync, TranscriptionOptions options) { - try { - // Verify that audioUrl is set - assertNotNull(options.getAudioUrl(), "AudioUrl must be set for URL-based transcription"); - assertFalse(options.getAudioUrl().isEmpty(), "AudioUrl must not be empty"); - - TranscriptionResult result = null; - if (sync) { - result = client.transcribe(options); - } else { - result = asyncClient.transcribe(options).block(); - } - - validateTranscriptionResult(testName, result); - } catch (Exception e) { - LOGGER.error("Error in test {}: {}", testName, e.getMessage()); - throw new RuntimeException(e); - } + protected TranscriptionOptions fromAudioFile() { + return new TranscriptionOptions( + new AudioFileDetails(BinaryData.fromBytes(SAMPLE_WAV)).setFilename(SAMPLE_WAV_FILE_NAME)); } - /** - * Performs transcription and validates the result. - * - * @param testName A label that uniquely defines the test. Used in console printout. - * @param sync 'true' to use synchronous client, 'false' to use asynchronous client. - * @param transcribeWithResponse 'true' to use transcribeWithResponse(), 'false' to use transcribe(). - * @param audioFilePath Path to the audio file to transcribe - * @param options TranscriptionOptions (can be null) - * @param requestOptions RequestOptions (can be null) - */ - protected void doTranscription(String testName, Boolean sync, Boolean transcribeWithResponse, String audioFilePath, - TranscriptionOptions options, RequestOptions requestOptions) { - - try { - // Load audio file - byte[] audioData = Files.readAllBytes(Paths.get(audioFilePath)); - AudioFileDetails audioFileDetails - = new AudioFileDetails(BinaryData.fromBytes(audioData)).setFilename(new File(audioFilePath).getName()); - - // Create new options with audio file details if options is currently using URL or null - if (options.getAudioUrl() == null) { - // Options was created with null, need to create a new one with audio file details - options = new TranscriptionOptions(audioFileDetails).setLocales(options.getLocales()) - .setLocaleModelMapping(options.getLocaleModelMapping()) - .setProfanityFilterMode(options.getProfanityFilterMode()) - .setDiarizationOptions(options.getDiarizationOptions()) - .setActiveChannels(options.getActiveChannels()) - .setEnhancedModeOptions(options.getEnhancedModeOptions()) - .setPhraseListOptions(options.getPhraseListOptions()); - } + protected BinaryData createMultipartBody(TranscriptionOptions options, RequestOptions requestOptions) { + AudioFileDetails audioFileDetails + = new AudioFileDetails(BinaryData.fromBytes(SAMPLE_WAV)).setFilename(SAMPLE_WAV_FILE_NAME); - if (sync) { - TranscriptionResult result = null; - if (!transcribeWithResponse) { - result = client.transcribe(options); - } else { - if (requestOptions == null) { - // Use the new transcribeWithResponse(TranscriptionOptions) convenience method - Response response = client.transcribeWithResponse(options); - printHttpRequestAndResponse(response); - result = response.getValue(); - } else { - // When custom RequestOptions are needed, use the lower-level API - BinaryData multipartBody - = new com.azure.ai.speech.transcription.implementation.MultipartFormDataHelper( - requestOptions) - .serializeJsonField("definition", options) - .serializeFileField("audio", audioFileDetails.getContent(), - audioFileDetails.getContentType(), audioFileDetails.getFilename()) - .end() - .getRequestBody(); - Response response = client.transcribeWithResponse(multipartBody, requestOptions); - printHttpRequestAndResponse(response); - result = response.getValue().toObject(TranscriptionResult.class); - } - } - validateTranscriptionResult(testName, result); - } else { - TranscriptionResult result = null; - if (!transcribeWithResponse) { - result = asyncClient.transcribe(options).block(); - } else { - if (requestOptions == null) { - // Use the new transcribeWithResponse(TranscriptionOptions) convenience method - Response response = asyncClient.transcribeWithResponse(options).block(); - printHttpRequestAndResponse(response); - result = response.getValue(); - } else { - // When custom RequestOptions are needed, use the lower-level API - BinaryData multipartBody - = new com.azure.ai.speech.transcription.implementation.MultipartFormDataHelper( - requestOptions) - .serializeJsonField("definition", options) - .serializeFileField("audio", audioFileDetails.getContent(), - audioFileDetails.getContentType(), audioFileDetails.getFilename()) - .end() - .getRequestBody(); - Response response - = asyncClient.transcribeWithResponse(multipartBody, requestOptions).block(); - printHttpRequestAndResponse(response); - result = response.getValue().toObject(TranscriptionResult.class); - } - } - validateTranscriptionResult(testName, result); - } - } catch (Exception e) { - LOGGER.error("Error in test {}: {}", testName, e.getMessage()); - throw new RuntimeException(e); - } + return new MultipartFormDataHelper(requestOptions).serializeJsonField("definition", options) + .serializeFileField("audio", audioFileDetails.getContent(), audioFileDetails.getContentType(), + audioFileDetails.getFilename()) + .end() + .getRequestBody(); } /** @@ -258,18 +132,17 @@ protected void doTranscription(String testName, Boolean sync, Boolean transcribe * @param result The transcription result to validate */ protected void validateTranscriptionResult(String testName, TranscriptionResult result) { - if (printResults) { + if (PRINT_RESULTS) { System.out.println("\n===== Test: " + testName + " ====="); System.out.println("Duration: " + result.getDuration() + "ms"); if (result.getCombinedPhrases() != null) { - result.getCombinedPhrases().forEach(phrase -> { - System.out.println("Channel " + phrase.getChannel() + ": " + phrase.getText()); - }); + result.getCombinedPhrases() + .forEach(phrase -> System.out.println("Channel " + phrase.getChannel() + ": " + phrase.getText())); } if (result.getPhrases() != null) { - result.getPhrases().forEach(phrase -> { - System.out.println("Phrase: " + phrase.getText() + " (confidence: " + phrase.getConfidence() + ")"); - }); + result.getPhrases() + .forEach(phrase -> System.out + .println("Phrase: " + phrase.getText() + " (confidence: " + phrase.getConfidence() + ")")); } } @@ -305,7 +178,7 @@ protected void validateTranscriptionResult(String testName, TranscriptionResult * @param response The HTTP response */ protected void printHttpRequestAndResponse(Response response) { - if (printResults) { + if (PRINT_RESULTS) { HttpRequest request = response.getRequest(); System.out.println("\n===== HTTP Request ====="); System.out.println(request.getHttpMethod() + " " + request.getUrl()); @@ -317,21 +190,4 @@ protected void printHttpRequestAndResponse(Response response) { } } - /** - * Gets the synchronous client. - * - * @return The TranscriptionClient - */ - protected TranscriptionClient getClient() { - return client; - } - - /** - * Gets the asynchronous client. - * - * @return The TranscriptionAsyncClient - */ - protected TranscriptionAsyncClient getAsyncClient() { - return asyncClient; - } } diff --git a/sdk/transcription/azure-ai-speech-transcription/src/test/java/com/azure/ai/speech/transcription/sample.wav b/sdk/transcription/azure-ai-speech-transcription/src/test/resources/sample.wav similarity index 100% rename from sdk/transcription/azure-ai-speech-transcription/src/test/java/com/azure/ai/speech/transcription/sample.wav rename to sdk/transcription/azure-ai-speech-transcription/src/test/resources/sample.wav