Add basic RestClient implentation based on HTTP Components 4.5

- Upgrade version of HTTP Components to 4.5
- Add helper class to create Http clients
- Add helper class to build http requests
- Add enum with the different Http Methods
- Add constants class for HTTP related values
This commit is contained in:
Miguel Ferreira 2015-08-21 17:44:57 +02:00
parent 6e74ef8e40
commit 8a93bb8d2d
12 changed files with 863 additions and 1 deletions

View File

@ -77,7 +77,7 @@
<cs.guava-testlib.version>18.0</cs.guava-testlib.version>
<cs.guava.version>18.0</cs.guava.version>
<cs.xapi.version>6.2.0-3.1</cs.xapi.version>
<cs.httpclient.version>4.3.6</cs.httpclient.version>
<cs.httpclient.version>4.5</cs.httpclient.version>
<cs.httpcore.version>4.4</cs.httpcore.version>
<cs.commons-httpclient.version>3.1</cs.commons-httpclient.version>
<cs.mysql.version>5.1.34</cs.mysql.version>

View File

@ -0,0 +1,118 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.utils.rest;
import java.io.IOException;
import java.net.URI;
import org.apache.http.HttpHost;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.log4j.Logger;
public class BasicRestClient implements RestClient {
private static final Logger s_logger = Logger.getLogger(BasicRestClient.class);
private static final String HTTPS = HttpConstants.HTTPS;
private static final int HTTPS_PORT = HttpConstants.HTTPS_PORT;
private final CloseableHttpClient client;
private final HttpClientContext clientContext;
private BasicRestClient(final Builder<?> builder) {
client = builder.client;
clientContext = builder.clientContext;
clientContext.setTargetHost(buildHttpHost(builder.host));
}
protected BasicRestClient(final CloseableHttpClient client, final HttpClientContext clientContex, final String host) {
this.client = client;
clientContext = clientContex;
clientContext.setTargetHost(buildHttpHost(host));
}
private static HttpHost buildHttpHost(final String host) {
return new HttpHost(host, HTTPS_PORT, HTTPS);
}
@SuppressWarnings("rawtypes")
public static Builder create() {
return new Builder();
}
@Override
public CloseableHttpResponse execute(final HttpUriRequest request) throws CloudstackRESTException {
logRequestExecution(request);
try {
return client.execute(clientContext.getTargetHost(), request, clientContext);
} catch (final IOException e) {
throw new CloudstackRESTException("Could not execute request " + request, e);
}
}
private void logRequestExecution(final HttpUriRequest request) {
final URI uri = request.getURI();
String query = uri.getQuery();
query = query != null ? "?" + query : "";
s_logger.debug("Executig " + request.getMethod() + " request on " + clientContext.getTargetHost() + uri.getPath() + query);
}
@Override
public void closeResponse(final CloseableHttpResponse response) throws CloudstackRESTException {
try {
s_logger.debug("Closing HTTP connection");
response.close();
} catch (final IOException e) {
final StringBuilder sb = new StringBuilder();
sb.append("Failed to close response object for request.\nResponse: ").append(response);
throw new CloudstackRESTException(sb.toString(), e);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected static class Builder<T extends Builder> {
private CloseableHttpClient client;
private HttpClientContext clientContext = HttpClientContext.create();
private String host;
public T client(final CloseableHttpClient client) {
this.client = client;
return (T) this;
}
public T clientContext(final HttpClientContext clientContext) {
this.clientContext = clientContext;
return (T) this;
}
public T host(final String host) {
this.host = host;
return (T) this;
}
public BasicRestClient build() {
return new BasicRestClient(this);
}
}
}

View File

@ -0,0 +1,71 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.utils.rest;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.SSLContext;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.impl.client.StandardHttpRequestRetryHandler;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
public class HttpClientHelper {
private static final String HTTPS = HttpConstants.HTTPS;
public static CloseableHttpClient createHttpClient(final int maxRedirects) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
final Registry<ConnectionSocketFactory> socketFactoryRegistry = createSocketFactoryConfigration();
final BasicCookieStore cookieStore = new BasicCookieStore();
return HttpClientBuilder.create()
.setConnectionManager(new PoolingHttpClientConnectionManager(socketFactoryRegistry))
.setRedirectStrategy(new LaxRedirectStrategy())
.setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.DEFAULT).setMaxRedirects(maxRedirects).build())
.setDefaultCookieStore(cookieStore)
.setRetryHandler(new StandardHttpRequestRetryHandler())
.build();
}
private static Registry<ConnectionSocketFactory> createSocketFactoryConfigration() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
Registry<ConnectionSocketFactory> socketFactoryRegistry;
final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(new TrustSelfSignedStrategy()).build();
final SSLConnectionSocketFactory cnnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
.register(HTTPS, cnnectionSocketFactory)
.build();
return socketFactoryRegistry;
}
}

View File

@ -0,0 +1,34 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.utils.rest;
public class HttpConstants {
public static final int HTTPS_PORT = 443;
public static final String HTTPS = "https";
public static final String GET_METHOD_TYPE = "get";
public static final String DELETE_METHOD_TYPE = "delete";
public static final String PUT_METHOD_TYPE = "put";
public static final String POST_METHOD_TYPE = "post";
public static final String TEXT_HTML_CONTENT_TYPE = "text/html";
public static final String JSON_CONTENT_TYPE = "application/json";
public static final String CONTENT_TYPE = "Content-Type";
}

View File

@ -0,0 +1,41 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.utils.rest;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
public enum HttpMethods {
GET(HttpGet.METHOD_NAME), POST(HttpPost.METHOD_NAME), PUT(HttpPut.METHOD_NAME), DELETE(HttpDelete.METHOD_NAME);
private final String name;
private HttpMethods(final String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}

View File

@ -0,0 +1,119 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.utils.rest;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.http.Consts;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import org.springframework.util.Assert;
import com.google.common.base.Optional;
public class HttpUriRequestBuilder {
private static final String CONTENT_TYPE = HttpConstants.CONTENT_TYPE;
private static final String JSON_CONTENT_TYPE = HttpConstants.JSON_CONTENT_TYPE;
private static final Optional<String> ABSENT = Optional.absent();
private HttpMethods method;
private String path;
private Optional<String> jsonPayload = ABSENT;
private final Map<String, String> parameters = new HashMap<String, String>();
private final Map<String, String> methodParameters = new HashMap<String, String>();
private HttpUriRequestBuilder() {
}
public static HttpUriRequestBuilder create() {
return new HttpUriRequestBuilder();
}
public HttpUriRequestBuilder method(final HttpMethods method) {
this.method = method;
return this;
}
public HttpUriRequestBuilder path(final String path) {
this.path = path;
return this;
}
public HttpUriRequestBuilder jsonPayload(final Optional<String> jsonPayload) {
this.jsonPayload = jsonPayload;
return this;
}
public HttpUriRequestBuilder parameters(final Map<String, String> parameters) {
this.parameters.clear();
this.parameters.putAll(parameters);
return this;
}
public HttpUriRequestBuilder methodParameters(final Map<String, String> methodParameters) {
this.methodParameters.clear();
this.methodParameters.putAll(methodParameters);
return this;
}
public HttpUriRequest build() {
validate();
final RequestBuilder builder = RequestBuilder.create(method.toString()).setUri(buildUri());
if (!methodParameters.isEmpty()) {
for (final Entry<String, String> entry : methodParameters.entrySet()) {
builder.addParameter(entry.getKey(), entry.getValue());
}
}
if (jsonPayload.isPresent()) {
builder.addHeader(new BasicHeader(CONTENT_TYPE, JSON_CONTENT_TYPE))
.setEntity(new StringEntity(jsonPayload.get(), ContentType.create(JSON_CONTENT_TYPE, Consts.UTF_8)));
}
return builder.build();
}
private void validate() {
Assert.notNull(method, "HTTP Method cannot be null");
Assert.hasText(path, "target path must be defined");
Assert.isTrue(path.startsWith("/"), "targte path must start with a '/' character");
}
private URI buildUri() {
try {
final URIBuilder builder = new URIBuilder().setPath(path);
for (final Map.Entry<String, String> entry : parameters.entrySet()) {
builder.addParameter(entry.getKey(), entry.getValue());
}
return builder.build();
} catch (final URISyntaxException e) {
throw new IllegalArgumentException("Unable to build REST Service URI", e);
}
}
}

View File

@ -0,0 +1,31 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.utils.rest;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
public interface RestClient {
public CloseableHttpResponse execute(final HttpUriRequest request) throws CloudstackRESTException;
public void closeResponse(final CloseableHttpResponse response) throws CloudstackRESTException;
}

View File

@ -0,0 +1,106 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.utils.rest;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import org.apache.http.HttpHost;
import org.apache.http.ProtocolVersion;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicStatusLine;
import org.junit.BeforeClass;
import org.junit.Test;
public class BasicRestClientTest {
private static final String LOCALHOST = "localhost";
private static final String HTTPS = HttpConstants.HTTPS;
private static final StatusLine HTTP_200_REPSONSE = new BasicStatusLine(new ProtocolVersion(HTTPS, 1, 1), 200, "OK");
private static final StatusLine HTTP_503_STATUSLINE = new BasicStatusLine(new ProtocolVersion(HTTPS, 1, 1), 503, "Service unavailable");
private static final CloseableHttpResponse mockResponse = mock(CloseableHttpResponse.class);
private static CloseableHttpClient httpClient;
private static HttpUriRequest request;
@BeforeClass
public static void setupClass() throws Exception {
request = HttpUriRequestBuilder.create()
.method(HttpMethods.GET)
.path("/path")
.build();
httpClient = spy(HttpClientHelper.createHttpClient(2));
}
@Test
public void testExecuteRequest() throws Exception {
when(mockResponse.getStatusLine()).thenReturn(HTTP_200_REPSONSE);
doReturn(mockResponse).when(httpClient).execute(any(HttpHost.class), HttpRequestMatcher.eq(request), any(HttpClientContext.class));
final BasicRestClient restClient = BasicRestClient.create()
.host(LOCALHOST)
.client(httpClient)
.build();
final CloseableHttpResponse response = restClient.execute(request);
assertThat(response, notNullValue());
assertThat(response, sameInstance(mockResponse));
assertThat(response.getStatusLine(), sameInstance(HTTP_200_REPSONSE));
}
@Test
public void testExecuteRequestStatusCodeIsNotOk() throws Exception {
when(mockResponse.getStatusLine()).thenReturn(HTTP_503_STATUSLINE);
doReturn(mockResponse).when(httpClient).execute(any(HttpHost.class), HttpRequestMatcher.eq(request), any(HttpClientContext.class));
final BasicRestClient restClient = BasicRestClient.create()
.host(LOCALHOST)
.client(httpClient)
.build();
final CloseableHttpResponse response = restClient.execute(request);
assertThat(response, notNullValue());
assertThat(response, sameInstance(mockResponse));
assertThat(response.getStatusLine(), sameInstance(HTTP_503_STATUSLINE));
}
@Test(expected = CloudstackRESTException.class)
public void testExecuteRequestWhenClientThrowsIOException() throws Exception {
final BasicRestClient restClient = BasicRestClient.create()
.host(LOCALHOST)
.client(HttpClientHelper.createHttpClient(5))
.build();
restClient.execute(request);
}
}

View File

@ -0,0 +1,38 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.utils.rest;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.notNullValue;
import org.apache.http.impl.client.CloseableHttpClient;
import org.junit.Test;
public class HttpClientHelperTest {
@Test
public void testCreateClient() throws Exception {
int maxRedirects = 5;
final CloseableHttpClient client = HttpClientHelper.createHttpClient(maxRedirects);
assertThat(client, notNullValue());
}
}

View File

@ -0,0 +1,141 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.utils.rest;
import static org.mockito.Matchers.argThat;
import java.io.IOException;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.ParseException;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.util.EntityUtils;
import org.hamcrest.Description;
import org.hamcrest.SelfDescribing;
import org.mockito.ArgumentMatcher;
public class HttpRequestMatcher extends ArgumentMatcher<HttpRequest> {
private final HttpRequest wanted;
public HttpRequestMatcher(final HttpRequest wanted) {
this.wanted = wanted;
}
public static HttpRequest eq(final HttpRequest request) {
return argThat(new HttpRequestMatcher(request));
}
@Override
public boolean matches(final Object actual) {
if (actual instanceof HttpUriRequest) {
final HttpUriRequest converted = (HttpUriRequest) actual;
return checkMethod(converted) && checkUri(converted) && checkPayload(converted);
} else {
return wanted == actual;
}
}
private boolean checkPayload(final HttpUriRequest actual) {
final String wantedPayload = getPayload(wanted);
final String actualPayload = getPayload(actual);
return equalsString(wantedPayload, actualPayload);
}
private static String getPayload(final HttpRequest request) {
String payload = "";
if (request instanceof HttpEntityEnclosingRequest) {
try {
payload = EntityUtils.toString(((HttpEntityEnclosingRequest) request).getEntity());
} catch (final ParseException e) {
throw new IllegalArgumentException("Couldn't read request's entity payload.", e);
} catch (final IOException e) {
throw new IllegalArgumentException("Couldn't read request's entity payload.", e);
}
}
return payload;
}
private boolean checkUri(final HttpUriRequest actual) {
if (wanted instanceof HttpUriRequest) {
final String wantedQuery = ((HttpUriRequest) wanted).getURI().getQuery();
final String actualQuery = actual.getURI().getQuery();
return equalsString(wantedQuery, actualQuery);
} else {
return wanted == actual;
}
}
private boolean checkMethod(final HttpUriRequest actual) {
if (wanted instanceof HttpUriRequest) {
final String wantedMethod = ((HttpUriRequest) wanted).getMethod();
final String actualMethod = actual.getMethod();
return equalsString(wantedMethod, actualMethod);
} else {
return wanted == actual;
}
}
private static boolean equalsString(final String a, final String b) {
return a == b || a != null && a.equals(b);
}
@Override
public void describeTo(final Description description) {
description.appendText(describe(wanted));
}
public String describe(final HttpRequest object) {
final StringBuilder sb = new StringBuilder();
if (object instanceof HttpUriRequest) {
final HttpUriRequest converted = (HttpUriRequest) object;
sb.append("method = ").append(converted.getMethod());
sb.append(", query = ").append(converted.getURI().getQuery());
sb.append(", payload = ").append(getPayload(object));
}
return sb.toString();
}
@Override
public boolean equals(final Object o) {
return EqualsBuilder.reflectionEquals(this, o);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
public SelfDescribing withExtraTypeInfo() {
return new SelfDescribing() {
@Override
public void describeTo(final Description description) {
description.appendText("(" + wanted.getClass().getSimpleName() + ") ").appendText(describe(wanted));
}
};
}
public boolean typeMatches(final Object object) {
return wanted != null && object != null && object.getClass() == wanted.getClass();
}
}

View File

@ -0,0 +1,115 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.utils.rest;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import java.util.HashMap;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.junit.Test;
import com.google.common.base.Optional;
public class HttpUriRequestBuilderTest {
@Test(expected = IllegalArgumentException.class)
public void testBuildWithNullMethod() throws Exception {
HttpUriRequestBuilder.create().path("/path").build();
}
@Test(expected = IllegalArgumentException.class)
public void testBuildWithNullPath() throws Exception {
HttpUriRequestBuilder.create().method(HttpMethods.GET).build();
}
@Test(expected = IllegalArgumentException.class)
public void testBuildWithEmptyPath() throws Exception {
HttpUriRequestBuilder.create()
.method(HttpMethods.GET)
.path("")
.build();
}
@Test(expected = IllegalArgumentException.class)
public void testBuildWithIlegalPath() throws Exception {
HttpUriRequestBuilder.create()
.method(HttpMethods.GET)
.path("path")
.build();
}
@Test
public void testBuildSimpleRequest() throws Exception {
final HttpUriRequest request = HttpUriRequestBuilder.create()
.method(HttpMethods.GET)
.path("/path")
.build();
assertThat(request, notNullValue());
assertThat(request.getURI().getPath(), equalTo("/path"));
assertThat(request.getURI().getScheme(), nullValue());
assertThat(request.getURI().getQuery(), nullValue());
assertThat(request.getURI().getHost(), nullValue());
assertThat(request.getMethod(), equalTo(HttpGet.METHOD_NAME));
}
@Test
public void testBuildRequestWithParameters() throws Exception {
final HashMap<String, String> parameters = new HashMap<String, String>();
parameters.put("key1", "value1");
final HttpUriRequest request = HttpUriRequestBuilder.create()
.method(HttpMethods.GET)
.path("/path")
.parameters(parameters)
.build();
assertThat(request, notNullValue());
assertThat(request.getURI().getPath(), equalTo("/path"));
assertThat(request.getURI().getQuery(), equalTo("key1=value1"));
assertThat(request.getURI().getScheme(), nullValue());
assertThat(request.getURI().getHost(), nullValue());
assertThat(request.getMethod(), equalTo(HttpGet.METHOD_NAME));
}
@Test
public void testBuildRequestWithJsonPayload() throws Exception {
final HttpUriRequest request = HttpUriRequestBuilder.create()
.method(HttpMethods.GET)
.path("/path")
.jsonPayload(Optional.of("{'key1':'value1'}"))
.build();
assertThat(request, notNullValue());
assertThat(request.getURI().getPath(), equalTo("/path"));
assertThat(request.getURI().getScheme(), nullValue());
assertThat(request.getURI().getQuery(), nullValue());
assertThat(request.getURI().getHost(), nullValue());
assertThat(request.getMethod(), equalTo(HttpGet.METHOD_NAME));
assertThat(request.containsHeader(HttpConstants.CONTENT_TYPE), equalTo(true));
assertThat(request.getFirstHeader(HttpConstants.CONTENT_TYPE).getValue(), equalTo(HttpConstants.JSON_CONTENT_TYPE));
assertThat(request, HttpUriRequestPayloadMatcher.hasPayload("{'key1':'value1'}"));
}
}

View File

@ -0,0 +1,48 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.utils.rest;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Matchers.argThat;
import org.apache.http.client.methods.HttpUriRequest;
import org.hamcrest.FeatureMatcher;
import org.hamcrest.Matcher;
public class HttpUriRequestQueryMatcher extends FeatureMatcher<HttpUriRequest, String> {
public static HttpUriRequest aQuery(final String query) {
return argThat(new HttpUriRequestQueryMatcher(equalTo(query), "query", "query"));
}
public static HttpUriRequest aQueryThatContains(final String query) {
return argThat(new HttpUriRequestQueryMatcher(containsString(query), "query", "query"));
}
public HttpUriRequestQueryMatcher(final Matcher<? super String> subMatcher, final String featureDescription, final String featureName) {
super(subMatcher, featureDescription, featureName);
}
@Override
protected String featureValueOf(final HttpUriRequest actual) {
return actual.getURI().getQuery();
}
}