Skip to content

Commit

Permalink
Merge pull request Azure#251 from Azure/AddErrorToOperationStatus
Browse files Browse the repository at this point in the history
Add error and provisioning state to OperationStatus
  • Loading branch information
Dan Schulte authored Oct 4, 2017
2 parents 6c4cf51 + 8fc8885 commit 4a1f9a2
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,6 @@ public final class AzureAsyncOperationPollStrategy extends PollStrategy {
*/
public static final String HEADER_NAME = "Azure-AsyncOperation";

/**
* The provisioning state of the operation resource if the operation is still in progress.
*/
public static final String IN_PROGRESS = "InProgress";

/**
* The provisioning state of the operation resource if the operation is successful.
*/
public static final String SUCCEEDED = "Succeeded";

/**
* Create a new AzureAsyncOperationPollStrategy object that will poll the provided operation
* resource URL.
Expand Down Expand Up @@ -96,10 +86,12 @@ public Single<HttpResponse> call(String bodyString) {
try {
final OperationResource operationResource = serializer.deserialize(bodyString, OperationResource.class);
if (operationResource != null) {
final String provisioningState = provisioningState(operationResource);
pollingCompleted = !IN_PROGRESS.equalsIgnoreCase(provisioningState);
final String resourceProvisioningState = provisioningState(operationResource);
setProvisioningState(resourceProvisioningState);

pollingCompleted = !ProvisioningState.IN_PROGRESS.equalsIgnoreCase(resourceProvisioningState);
if (pollingCompleted) {
pollingSucceeded = SUCCEEDED.equalsIgnoreCase(provisioningState);
pollingSucceeded = ProvisioningState.SUCCEEDED.equalsIgnoreCase(resourceProvisioningState);
clearDelayInMilliseconds();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import com.google.common.reflect.TypeToken;
import com.microsoft.azure.annotations.AzureHost;
import com.microsoft.rest.RestException;
import com.microsoft.rest.protocol.SerializerAdapter;
import com.microsoft.rest.InvalidReturnTypeException;
import com.microsoft.rest.RestProxy;
Expand Down Expand Up @@ -175,7 +176,8 @@ public Observable<OperationStatus<Object>> call(HttpResponse httpResponse) {

Observable<OperationStatus<Object>> result;
if (pollStrategy == null || pollStrategy.isDone()) {
result = toCompletedOperationStatusObservable(httpRequest, httpResponse, methodParser, operationStatusResultType);
final String provisioningState = pollStrategy == null ? ProvisioningState.SUCCEEDED : pollStrategy.provisioningState();
result = toCompletedOperationStatusObservable(provisioningState, httpRequest, httpResponse, methodParser, operationStatusResultType);
} else {
result = sendPollRequestWithDelay(pollStrategy)
.flatMap(new Func1<HttpResponse, Observable<OperationStatus<Object>>>() {
Expand All @@ -186,7 +188,7 @@ public Observable<OperationStatus<Object>> call(HttpResponse httpResponse) {
result = Observable.just(new OperationStatus<>(pollStrategy));
}
else {
result = toCompletedOperationStatusObservable(httpRequest, httpResponse, methodParser, operationStatusResultType);
result = toCompletedOperationStatusObservable(pollStrategy.provisioningState(), httpRequest, httpResponse, methodParser, operationStatusResultType);
}
return result;
}
Expand Down Expand Up @@ -240,11 +242,16 @@ private static PollStrategy createPollStrategy(HttpRequest httpRequest, HttpResp
return result;
}

private Observable<OperationStatus<Object>> toCompletedOperationStatusObservable(HttpRequest httpRequest, HttpResponse httpResponse, SwaggerMethodParser methodParser, Type operationStatusResultType) {
private Observable<OperationStatus<Object>> toCompletedOperationStatusObservable(String provisioningState, HttpRequest httpRequest, HttpResponse httpResponse, SwaggerMethodParser methodParser, Type operationStatusResultType) {
Observable<OperationStatus<Object>> result;
try {
final Object resultObject = super.handleSyncHttpResponse(httpRequest, httpResponse, methodParser, operationStatusResultType);
result = Observable.just(new OperationStatus<>(resultObject));
result = Observable.just(new OperationStatus<>(resultObject, provisioningState));
} catch (RestException e) {
if (ProvisioningState.SUCCEEDED.equals(provisioningState)) {
provisioningState = ProvisioningState.FAILED;
}
result = Observable.just(new OperationStatus<>(e, provisioningState));
} catch (IOException e) {
result = Observable.error(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@

package com.microsoft.azure;

import com.microsoft.rest.RestException;

/**
* The current state of polling for the result of a long running operation.
* @param <T> The type of value that will be returned from the long running operation.
*/
public class OperationStatus<T> {
private PollStrategy pollStrategy;
private T result;
private final PollStrategy pollStrategy;
private final T result;
private final RestException error;
private final String provisioningState;

/**
* Create a new OperationStatus with the provided PollStrategy.
Expand All @@ -21,30 +25,58 @@ public class OperationStatus<T> {
*/
OperationStatus(PollStrategy pollStrategy) {
this.pollStrategy = pollStrategy;
this.result = null;
this.error = null;
this.provisioningState = pollStrategy.provisioningState();
}

/**
* Create a new OperationStatus with the provided result.
* @param result The final result of a long running operation.
*/
OperationStatus(T result) {
OperationStatus(T result, String provisioningState) {
this.pollStrategy = null;
this.result = result;
this.error = null;
this.provisioningState = provisioningState;
}

OperationStatus(RestException error, String provisioningState) {
this.pollStrategy = null;
this.result = null;
this.error = error;
this.provisioningState = provisioningState;
}

/**
* Get whether or not the long running operation is done.
* @return Whether or not the long running operation is done.
*/
public boolean isDone() {
return pollStrategy == null;
}

/**
* @return the current provisioning state of the long running operation.
*/
public String provisioningState() {
return provisioningState;
}

/**
* If the long running operation is done, get the result of the operation. If the operation is
* not done, then return null.
* @return The result of the operation, or null if the operation isn't done yet.
* not done or if the operation failed, then return null.
* @return The result of the operation, or null if the operation isn't done yet or if it failed.
*/
public T result() {
return result;
}

/**
* If the long running operation failed, get the error that occurred. If the operation is not
* done or did not fail, then return null.
* @return The error of the operation, or null if the operation isn't done or didn't fail.
*/
public RestException error() {
return error;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*/
abstract class PollStrategy {
private long delayInMilliseconds;
private String provisioningState;

PollStrategy(long delayInMilliseconds) {
this.delayInMilliseconds = delayInMilliseconds;
Expand Down Expand Up @@ -81,6 +82,21 @@ Single<Void> delayAsync() {
return result;
}

/**
* @return the current provisioning state of the long running operation.
*/
String provisioningState() {
return provisioningState;
}

/**
* Set the current provisioning state of the long running operation.
* @param provisioningState The current provisioning state of the long running operation.
*/
protected void setProvisioningState(String provisioningState) {
this.provisioningState = provisioningState;
}

/**
* Create a new HTTP poll request.
* @return A new HTTP poll request.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for
* license information.
*/

package com.microsoft.azure;

/**
* The different provisioning states that a long running operation can be in.
*/
public final class ProvisioningState {
/**
* The provisioning state of the operation resource if the operation is still in progress.
*/
public static final String IN_PROGRESS = "InProgress";

/**
* The provisioning state of the operation resource if the operation is successful.
*/
public static final String SUCCEEDED = "Succeeded";

/**
* The provisioning state of the operation resource if the operation is unsuccessful.
*/
public static final String FAILED = "Failed";
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ private interface MockResourceService {
@ExpectedResponses({200})
Observable<MockResource> beginCreateAsyncWithBadReturnType(@PathParam("subscriptionId") String subscriptionId, @PathParam("resourceGroupName") String resourceGroupName, @PathParam("mockResourceName") String mockResourceName, @PathParam("pollsRemaining") int pollsUntilResource);

@PUT("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/mockprovider/mockresources/{mockResourceName}?PollType=Location&PollsRemaining=1&InitialResponseStatusCode=294")
@ExpectedResponses({200})
Observable<OperationStatus<MockResource>> beginCreateAsyncWithLocationAndPollsAndUnexpectedStatusCode(@PathParam("subscriptionId") String subscriptionId, @PathParam("resourceGroupName") String resourceGroupName, @PathParam("mockResourceName") String mockResourceName);

@PUT("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/mockprovider/mockresources/{mockResourceName}?PollType=Location&PollsRemaining={pollsRemaining}")
@ExpectedResponses({200})
Observable<OperationStatus<MockResource>> beginCreateAsyncWithLocationAndPolls(@PathParam("subscriptionId") String subscriptionId, @PathParam("resourceGroupName") String resourceGroupName, @PathParam("mockResourceName") String mockResourceName, @PathParam("pollsRemaining") int pollsUntilResource);
Expand Down Expand Up @@ -361,6 +365,29 @@ public void beginCreateAsyncWithBadReturnType() {
assertEquals(0, httpClient.pollRequests());
}

@Test
public void beginCreateAsyncWithLocationAndPollsAndUnexpectedStatusCode() {
final MockAzureHttpClient httpClient = new MockAzureHttpClient();

createMockService(MockResourceService.class, httpClient)
.beginCreateAsyncWithLocationAndPollsAndUnexpectedStatusCode("1", "mine", "c")
.subscribe(new Action1<OperationStatus<MockResource>>() {
@Override
public void call(OperationStatus<MockResource> operationStatus) {
assertTrue(operationStatus.isDone());
assertNull(operationStatus.result());
assertNotNull(operationStatus.error());
assertEquals("Status code 294, null", operationStatus.error().getMessage());
assertEquals(ProvisioningState.FAILED, operationStatus.provisioningState());
}
});

assertEquals(0, httpClient.getRequests());
assertEquals(1, httpClient.createRequests());
assertEquals(0, httpClient.deleteRequests());
assertEquals(0, httpClient.pollRequests());
}

@Test
public void beginCreateAsyncWithLocationAndPolls() {
final MockAzureHttpClient httpClient = new MockAzureHttpClient();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.microsoft.azure.LocationPollStrategy;
import com.microsoft.azure.MockResource;
import com.microsoft.azure.OperationResource;
import com.microsoft.azure.ProvisioningState;
import com.microsoft.rest.http.HttpClient;
import com.microsoft.rest.http.HttpHeader;
import com.microsoft.rest.http.HttpHeaders;
Expand Down Expand Up @@ -135,11 +136,11 @@ else if (requestPathLower.contains("/mockprovider/mockoperations/")) {
if (pollType.equalsIgnoreCase(AzureAsyncOperationPollStrategy.HEADER_NAME)) {
final OperationResource.Properties properties = new OperationResource.Properties();
if (pollsRemaining <= 1) {
properties.setProvisioningState(AzureAsyncOperationPollStrategy.SUCCEEDED);
properties.setProvisioningState(ProvisioningState.SUCCEEDED);
}
else {
--pollsRemaining;
properties.setProvisioningState(AzureAsyncOperationPollStrategy.IN_PROGRESS);
properties.setProvisioningState(ProvisioningState.IN_PROGRESS);
}
final OperationResource operationResource = new OperationResource();
operationResource.setProperties(properties);
Expand Down

0 comments on commit 4a1f9a2

Please sign in to comment.