PageRenderTime 31ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/sal-core/src/test/java/com/atlassian/sal/core/net/TestHttpClientRequest.java

https://bitbucket.org/atlassian/atlassian-sal
Java | 536 lines | 419 code | 99 blank | 18 comment | 0 complexity | c06c7fa97c143daeb458f96f289fc5c6 MD5 | raw file
  1. package com.atlassian.sal.core.net;
  2. import com.atlassian.plugin.util.PluginKeyStack;
  3. import com.atlassian.sal.api.net.Request;
  4. import com.atlassian.sal.api.net.ResponseException;
  5. import com.atlassian.util.profiling.MetricKey;
  6. import com.atlassian.util.profiling.MetricTag;
  7. import com.atlassian.util.profiling.StrategiesRegistry;
  8. import com.atlassian.util.profiling.strategy.MetricStrategy;
  9. import com.google.common.base.Throwables;
  10. import org.apache.commons.codec.binary.Base64;
  11. import org.apache.http.Header;
  12. import org.apache.http.HttpClientConnection;
  13. import org.apache.http.HttpEntityEnclosingRequest;
  14. import org.apache.http.HttpException;
  15. import org.apache.http.HttpHost;
  16. import org.apache.http.HttpRequest;
  17. import org.apache.http.HttpResponse;
  18. import org.apache.http.HttpStatus;
  19. import org.apache.http.NameValuePair;
  20. import org.apache.http.ProtocolVersion;
  21. import org.apache.http.auth.AUTH;
  22. import org.apache.http.client.RedirectException;
  23. import org.apache.http.client.config.AuthSchemes;
  24. import org.apache.http.client.utils.URLEncodedUtils;
  25. import org.apache.http.conn.ConnectionRequest;
  26. import org.apache.http.conn.HttpClientConnectionManager;
  27. import org.apache.http.conn.routing.HttpRoute;
  28. import org.apache.http.entity.StringEntity;
  29. import org.apache.http.message.BasicHttpResponse;
  30. import org.apache.http.message.BasicNameValuePair;
  31. import org.apache.http.protocol.HttpContext;
  32. import org.apache.http.protocol.HttpRequestExecutor;
  33. import org.hamcrest.FeatureMatcher;
  34. import org.hamcrest.Matcher;
  35. import org.hamcrest.Matchers;
  36. import org.junit.Before;
  37. import org.junit.Rule;
  38. import org.junit.Test;
  39. import org.junit.contrib.java.lang.system.RestoreSystemProperties;
  40. import org.junit.rules.ExpectedException;
  41. import org.junit.runner.RunWith;
  42. import org.mockito.ArgumentCaptor;
  43. import org.mockito.Mock;
  44. import org.mockito.invocation.InvocationOnMock;
  45. import org.mockito.junit.MockitoJUnitRunner;
  46. import org.mockito.stubbing.Answer;
  47. import java.io.IOException;
  48. import java.net.URI;
  49. import java.net.URISyntaxException;
  50. import java.nio.charset.StandardCharsets;
  51. import java.text.MessageFormat;
  52. import java.util.List;
  53. import java.util.concurrent.ExecutionException;
  54. import java.util.concurrent.TimeUnit;
  55. import java.util.stream.Collectors;
  56. import static com.atlassian.sal.core.net.HttpClientRequest.METRIC_NAME;
  57. import static org.hamcrest.CoreMatchers.instanceOf;
  58. import static org.hamcrest.CoreMatchers.is;
  59. import static org.hamcrest.CoreMatchers.not;
  60. import static org.hamcrest.CoreMatchers.notNullValue;
  61. import static org.hamcrest.MatcherAssert.assertThat;
  62. import static org.hamcrest.Matchers.arrayContaining;
  63. import static org.hamcrest.Matchers.contains;
  64. import static org.hamcrest.Matchers.hasItems;
  65. import static org.hamcrest.Matchers.typeCompatibleWith;
  66. import static org.hamcrest.core.IsEqual.equalTo;
  67. import static org.junit.Assert.fail;
  68. import static org.mockito.ArgumentMatchers.any;
  69. import static org.mockito.ArgumentMatchers.anyInt;
  70. import static org.mockito.ArgumentMatchers.anyLong;
  71. import static org.mockito.Mockito.mock;
  72. import static org.mockito.Mockito.times;
  73. import static org.mockito.Mockito.verify;
  74. import static org.mockito.Mockito.when;
  75. @RunWith(MockitoJUnitRunner.class)
  76. public class TestHttpClientRequest {
  77. @Rule
  78. public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
  79. private static final String DUMMY_HOST = "dummy.atlassian.test";
  80. private static final String DUMMY_HTTP_URL = MessageFormat.format("http://{0}:8090/", DUMMY_HOST);
  81. private static final String DUMMY_PROXY_HOST = "dummy.proxy.atlassian.test";
  82. private static final String DUMMY_PROXY_PORT = "12345";
  83. private static final String DUMMY_PROXY_USER = "dummyproxyuser";
  84. private static final String DUMMY_PROXY_PASSWORD = "dummyproxypassword";
  85. @Rule
  86. public ExpectedException thrown = ExpectedException.none();
  87. @Mock
  88. private HttpRequestExecutor mockRequestExecutor;
  89. @Mock
  90. private HttpClientConnectionManager mockConnectionManager;
  91. private HttpClientRequestFactory requestFactory;
  92. private final ArgumentCaptor<HttpRequest> requestCaptor = ArgumentCaptor.forClass(HttpRequest.class);
  93. private final ArgumentCaptor<HttpRoute> routeCaptor = ArgumentCaptor.forClass(HttpRoute.class);
  94. @Before
  95. public void setup() throws InterruptedException, ExecutionException, IOException, HttpException {
  96. // Clear all system proxy settings
  97. requestFactory = new HttpClientWithMockConnectionRequestFactory(mockConnectionManager, mockRequestExecutor);
  98. // Always respond with a 200/OK message
  99. when(mockRequestExecutor.execute(any(HttpRequest.class), any(HttpClientConnection.class),
  100. any(HttpContext.class))).thenReturn(createOkResponse());
  101. // This allows us to hook in to the connection details that HttpClient would have made
  102. final HttpClientConnection conn = mock(HttpClientConnection.class);
  103. final ConnectionRequest connRequest = mock(ConnectionRequest.class);
  104. when(connRequest.get(anyLong(), any(TimeUnit.class))).thenReturn(conn);
  105. when(mockConnectionManager.requestConnection(any(HttpRoute.class), any())).thenReturn(connRequest);
  106. }
  107. private static HttpResponse createOkResponse() {
  108. final BasicHttpResponse response = new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 1), HttpStatus.SC_OK, "OK");
  109. response.setEntity(new StringEntity("test body", StandardCharsets.UTF_8));
  110. return response;
  111. }
  112. private static HttpResponse createRedirectResponse(String location) {
  113. final BasicHttpResponse response = new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 1), HttpStatus.SC_MOVED_PERMANENTLY, "Redirect");
  114. response.setEntity(new StringEntity("Redirect", StandardCharsets.UTF_8));
  115. response.setHeader("Location", location);
  116. return response;
  117. }
  118. private static HttpResponse createNoContentResponse() {
  119. return new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 1), HttpStatus.SC_NO_CONTENT, "No Content");
  120. }
  121. @Test
  122. public void assertThatHeaderIsAddedToRequest() throws ResponseException, IOException, HttpException {
  123. final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
  124. final String testHeaderName = "foo";
  125. final String testHeaderValue = "bar";
  126. request.addHeader(testHeaderName, testHeaderValue);
  127. request.execute();
  128. verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
  129. final HttpRequest lastRequest = requestCaptor.getValue();
  130. assertThat(lastRequest, notNullValue());
  131. final Header[] headers = lastRequest.getHeaders(testHeaderName);
  132. //noinspection unchecked
  133. assertThat(headers, arrayContaining(headerWithValue(equalTo(testHeaderValue))));
  134. }
  135. @Test
  136. public void assertThatMultiValuedHeadersAreAddedToRequest() throws ResponseException, IOException, HttpException {
  137. final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
  138. final String testHeaderName = "foo";
  139. final String testHeaderValue1 = "bar1";
  140. final String testHeaderValue2 = "bar2";
  141. request.addHeader(testHeaderName, testHeaderValue1);
  142. request.addHeader(testHeaderName, testHeaderValue2);
  143. request.execute();
  144. verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
  145. final HttpRequest lastRequest = requestCaptor.getValue();
  146. assertThat(lastRequest, notNullValue());
  147. final Header[] headers = lastRequest.getHeaders(testHeaderName);
  148. //noinspection unchecked
  149. assertThat(headers, arrayContaining(
  150. headerWithValue(equalTo(testHeaderValue1)),
  151. headerWithValue(equalTo(testHeaderValue2))));
  152. }
  153. @Test
  154. public void testThatRouteIsNotCached() throws ResponseException, IOException {
  155. System.setProperty(SystemPropertiesProxyConfig.PROXY_HOST_PROPERTY_NAME, DUMMY_PROXY_HOST);
  156. System.setProperty(SystemPropertiesProxyConfig.PROXY_PORT_PROPERTY_NAME, DUMMY_PROXY_PORT);
  157. final HttpClientRequestFactory factory = new HttpClientWithMockConnectionRequestFactory(mockConnectionManager, mockRequestExecutor);
  158. HttpClientRequest request = factory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
  159. request.execute();
  160. System.setProperty(SystemPropertiesProxyConfig.PROXY_HOST_PROPERTY_NAME, "hostName");
  161. System.setProperty(SystemPropertiesProxyConfig.PROXY_PORT_PROPERTY_NAME, "1234");
  162. request = requestFactory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
  163. request.execute();
  164. verify(mockConnectionManager, times(2)).connect(any(HttpClientConnection.class), routeCaptor.capture(), anyInt(), any(HttpContext.class
  165. ));
  166. List<HttpRoute> routes = routeCaptor.getAllValues();
  167. assertThat(routes.get(0), proxyHostIs(hostWithNameAndPort(DUMMY_PROXY_HOST, Integer.parseInt(DUMMY_PROXY_PORT))));
  168. assertThat(routes.get(1), proxyHostIs(hostWithNameAndPort("hostName", Integer.parseInt("1234"))));
  169. }
  170. @Test
  171. public void assertThatParameterIsAddedToRequest() throws IOException, ResponseException, HttpException {
  172. final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.POST, DUMMY_HTTP_URL);
  173. final String testParameterName = "foo";
  174. final String testParameterValue = "bar";
  175. request.addRequestParameters(testParameterName, testParameterValue);
  176. request.execute();
  177. verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
  178. final HttpRequest lastRequest = requestCaptor.getValue();
  179. assertThat(lastRequest, notNullValue());
  180. assertThat(lastRequest.getClass(), is(typeCompatibleWith(HttpEntityEnclosingRequest.class)));
  181. assertThat(lastRequest, requestParameters(contains(parameterWithNameAndValue(
  182. testParameterName, testParameterValue))));
  183. }
  184. @Test
  185. public void assertThatMultiValuedParametersAreAddedToRequest() throws IOException, ResponseException, HttpException {
  186. final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.POST, DUMMY_HTTP_URL);
  187. final String testParameterName = "foo";
  188. final String testParameterValue1 = "bar1";
  189. final String testParameterValue2 = "bar2";
  190. request.addRequestParameters(testParameterName, testParameterValue1, testParameterName, testParameterValue2);
  191. request.execute();
  192. verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
  193. final HttpRequest lastRequest = requestCaptor.getValue();
  194. assertThat(lastRequest, notNullValue());
  195. assertThat(lastRequest.getClass(), is(typeCompatibleWith(HttpEntityEnclosingRequest.class)));
  196. //noinspection unchecked
  197. assertThat(lastRequest, requestParameters(contains(
  198. parameterWithNameAndValue(testParameterName, testParameterValue1),
  199. parameterWithNameAndValue(testParameterName, testParameterValue2)
  200. )));
  201. }
  202. @Test
  203. public void assertThatParametersAreAddedWithMultipleCalls() throws IOException, ResponseException, HttpException {
  204. final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.POST, DUMMY_HTTP_URL);
  205. final String testParameterName = "foo";
  206. final String testParameterValue1 = "bar1";
  207. final String testParameterValue2 = "bar2";
  208. request.addRequestParameters(testParameterName, testParameterValue1);
  209. request.addRequestParameters(testParameterName, testParameterValue2);
  210. request.execute();
  211. verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
  212. final HttpRequest lastRequest = requestCaptor.getValue();
  213. assertThat(lastRequest, notNullValue());
  214. assertThat(lastRequest.getClass(), is(typeCompatibleWith(HttpEntityEnclosingRequest.class)));
  215. //noinspection unchecked
  216. assertThat(lastRequest, requestParameters(contains(
  217. parameterWithNameAndValue(testParameterName, testParameterValue1),
  218. parameterWithNameAndValue(testParameterName, testParameterValue2)
  219. )));
  220. }
  221. @Test
  222. public void assertThatAddingParametersToGetRequestThrowsException() {
  223. final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
  224. thrown.expect(IllegalStateException.class);
  225. request.addRequestParameters("foo", "bar");
  226. }
  227. @Test
  228. public void assertThatSystemProxyHostSettingHonoured() throws IOException, ResponseException, HttpException {
  229. System.setProperty(SystemPropertiesProxyConfig.PROXY_HOST_PROPERTY_NAME, DUMMY_PROXY_HOST);
  230. System.setProperty(SystemPropertiesProxyConfig.PROXY_PORT_PROPERTY_NAME, DUMMY_PROXY_PORT);
  231. final HttpClientRequestFactory factory = new HttpClientWithMockConnectionRequestFactory(mockConnectionManager, mockRequestExecutor);
  232. final HttpClientRequest request = factory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
  233. request.execute();
  234. verify(mockConnectionManager).connect(any(HttpClientConnection.class), routeCaptor.capture(), anyInt(), any(HttpContext.class));
  235. HttpRoute route = routeCaptor.getValue();
  236. assertThat(route, proxyHostIs(hostWithNameAndPort(DUMMY_PROXY_HOST, Integer.parseInt(DUMMY_PROXY_PORT))));
  237. }
  238. @Test
  239. public void assertThatProxyNotUsedByDefault() throws IOException, ResponseException, HttpException {
  240. final HttpClientRequestFactory factory = new HttpClientWithMockConnectionRequestFactory(mockConnectionManager, mockRequestExecutor);
  241. final HttpClientRequest request = factory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
  242. request.execute();
  243. verify(mockConnectionManager).connect(any(HttpClientConnection.class), routeCaptor.capture(), anyInt(), any(HttpContext.class));
  244. final HttpRoute route = routeCaptor.getValue();
  245. assertThat(route, proxyHostIs(Matchers.nullValue(HttpHost.class)));
  246. }
  247. @Test
  248. public void assertThatNonProxyHostsSystemPropertyHonoured() throws IOException, ResponseException, HttpException {
  249. System.setProperty(SystemPropertiesProxyConfig.PROXY_HOST_PROPERTY_NAME, DUMMY_PROXY_HOST);
  250. System.setProperty(SystemPropertiesProxyConfig.PROXY_PORT_PROPERTY_NAME, DUMMY_PROXY_PORT);
  251. System.setProperty(SystemPropertiesProxyConfig.PROXY_NON_HOSTS_PROPERTY_NAME, "localhost");
  252. final HttpClientRequestFactory factory = new HttpClientWithMockConnectionRequestFactory(mockConnectionManager, mockRequestExecutor);
  253. // deliberatly set after factory is created to match
  254. // how jira and confluence use it
  255. System.setProperty(SystemPropertiesProxyConfig.PROXY_NON_HOSTS_PROPERTY_NAME, "*.notproxied.test|localhost");
  256. final HttpClientRequest request = factory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
  257. request.execute();
  258. request.setUrl("http://www.notproxied.test").execute();
  259. verify(mockConnectionManager, times(2)).connect(any(HttpClientConnection.class), routeCaptor.capture(), anyInt(), any(HttpContext.class));
  260. final List<HttpRoute> routes = routeCaptor.getAllValues();
  261. //noinspection unchecked
  262. assertThat(routes, contains(
  263. proxyHostIs(hostWithNameAndPort(DUMMY_PROXY_HOST, Integer.parseInt(DUMMY_PROXY_PORT))),
  264. proxyHostIs(Matchers.nullValue(HttpHost.class))
  265. ));
  266. }
  267. @Test
  268. public void assertThatProxyAuthenticationSystemPropertyHonoured() throws IOException, ResponseException, HttpException {
  269. System.setProperty(SystemPropertiesProxyConfig.PROXY_HOST_PROPERTY_NAME, DUMMY_PROXY_HOST);
  270. System.setProperty(SystemPropertiesProxyConfig.PROXY_PORT_PROPERTY_NAME, DUMMY_PROXY_PORT);
  271. System.setProperty(SystemPropertiesProxyConfig.PROXY_USER_PROPERTY_NAME, DUMMY_PROXY_USER);
  272. System.setProperty(SystemPropertiesProxyConfig.PROXY_PASSWORD_PROPERTY_NAME, DUMMY_PROXY_PASSWORD);
  273. final HttpClientRequestFactory factory = new HttpClientWithMockConnectionRequestFactory(mockConnectionManager, mockRequestExecutor);
  274. final HttpClientRequest request = factory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
  275. final String username = "charlie";
  276. final String password = "password123";
  277. request.addBasicAuthentication(DUMMY_HOST, username, password);
  278. request.execute();
  279. verify(mockConnectionManager).connect(any(HttpClientConnection.class), routeCaptor.capture(), anyInt(), any(HttpContext.class));
  280. final HttpRoute route = routeCaptor.getValue();
  281. assertThat(route, proxyHostIs(hostWithNameAndPort(DUMMY_PROXY_HOST, Integer.parseInt(DUMMY_PROXY_PORT))));
  282. verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
  283. final HttpRequest lastRequest = requestCaptor.getValue();
  284. final Header[] headers = lastRequest.getHeaders(AUTH.PROXY_AUTH_RESP);
  285. //noinspection unchecked
  286. assertThat(headers, arrayContaining(headerWithValue(
  287. basicAuthWithUsernameAndPassword(DUMMY_PROXY_USER, DUMMY_PROXY_PASSWORD))));
  288. }
  289. private void assertThatBasicAuthenticationHeadersAdded(String url) throws ResponseException,URISyntaxException,IOException,HttpException {
  290. final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.GET, url);
  291. final String username = "charlie";
  292. final String password = "password123";
  293. final URI uri = new URI(url);
  294. request.addBasicAuthentication(uri.getHost(), username, password);
  295. request.execute();
  296. verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
  297. final HttpRequest lastRequest = requestCaptor.getValue();
  298. final Header[] headers = lastRequest.getHeaders(AUTH.WWW_AUTH_RESP);
  299. //noinspection unchecked
  300. assertThat(headers, arrayContaining(headerWithValue(basicAuthWithUsernameAndPassword(username, password))));
  301. }
  302. @Test
  303. public void assertThatBasicAuthenticationHeadersAddedDefaultPort() throws ResponseException,URISyntaxException,IOException,HttpException {
  304. assertThatBasicAuthenticationHeadersAdded(MessageFormat.format("http://{0}/", DUMMY_HOST));
  305. }
  306. @Test
  307. public void assertThatBasicAuthenticationHeadersAddedNotDefaultPort() throws ResponseException,URISyntaxException,IOException,HttpException {
  308. assertThatBasicAuthenticationHeadersAdded(MessageFormat.format("http://{0}:8090/", DUMMY_HOST));
  309. }
  310. @Test
  311. public void assertThatBasicAuthenticationHeadersAddedForHttpsNotDefaultPort() throws ResponseException,URISyntaxException,IOException,HttpException {
  312. assertThatBasicAuthenticationHeadersAdded(MessageFormat.format("https://{0}:8090/", DUMMY_HOST));
  313. }
  314. @Test
  315. public void assertThatBasicAuthenticationHeadersAddedForHttpsDefaultPort() throws ResponseException,URISyntaxException,IOException,HttpException {
  316. assertThatBasicAuthenticationHeadersAdded(MessageFormat.format("https://{0}/", DUMMY_HOST));
  317. }
  318. @Test
  319. public void assertThatExceptionThrownAfterDefaultMaximumRedirects() throws ResponseException, IOException, HttpException {
  320. when(mockRequestExecutor.execute(any(HttpRequest.class), any(HttpClientConnection.class),
  321. any(HttpContext.class))).thenAnswer(new Answer<HttpResponse>() {
  322. int redirectCount = 0;
  323. @Override
  324. public HttpResponse answer(final InvocationOnMock invocationOnMock) throws Throwable {
  325. // We just add a changing query string parameter here to avoid a circular redirect
  326. return createRedirectResponse(DUMMY_HTTP_URL + "?redirect_count=" + redirectCount++);
  327. }
  328. });
  329. final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
  330. try {
  331. request.execute();
  332. fail("An exception should be thrown when maximum redirects is exceeded.");
  333. } catch (ResponseException expectedException) {
  334. // Although JUnit has an ExpectedException rule, we need to catch this both to ensure that a
  335. // RedirectException is the cause, and to subsequently verify the execution method call count.
  336. assertThat(Throwables.getCausalChain(expectedException), Matchers.hasItem(instanceOf(RedirectException.class)));
  337. }
  338. verify(mockRequestExecutor, times(SystemPropertiesConnectionConfig.DEFAULT_MAX_REDIRECTS + 1))
  339. .execute(any(HttpRequest.class), any(HttpClientConnection.class), any(HttpContext.class));
  340. }
  341. @Test
  342. public void assertThatNoContentDoesNotThrowNPE() throws ResponseException, IOException, HttpException {
  343. when(mockRequestExecutor.execute(any(HttpRequest.class), any(HttpClientConnection.class),
  344. any(HttpContext.class))).thenAnswer(new Answer<HttpResponse>() {
  345. @Override
  346. public HttpResponse answer(final InvocationOnMock invocationOnMock) throws Throwable {
  347. return createNoContentResponse();
  348. }
  349. });
  350. final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
  351. try {
  352. request.execute();
  353. }
  354. catch (Exception e) {
  355. //If we catch an exception, check that it's not a NPE
  356. assertThat(Throwables.getRootCause(e),Matchers.not(instanceOf(NullPointerException.class)));
  357. }
  358. }
  359. @Test
  360. public void assertThatRequestParameterIsUTF8Encoded() throws ResponseException, IOException, HttpException
  361. {
  362. final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.POST, DUMMY_HTTP_URL);
  363. final String testParameterName = "test";
  364. final String testParameterValue = "ั‚ะตัั‚";
  365. request.addRequestParameters(testParameterName, testParameterValue);
  366. request.execute();
  367. verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
  368. final HttpRequest lastRequest = requestCaptor.getValue();
  369. //noinspection unchecked
  370. assertThat(lastRequest, requestParameters(contains(
  371. parameterWithNameAndValue(testParameterName, testParameterValue)
  372. )));
  373. }
  374. @Test
  375. public void assertThatRequestExecutionTriggersCorrectMetrics() throws ResponseException, IOException, HttpException {
  376. String pluginKey = "ita";
  377. PluginKeyStack.push(pluginKey);
  378. MetricStrategy metricStrategy = mock(MetricStrategy.class);
  379. ArgumentCaptor<MetricKey> metricCaptor = ArgumentCaptor.forClass(MetricKey.class);
  380. StrategiesRegistry.addMetricStrategy(metricStrategy);
  381. final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
  382. request.execute();
  383. verify(metricStrategy).startTimer(metricCaptor.capture());
  384. assertThat(metricCaptor.getValue().getMetricName(), is(METRIC_NAME));
  385. assertThat(metricCaptor.getValue().getTags(),
  386. hasItems(MetricTag.of("action", "GET"),
  387. MetricTag.of("pluginKeyAtCreation", pluginKey)));
  388. // path is optional tag and should not be outputted
  389. assertThat(metricCaptor.getValue().getTags()
  390. .stream()
  391. .map(MetricTag::getKey)
  392. .collect(Collectors.toList()), not(hasItems("url")));
  393. }
  394. private static Matcher<Header> headerWithValue(final Matcher<String> valueMatcher) {
  395. return new FeatureMatcher<Header, String>(valueMatcher, "header with value", "header value") {
  396. @Override
  397. protected String featureValueOf(final Header header) {
  398. return header.getValue();
  399. }
  400. };
  401. }
  402. private static Matcher<HttpRequest> requestParameters(final Matcher<Iterable<? extends NameValuePair>> parametersMatcher) {
  403. return new FeatureMatcher<HttpRequest, Iterable<? extends NameValuePair>>(
  404. parametersMatcher, "parameters with value", "parameters value") {
  405. @Override
  406. protected Iterable<? extends NameValuePair> featureValueOf(final HttpRequest httpRequest) {
  407. try {
  408. return URLEncodedUtils.parse(((HttpEntityEnclosingRequest) httpRequest).getEntity());
  409. } catch (IOException e) {
  410. throw new RuntimeException(e);
  411. }
  412. }
  413. };
  414. }
  415. private static Matcher<NameValuePair> parameterWithNameAndValue(final String name, final String value) {
  416. final NameValuePair expectedParameter = new BasicNameValuePair(name, value);
  417. return Matchers.equalTo(expectedParameter);
  418. }
  419. private static Matcher<HttpRoute> proxyHostIs(final Matcher<HttpHost> routeMatcher) {
  420. return new FeatureMatcher<HttpRoute, HttpHost>(routeMatcher, "proxy host for route", "proxy host") {
  421. @Override
  422. protected HttpHost featureValueOf(final HttpRoute route) {
  423. return route.getProxyHost();
  424. }
  425. };
  426. }
  427. private static Matcher<HttpHost> hostWithNameAndPort(final String name, final int port) {
  428. final HttpHost expectedHost = new HttpHost(name, port);
  429. return Matchers.equalTo(expectedHost);
  430. }
  431. private static Matcher<String> basicAuthWithUsernameAndPassword(final String username, final String password) {
  432. final String basicAuthCreds = MessageFormat.format("{0}:{1}", username, password);
  433. final String encodedBasicAuthCreds = Base64.encodeBase64String(basicAuthCreds.getBytes());
  434. final String expectedBasicAuthHeader = MessageFormat.format("{0} {1}", AuthSchemes.BASIC, encodedBasicAuthCreds);
  435. return Matchers.equalTo(expectedBasicAuthHeader);
  436. }
  437. }