How to Mock a proxy connection in HttpClient in Java - java

I am trying to Mock the below code but unsuccessful, Can anyone suggest how this can be achieved.
HttpClient httpClient = HttpClient.create()
.tcpConfiguration(tcpClient -> tcpClient
.proxy(proxy -> proxy
.type(ProxyProvider.Proxy.HTTP)
.host(host)
.port(Integer.parseInt(port))));
ClientHttpConnector clientHttpConnector = new ReactorClientHttpConnector(httpClient);
webClient = WebClient.builder().clientConnector(clientHttpConnector).build();

Move the code which creates the HttpClient to it's own class:
interface HttpClientFactory {
HttpClient create();
}
class DefaultHttpClientFactory implements {
HttpClient create() {
return HttpClient.create()
.tcpConfiguration(tcpClient -> tcpCl...
}
}
Now you can mock HttpClientFactory and the mock HttpClient it returns.

Related

Use Apache HttpClient with caching enabled as Jersey 2 client

How can I use a custom configured Apache HttpClient with Jersey Client 2?
HttpClient with Caching (from apache docs)
CacheConfig cacheConfig = CacheConfig.custom()
.setMaxCacheEntries(1000)
.setMaxObjectSize(8192)
.build();
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(30000)
.setSocketTimeout(30000)
.build();
CloseableHttpClient cachingClient = CachingHttpClients.custom()
.setCacheConfig(cacheConfig)
.setDefaultRequestConfig(requestConfig)
.build();
Using Apache Http in general works by setting
protected ClientConfig getClientConfig() {
ClientConfig config = new ClientConfig();
config.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true);
final PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
config.property(ApacheClientProperties.CONNECTION_MANAGER, connectionManager);
final ApacheConnectorProvider connector = new ApacheConnectorProvider();
config.connectorProvider(connector);
return config;
}
But how to use custom http client config like above?
You can use ApacheHttpClientBuilderConfigurator. So you can do:
config.register(new ApacheHttpClientBuilderConfigurator() {
public HttpClientBuilder configure(HttpClientBuilder httpClientBuilder) {
return httpClientBuilder.setDefaultRequestConfig(requestConfig);
}
});
See the example.
The Apache caching client is not properly supported at the moment. You may return CachingHttpClientBuilder from the method, but the HttpClientBuilder does not have getters to see what is already set, so you need to set everything from scratch.

Writing Mock class for java http client

I am trying to write unit test cases for my HTTP Client and would like to use mockito to mock the responses received from the server.
public HttpResponse postRequest(String uri, String body) throws IOException {
HttpResponse response;
String url = baseUrl + uri;
try (CloseableHttpClient httpClient = HttpClientBuilder.create()
.build()) {
HttpPost post = new HttpPost(url);
post.setEntity(new StringEntity(body));
post.setHeader(AUTHORIZATION_HEADER, authorization);
post.setHeader(CONTENTTYPE_HEADER, APPLICATION_JSON);
post.setHeader(ACCEPT_HEADER, APPLICATION_JSON);
response = httpClient.execute(post);
} catch (IOException e) {
System.out.println("Caught an exception" + e.getMessage().toString());
logger.error("Caught an exception" + e.getMessage().toString());
throw e;
}
return response;
}
My test class is as follows. I am unable to figure out how I should send my response body.
public class HTTPRequestTest extends Mockito {
private String body = "{a:b}";
#Test
public void xyz throws Exception {
HttpClient httpClient = mock(HttpClient.class);
HttpPost httpPost = mock(HttpPost.class);
HttpResponse httpResponse = mock(HttpResponse.class);
StatusLine statusLine = mock(StatusLine.class);
when(httpClient.execute(httpPost)).thenReturn(body);
}
}
Using PowerMockito :
First annotate your test class
#RunWith(PowerMockRunner.class)
#PrepareForTest(HttpClientBuilder.class)
then your test method can be something like:
#Test
public void xyz() throws Exception {
HttpClientBuilder mockClientBuilder = PowerMockito.mock(HttpClientBuilder.class);
CloseableHttpClient mockHttpClient = PowerMockito.mock(CloseableHttpClient.class);
CloseableHttpResponse mockResponse = PowerMockito.mock(CloseableHttpResponse.class);
PowerMockito.mockStatic(HttpClientBuilder.class);
PowerMockito.when(HttpClientBuilder.class, "create").thenReturn(mockClientBuilder);
PowerMockito.when(mockClientBuilder.build()).thenReturn(mockHttpClient);
PowerMockito.when(mockHttpClient.execute(any(HttpPost.class))).thenReturn(mockResponse);
HttpResponse response = classUnderTest.postRequest("uri", "body");
//assertResponse
}
The problem is that your HttpClient mock isn't being used in your unit test.
Your postRequest function creates a new HttpClient using this method:
HttpClientBuilder.create().build()
HttpClientBuilder instantiates a new HttpClient, which is a totally separate instance of HttpClient than the mock you create in your unit test. Unfortunately, there isn't an easy way to test your code as written because Mockito can't mock static methods (like HttpClientBuilder.create). See this post for more discussion of this problem and possible workarounds.
To summarize that post, your options are to either rewrite your code so you can inject a mock more easily, or switch to a mocking framework that can mock static methods (like PowerMock).
As suggested in other answers, PowerMock is definitely an option here to mock static methods (in your case HttpClientBuilder.create().build()), however, for your particular instance, you can also resolve the issue by moving the instantiation of the HttpClient out of your doPost method and declare it as instance variable.
#Mock
CloseableHttpClient httpClient = HttpClientBuilder.create().build()
This way when you mock using Mockito, it will be a mocked object. In JUnit5, this can be done by using #Mock above the CloseableHttpClient declaration and then initializing all mocks in the setup method.

Mocking Apache HttpClient 4.4 PoolingHttpClientConnectionManager

I know how to mock a default HttpClient, but how do I mock the latest (v4.4) HttpClient that is created using a PoolingHttpClientConnectionManager with Mockito?
My code looks like this:
PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager();
...
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(mgr).build();
HttpResponse response = httpClient.execute(request);
... // here I want to substitute a mocked HttpResponse
It is likely to be easier to mock out HttpRequestExecutor than HttpClientConnection. You would still need to provide a no-op implementation of HttpClientConnectionManager in order to prevent HttpClient from creating and connecting sockets
HttpRequestExecutor requestExecutor = Mockito.mock(HttpRequestExecutor.class);
Mockito.when(requestExecutor.execute(
Mockito.<HttpRequest>any(),
Mockito.<HttpClientConnection>any(),
Mockito.<HttpContext>any())).thenReturn(new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "Hah"));
HttpClientConnectionManager cm = Mockito.mock(HttpClientConnectionManager.class);
HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
ConnectionRequest connRequest = Mockito.mock(ConnectionRequest.class);
Mockito.when(cm.requestConnection(
Mockito.<HttpRoute>any(),
Mockito.any())).thenReturn(connRequest);
Mockito.when(connRequest.get(
Mockito.anyLong(),
Mockito.<TimeUnit>any())).thenReturn(conn);
CloseableHttpClient client = HttpClients.custom()
.setRequestExecutor(requestExecutor)
.setConnectionManager(cm)
.build();
CloseableHttpResponse response = client.execute(new HttpGet("http://pampa/"));
try {
System.out.println(response.getStatusLine());
} finally {
response.close();
}
Just realized that PoolingHttpClientConnectionManager is the default connection manager used by HttpClient built with HttpClients.custom().build() (at least in v4.4), so I just went back to mocking the HttpClient.
protected HttpClient buildHttpClient() {
return HttpClients.custom()./* other config */.build();
}
unit test code:
#Mock
HttpClient mockClient;
#Mock
HttpResponse mockResponse;
#Spy
MyClass myclass = new MyClass();
. . .
#Test
public void myTestCase() {
. . .
when(myclass.buildHttpClient()).thenReturn(mockClient);
when(mockClient.execute(requestCaptor.capture())).thenReturn(mockResponse);
. . .

How do I replace Deprecated httpClient.getParams() with RequestConfig?

I have inherited the code
import org.apache.http.client.HttpClient;
...
HttpClient httpclient = createHttpClientOrProxy();
...
private HttpClient createHttpClientOrProxy() {
HttpClient httpclient = new DefaultHttpClient();
/*
* Set an HTTP proxy if it is specified in system properties.
*
* http://docs.oracle.com/javase/6/docs/technotes/guides/net/proxies.html
* http://hc.apache.org/httpcomponents-client-ga/httpclient/examples/org/apache/http/examples/client/ClientExecuteProxy.java
*/
if( isSet(System.getProperty("http.proxyHost")) ) {
int port = 80;
if( isSet(System.getProperty("http.proxyPort")) ) {
port = Integer.parseInt(System.getProperty("http.proxyPort"));
}
HttpHost proxy = new HttpHost(System.getProperty("http.proxyHost"), port, "http");
// #Deprecated methods here... getParams() and ConnRoutePNames
httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
}
return httpclient;
}
httpClient.getParams() is #Deprecated and reads "
HttpParams getParams()
Deprecated.
(4.3) use RequestConfig.
There are no class docs for RequestConfig and I do not know what method should be used to replace getParams() and ConnRoutePNames.DEFAULT_PROXY.
This is more of a follow-up to the answer given by #Stephane Lallemagne
There is a much conciser way of making HttpClient pick up system proxy settings
CloseableHttpClient client = HttpClients.custom()
.setRoutePlanner(
new SystemDefaultRoutePlanner(ProxySelector.getDefault()))
.build();
or this if you want an instance of HttpClient fully configured with system defaults
CloseableHttpClient client = HttpClients.createSystem();
You are using apache HttpClient 4.3 library with apache HttpClient 4.2 code.
Please notice that getParams() and ConnRoutePNames are not the only deprecated methods in your case. The DefaultHttpClient class itself rely on 4.2 implementation and is also deprecated in 4.3.
In regard to the 4.3 documentation here (http://hc.apache.org/httpcomponents-client-4.3.x/tutorial/html/connmgmt.html#d5e473), you can rewrite it this way:
private HttpClient createHttpClientOrProxy() {
HttpClientBuilder hcBuilder = HttpClients.custom();
// Set HTTP proxy, if specified in system properties
if( isSet(System.getProperty("http.proxyHost")) ) {
int port = 80;
if( isSet(System.getProperty("http.proxyPort")) ) {
port = Integer.parseInt(System.getProperty("http.proxyPort"));
}
HttpHost proxy = new HttpHost(System.getProperty("http.proxyHost"), port, "http");
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
hcBuilder.setRoutePlanner(routePlanner);
}
CloseableHttpClient httpClient = hcBuilder.build();
return httpClient;
}

Apache HTTP client, request from specific network interface

I have machine with 4 internet IP's and I want to know if I can make apache http client to make requests from specific ip/network interface
Using HttpClient 4.3 APIs
RequestConfig config = RequestConfig.custom()
.setLocalAddress(InetAddress.getByAddress(new byte[] {127,0,0,1}))
.build();
HttpGet httpGet = new HttpGet("/stuff");
httpGet.setConfig(config);
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
CloseableHttpResponse response = httpClient.execute(httpGet);
try {
// do something useful
} finally {
response.close();
}
} finally {
httpClient.close();
}
Never did this, but there is a ClientConnectionOperator interface (and some factories too) in the API to create the socket. Maybe you can implement your own and create the socket with a concrete interface.

Categories