mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-02 20:02:29 +01:00
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:
parent
6e74ef8e40
commit
8a93bb8d2d
2
pom.xml
2
pom.xml
@ -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>
|
||||
|
||||
118
utils/src/main/java/com/cloud/utils/rest/BasicRestClient.java
Normal file
118
utils/src/main/java/com/cloud/utils/rest/BasicRestClient.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
34
utils/src/main/java/com/cloud/utils/rest/HttpConstants.java
Normal file
34
utils/src/main/java/com/cloud/utils/rest/HttpConstants.java
Normal 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";
|
||||
|
||||
}
|
||||
41
utils/src/main/java/com/cloud/utils/rest/HttpMethods.java
Normal file
41
utils/src/main/java/com/cloud/utils/rest/HttpMethods.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
31
utils/src/main/java/com/cloud/utils/rest/RestClient.java
Normal file
31
utils/src/main/java/com/cloud/utils/rest/RestClient.java
Normal 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;
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
141
utils/src/test/java/com/cloud/utils/rest/HttpRequestMatcher.java
Normal file
141
utils/src/test/java/com/cloud/utils/rest/HttpRequestMatcher.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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'}"));
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user