Skip to content

Commit

Permalink
Httpbin update (check for https/http), default impl for HttpResponseD…
Browse files Browse the repository at this point in the history
…ecodeData methods (Azure#559)

* [test] The protocol part of url property in httpbin response is not consistent with request url, fix:assert for both http and https. The '1.1 vegur' via header is not returned from httpbin anymore.

* Adding default impls for methods in HttpResponseDecodeData interface, java-doc for HttpResponseDecoder.

* Fixing the regression introduced (due to new MalformedValueException type) in the commit c6945f28534b3c57d261e30505c813114994fb84
  • Loading branch information
anuchandy authored Feb 20, 2019
1 parent 5c4d932 commit 3480480
Show file tree
Hide file tree
Showing 5 changed files with 233 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.microsoft.rest.v3.annotations.UnexpectedResponseExceptionType;
import com.microsoft.rest.v3.http.HttpClient;
import com.microsoft.rest.v3.http.HttpHeaders;
import org.junit.Assert;
import org.junit.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
Expand Down Expand Up @@ -165,63 +166,63 @@ public void SyncGetRequestWithAnything() {
final HttpBinJSON json = createService(Service5.class)
.getAnything();
assertNotNull(json);
assertEquals("http://httpbin.org/anything", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything", json.url);
}

@Test
public void SyncGetRequestWithAnythingWithPlus() {
final HttpBinJSON json = createService(Service5.class)
.getAnythingWithPlus();
assertNotNull(json);
assertEquals("http://httpbin.org/anything/with+plus", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything/with+plus", json.url);
}

@Test
public void SyncGetRequestWithAnythingWithPathParam() {
final HttpBinJSON json = createService(Service5.class)
.getAnythingWithPathParam("withpathparam");
assertNotNull(json);
assertEquals("http://httpbin.org/anything/withpathparam", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything/withpathparam", json.url);
}

@Test
public void SyncGetRequestWithAnythingWithPathParamWithSpace() {
final HttpBinJSON json = createService(Service5.class)
.getAnythingWithPathParam("with path param");
assertNotNull(json);
assertEquals("http://httpbin.org/anything/with path param", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything/with path param", json.url);
}

@Test
public void SyncGetRequestWithAnythingWithPathParamWithPlus() {
final HttpBinJSON json = createService(Service5.class)
.getAnythingWithPathParam("with+path+param");
assertNotNull(json);
assertEquals("http://httpbin.org/anything/with+path+param", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything/with+path+param", json.url);
}

@Test
public void SyncGetRequestWithAnythingWithEncodedPathParam() {
final HttpBinJSON json = createService(Service5.class)
.getAnythingWithEncodedPathParam("withpathparam");
assertNotNull(json);
assertEquals("http://httpbin.org/anything/withpathparam", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything/withpathparam", json.url);
}

@Test
public void SyncGetRequestWithAnythingWithEncodedPathParamWithPercent20() {
final HttpBinJSON json = createService(Service5.class)
.getAnythingWithEncodedPathParam("with%20path%20param");
assertNotNull(json);
assertEquals("http://httpbin.org/anything/with path param", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything/with path param", json.url);
}

@Test
public void SyncGetRequestWithAnythingWithEncodedPathParamWithPlus() {
final HttpBinJSON json = createService(Service5.class)
.getAnythingWithEncodedPathParam("with+path+param");
assertNotNull(json);
assertEquals("http://httpbin.org/anything/with+path+param", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything/with+path+param", json.url);
}

@Test
Expand All @@ -230,7 +231,7 @@ public void AsyncGetRequestWithAnything() {
.getAnythingAsync()
.block();
assertNotNull(json);
assertEquals("http://httpbin.org/anything", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything", json.url);
}

@Host("http://httpbin.org")
Expand All @@ -253,23 +254,23 @@ public void SyncGetRequestWithQueryParametersAndAnything() {
final HttpBinJSON json = createService(Service6.class)
.getAnything("A", 15);
assertNotNull(json);
assertEquals("http://httpbin.org/anything?a=A&b=15", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything?a=A&b=15", json.url);
}

@Test
public void SyncGetRequestWithQueryParametersAndAnythingWithPercent20() {
final HttpBinJSON json = createService(Service6.class)
.getAnything("A%20Z", 15);
assertNotNull(json);
assertEquals("http://httpbin.org/anything?a=A%2520Z&b=15", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything?a=A%2520Z&b=15", json.url);
}

@Test
public void SyncGetRequestWithQueryParametersAndAnythingWithEncodedWithPercent20() {
final HttpBinJSON json = createService(Service6.class)
.getAnythingWithEncoded("x%20y", 15);
assertNotNull(json);
assertEquals("http://httpbin.org/anything?a=x y&b=15", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything?a=x y&b=15", json.url);
}

@Test
Expand All @@ -278,7 +279,7 @@ public void AsyncGetRequestWithQueryParametersAndAnything() {
.getAnythingAsync("A", 15)
.block();
assertNotNull(json);
assertEquals("http://httpbin.org/anything?a=A&b=15", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything?a=A&b=15", json.url);
}

@Host("http://httpbin.org")
Expand All @@ -297,7 +298,7 @@ public void SyncGetRequestWithHeaderParametersAndAnythingReturn() {
final HttpBinJSON json = createService(Service7.class)
.getAnything("A", 15);
assertNotNull(json);
assertEquals("http://httpbin.org/anything", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything", json.url);
assertNotNull(json.headers);
final HttpHeaders headers = new HttpHeaders(json.headers);
assertEquals("A", headers.value("A"));
Expand All @@ -312,7 +313,7 @@ public void AsyncGetRequestWithHeaderParametersAndAnything() {
.getAnythingAsync("A", 15)
.block();
assertNotNull(json);
assertEquals("http://httpbin.org/anything", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything", json.url);
assertNotNull(json.headers);
final HttpHeaders headers = new HttpHeaders(json.headers);
assertEquals("A", headers.value("A"));
Expand Down Expand Up @@ -538,7 +539,7 @@ public void SyncHeadersRequest() {
final HttpBinJSON json = createService(Service13.class)
.get();
assertNotNull(json);
assertEquals("http://httpbin.org/anything", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything", json.url);
assertNotNull(json.headers);
final HttpHeaders headers = new HttpHeaders(json.headers);
assertEquals("MyHeaderValue", headers.value("MyHeader"));
Expand All @@ -553,7 +554,7 @@ public void AsyncHeadersRequest() {
.getAsync()
.block();
assertNotNull(json);
assertEquals("http://httpbin.org/anything", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything", json.url);
assertNotNull(json.headers);
final HttpHeaders headers = new HttpHeaders(json.headers);
assertEquals("MyHeaderValue", headers.value("MyHeader"));
Expand All @@ -579,7 +580,7 @@ public void AsyncHttpsHeadersRequest() {
.getAsync()
.block();
assertNotNull(json);
assertEquals("https://httpbin.org/anything", json.url);
assertMatchWithHttpOrHttps("httpbin.org/anything", json.url);
assertNotNull(json.headers);
final HttpHeaders headers = new HttpHeaders(json.headers);
assertEquals("MyHeaderValue", headers.value("MyHeader"));
Expand Down Expand Up @@ -621,7 +622,7 @@ public void service16Put() {
final Service16 service = createService(Service16.class);
final HttpBinJSON result = service.put(new byte[] { 0, 1, 2, 3, 4, 5 });
assertNotNull(result);
assertEquals("http://httpbin.org/put", result.url);
assertMatchWithHttpOrHttps("httpbin.org/put", result.url);
assertTrue(result.data instanceof String);
assertArrayEquals(new byte[] { 0, 1, 2, 3, 4, 5 }, ((String)result.data).getBytes());
}
Expand All @@ -632,7 +633,7 @@ public void service16PutAsync() {
final HttpBinJSON result = service.putAsync(new byte[] { 0, 1, 2, 3, 4, 5 })
.block();
assertNotNull(result);
assertEquals("http://httpbin.org/put", result.url);
assertMatchWithHttpOrHttps("httpbin.org/put", result.url);
assertTrue(result.data instanceof String);
assertArrayEquals(new byte[] { 0, 1, 2, 3, 4, 5 }, ((String)result.data).getBytes());
}
Expand All @@ -653,15 +654,15 @@ public void SyncRequestWithMultipleHostParams() {
final Service17 service17 = createService(Service17.class);
final HttpBinJSON result = service17.get("http", "bin");
assertNotNull(result);
assertEquals("http://httpbin.org/get", result.url);
assertMatchWithHttpOrHttps("httpbin.org/get", result.url);
}

@Test
public void AsyncRequestWithMultipleHostParams() {
final Service17 service17 = createService(Service17.class);
final HttpBinJSON result = service17.getAsync("http", "bin").block();
assertNotNull(result);
assertEquals("http://httpbin.org/get", result.url);
assertMatchWithHttpOrHttps("httpbin.org/get", result.url);
}

@Host("https://httpbin.org")
Expand Down Expand Up @@ -755,5 +756,17 @@ private static void assertContains(String value, String expectedSubstring) {
assertTrue("Expected \"" + value + "\" to contain \"" + expectedSubstring + "\".", value.contains(expectedSubstring));
}

private static void assertMatchWithHttpOrHttps(String url1, String url2) {
final String s1 = "http://" + url1;
if (s1.equalsIgnoreCase(url2)) {
return;
}
final String s2 = "https://" + url1;
if (s2.equalsIgnoreCase(url2)) {
return;
}
Assert.assertTrue("'" + url2 + "' does not match with '" + s1 + "' or '" + s2 + "'." , false);
}

private static final SerializerAdapter serializer = new JacksonAdapter();
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@
*
* Example 1:
* {@code @PUT("{functionId}")}
* {@code Single<RestResponse<Headers, Body>>} createOrReplace(@PathParam("functionId", encoded = true) String functionId, @BodyParam FunctionInner function, @HeaderParam("If-Match") String ifMatch);
* {@code Mono<RestResponse<Headers, Body>>} createOrReplace(@PathParam("functionId", encoded = true) String functionId, @BodyParam FunctionInner function, @HeaderParam("If-Match") String ifMatch);
*
* "If-Match: user passed value" will show up as one of the headers.
*
* Example 2:
* {@code @}GET("subscriptions/{subscriptionId}/providers/Microsoft.ServiceBus/namespaces")
* {@code Single<RestResponse<Headers, Body>>} list(@Path("subscriptionId") String subscriptionId, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent);
* {@code Mono<RestResponse<Headers, Body>>} list(@Path("subscriptionId") String subscriptionId, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent);
*
* "accept-language" generated by the HTTP client will be overwritten by the user passed value.
*
* Example 3:
* {@code @GET("subscriptions/{subscriptionId}/providers/Microsoft.ServiceBus/namespaces")}
* {@code Single<RestResponse<Headers, Body>>} list(@Path("subscriptionId") String subscriptionId, @Header("Authorization") String token);
* {@code Mono<RestResponse<Headers, Body>>} list(@Path("subscriptionId") String subscriptionId, @Header("Authorization") String token);
*
* The token parameter will replace the effect of any credentials in the HTTP pipeline.
*
* Example 4:
* {@code @PUT("{containerName}/{blob}")}
* {@code @ExpectedResponses({200})}
* {@code Single<RestResponse<BlobSetMetadataHeaders, Void>> setMetadata(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map<String, String> metadata, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") String ifModifiedSince, @HeaderParam("If-Unmodified-Since") String ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatches, @HeaderParam("If-None-Match") String ifNoneMatch, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp);}
* {@code Mono<RestResponse<BlobSetMetadataHeaders, Void>> setMetadata(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map<String, String> metadata, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") String ifModifiedSince, @HeaderParam("If-Unmodified-Since") String ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatches, @HeaderParam("If-None-Match") String ifNoneMatch, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp);}
*
* The metadata parameter will be expanded out so that each entry becomes "x-ms-meta-{@literal <entryKey>}: {@literal <entryValue>}".
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,47 +6,79 @@

package com.microsoft.rest.v3.serializer;

import com.microsoft.rest.v3.RestResponse;
import com.microsoft.rest.v3.annotations.HeaderCollection;
import com.microsoft.rest.v3.http.HttpMethod;
import com.microsoft.rest.v3.util.TypeUtil;
import reactor.core.publisher.Mono;

import java.lang.reflect.Type;

/**
* Type representing necessary data required to decode a Http response.
* Type representing necessary data required to decode a specific Http response.
*/
public interface HttpResponseDecodeData {
/**
* Get the HTTP method that will be used to retrieve the response.
* Get the HTTP method that was used to retrieve the response.
*
* @return the HTTP method that will be used to retrieve the response
* @return the HTTP method that was used to retrieve the response
*/
HttpMethod httpMethod();

/**
* Get the return type.
*
* @return the return type
*/
Type returnType();

/**
* Get the type of the entity to be used as the model to hold deserialized 'Matching' headers.
*
* The 'header entity' is optional and client can choose it when a strongly typed model is needed for headers.
*
* 'Matching' headers are the REST API returned headers those with:
* 1. header names same as name of a properties in the entity.
* 2. header names start with value of {@link HeaderCollection} annotation applied to the properties in the entity.
*
* @return headers entity type
*/
default Type headersType() {
Type token = this.returnType();
Type headersType = null;
//
if (TypeUtil.isTypeOrSubTypeOf(token, Mono.class)) {
token = TypeUtil.getTypeArgument(token);
}
if (TypeUtil.isTypeOrSubTypeOf(token, RestResponse.class)) {
headersType = TypeUtil.getTypeArguments(TypeUtil.getSuperType(token, RestResponse.class))[0];
}
return headersType;
}

/**
* Get the expected HTTP response status codes.
*
* If the returned int[] is null, then all status codes less than 400 are allowed.
*
* @return the expected HTTP response status codes,if null then all status codes less than 400 are allowed
*/
int[] expectedStatusCodes();
default int[] expectedStatusCodes() {
return null;
}

/**
* Get the type of the HTTP response content.
* Get the type of the 'entity' in HTTP response content.
*
* When this method return non-null {@code Type} then the raw HTTP response
* content will need to parsed to this {@code Type} then converted to actual
* {@code returnType}.
*
* @return the type that the raw HTTP response content will be sent as
*/
Type returnValueWireType();

/**
* Get the return type.
*
* @return the return type
*/
Type returnType();
default Type returnValueWireType() {
return null;
}

/**
* Get the type of body Object that a thrown {@link com.microsoft.rest.v3.RestException} will
Expand All @@ -55,5 +87,7 @@ public interface HttpResponseDecodeData {
* @return the type of body Object that a thrown RestException will contain if the HTTP
* response's status code is not one of the expected status codes
*/
Class<?> exceptionBodyType();
default Class<?> exceptionBodyType() {
return Object.class;
}
}
Loading

0 comments on commit 3480480

Please sign in to comment.