diff --git a/sdk/batch/azure-compute-batch/README.md b/sdk/batch/azure-compute-batch/README.md index a133e740d3d6..36e5c41ed2b1 100644 --- a/sdk/batch/azure-compute-batch/README.md +++ b/sdk/batch/azure-compute-batch/README.md @@ -159,6 +159,22 @@ BatchTaskCreateContent taskToCreate = new BatchTaskCreateContent(taskId, "echo h batchClient.createTask(jobId, taskToCreate); ``` +Error handling + +When a call to the batch service fails the response from that call will contain a BatchError object in the body of the response. In the AZURE-COMPUTE-BATCH SDK when an api method is called and a failure from the server occurs the sdk will throw a HttpResponseException exception. You can use the helper method BatchError.fromException() to extract out the BatchError object. + +```java +try( + + BatchPool pool = batchClient.getPool("poolthatdoesnotexist"); + +} catch (HttpResponseException err) { + + BatchError batchError = BatchError.fromException(err); + Assertions.assertEquals("PoolNotFound", error.getCode()); +} +``` + ## Help If you encounter any bugs with these libraries, please file issues via [Issues](https://github.com/Azure/azure-sdk-for-java) or check out [StackOverflow for Azure Java SDK](https://stackoverflow.com/questions/tagged/azure-java-sdk). diff --git a/sdk/batch/azure-compute-batch/assets.json b/sdk/batch/azure-compute-batch/assets.json index 76cb7f078d74..4ae049c54fcd 100644 --- a/sdk/batch/azure-compute-batch/assets.json +++ b/sdk/batch/azure-compute-batch/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/batch/azure-compute-batch", - "Tag": "java/batch/azure-compute-batch_ead064573c" + "Tag": "java/batch/azure-compute-batch_36edb7c93c" } diff --git a/sdk/batch/azure-compute-batch/pom.xml b/sdk/batch/azure-compute-batch/pom.xml index 1d8b37b65a72..b1a6a8984df9 100644 --- a/sdk/batch/azure-compute-batch/pom.xml +++ b/sdk/batch/azure-compute-batch/pom.xml @@ -96,5 +96,11 @@ 12.29.0 test + + org.mockito + mockito-core + 4.11.0 + test + diff --git a/sdk/batch/azure-compute-batch/src/main/java/com/azure/compute/batch/models/BatchError.java b/sdk/batch/azure-compute-batch/src/main/java/com/azure/compute/batch/models/BatchError.java index 3a57a89f1f62..4c54630fc0cd 100644 --- a/sdk/batch/azure-compute-batch/src/main/java/com/azure/compute/batch/models/BatchError.java +++ b/sdk/batch/azure-compute-batch/src/main/java/com/azure/compute/batch/models/BatchError.java @@ -5,11 +5,15 @@ import com.azure.core.annotation.Generated; import com.azure.core.annotation.Immutable; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.HttpResponse; +import com.azure.json.JsonProviders; import com.azure.json.JsonReader; import com.azure.json.JsonSerializable; import com.azure.json.JsonToken; import com.azure.json.JsonWriter; import java.io.IOException; +import java.io.StringReader; import java.util.List; /** @@ -125,4 +129,35 @@ public static BatchError fromJson(JsonReader jsonReader) throws IOException { return deserializedBatchError; }); } + + /** + * Reads an instance of BatchError from an HttpResponseException. + * + * @param err The HttpResponseException based exception returned from an api + * call. + * @return An instance of BatchError if the HttpResponseException containted an + * instance of it, or null if it was pointing + * to an HttpResponseException with no BatchError. + */ + public static BatchError fromException(HttpResponseException err) { + if (err == null) { + return null; + } + HttpResponse response = err.getResponse(); + if (response == null) { + return null; + } + String bodyastring = response.getBodyAsString().block(); + if (bodyastring == null) { + return null; + } + JsonReader jsonReader; + try { + jsonReader = JsonProviders.createReader(new StringReader(bodyastring)); + return BatchError.fromJson(jsonReader); + } catch (IOException e) { + // If the body of the response is not a valid json, return null + return null; + } + } } diff --git a/sdk/batch/azure-compute-batch/src/test/java/com/azure/compute/batch/BatchErrorTests.java b/sdk/batch/azure-compute-batch/src/test/java/com/azure/compute/batch/BatchErrorTests.java new file mode 100644 index 000000000000..e6cfedca9b6e --- /dev/null +++ b/sdk/batch/azure-compute-batch/src/test/java/com/azure/compute/batch/BatchErrorTests.java @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.compute.batch; + +import com.azure.compute.batch.models.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import com.azure.core.exception.HttpResponseException; + +public class BatchErrorTests extends BatchClientTestBase { + + @Test + public void testResizeErrorCases() { + try { + + BatchPoolResizeContent resizeContent = new BatchPoolResizeContent(); + batchClient.resizePool("fakepool", resizeContent); + } catch (HttpResponseException err) { + + BatchError error = BatchError.fromException(err); + Assertions.assertNotNull(error); + Assertions.assertEquals("MissingRequiredProperty", error.getCode()); + Assertions.assertTrue( + error.getMessage().getValue().contains("A required property was not specified in the request body.")); + Assertions.assertEquals("targetDedicatedNodes and/or targetLowPriorityNodes", + error.getValues().get(0).getValue()); + } + + try { + + batchClient.resizePool("fakepool", + new BatchPoolResizeContent().setTargetDedicatedNodes(1).setTargetLowPriorityNodes(1)); + } catch (HttpResponseException err) { + + BatchError error = BatchError.fromException(err); + Assertions.assertNotNull(error); + Assertions.assertEquals("PoolNotFound", error.getCode()); + Assertions.assertTrue(error.getMessage().getValue().contains("The specified pool does not exist.")); + Assertions.assertNull(error.getValues()); + } + } +} diff --git a/sdk/batch/azure-compute-batch/src/test/java/com/azure/compute/batch/models/BatchErrorUnitTest.java b/sdk/batch/azure-compute-batch/src/test/java/com/azure/compute/batch/models/BatchErrorUnitTest.java new file mode 100644 index 000000000000..90230ee2318b --- /dev/null +++ b/sdk/batch/azure-compute-batch/src/test/java/com/azure/compute/batch/models/BatchErrorUnitTest.java @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.compute.batch.models; + +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.HttpResponse; +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Mono; +import java.io.IOException; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +public class BatchErrorUnitTest { + + @Test + public void testFromExceptionWithValidJson() throws IOException { + // Arrange + String json = "{\"code\":\"InvalidRequest\",\"message\":{\"value\":\"Invalid request\"},\"values\":[]}"; + HttpResponse response = mock(HttpResponse.class); + when(response.getBodyAsString()).thenReturn(Mono.just(json)); + HttpResponseException exception = new HttpResponseException("Error", response); + + // Act + BatchError batchError = BatchError.fromException(exception); + + // Assert + assertNotNull(batchError); + assertEquals("InvalidRequest", batchError.getCode()); + assertNotNull(batchError.getMessage()); + assertEquals("Invalid request", batchError.getMessage().getValue()); + assertTrue(batchError.getValues().isEmpty()); + } + + @Test + public void testFromExceptionWithValidJsonMultiValues() throws IOException { + // Arrange + String json + = "{\"code\":\"InvalidRequest\",\"message\":{\"value\":\"Error message\"},\"values\":[{\"key\": \"key1\",\"value\":\"value1\"},{\"key\": \"key2\",\"value\":\"value2\"}]}"; + HttpResponse response = mock(HttpResponse.class); + when(response.getBodyAsString()).thenReturn(Mono.just(json)); + HttpResponseException exception = new HttpResponseException("Error", response); + + // Act + BatchError batchError = BatchError.fromException(exception); + + // Assert + assertNotNull(batchError); + assertEquals("InvalidRequest", batchError.getCode()); + assertNotNull(batchError.getMessage()); + assertEquals("Error message", batchError.getMessage().getValue()); + assertNotNull(batchError.getValues()); + assertEquals("key1", batchError.getValues().get(0).getKey()); + assertEquals("value1", batchError.getValues().get(0).getValue()); + assertEquals("key2", batchError.getValues().get(1).getKey()); + assertEquals("value2", batchError.getValues().get(1).getValue()); + } + + @Test + public void testFromExceptionWithInvalidJson() { + // Arrange + String invalidJson = "Invalid JSON"; + HttpResponse response = mock(HttpResponse.class); + when(response.getBodyAsString()).thenReturn(Mono.just(invalidJson)); + HttpResponseException exception = new HttpResponseException("Error", response); + + // Act + BatchError batchError = BatchError.fromException(exception); + + // Assert + assertNull(batchError); + } + + @Test + public void testFromExceptionWithNullResponse() { + // Arrange + HttpResponse response = mock(HttpResponse.class); + when(response.getBodyAsString()).thenReturn(Mono.empty()); + HttpResponseException exception = new HttpResponseException("Error", response); + + // Act + BatchError batchError = BatchError.fromException(exception); + + // Assert + assertNull(batchError); + } +}