diff --git a/itests/hive-unit/pom.xml b/itests/hive-unit/pom.xml
index dbc9136..90b5115 100644
--- a/itests/hive-unit/pom.xml
+++ b/itests/hive-unit/pom.xml
@@ -65,6 +65,57 @@
${project.version}
+
+ com.github.tomakehurst
+ wiremock
+ 1.55
+
+
+ standalone
+
+
+ org.mortbay.jetty
+ jetty
+
+
+ com.google.guava
+ guava
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+ org.skyscreamer
+ jsonassert
+
+
+ xmlunit
+ xmlunit
+
+
+ com.jayway.jsonpath
+ json-path
+
+
+ net.sf.jopt-simple
+ jopt-simple
+
+
+
+
diff --git a/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/wiremock/MiniHS2WithWireMock.java b/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/wiremock/MiniHS2WithWireMock.java
new file mode 100644
index 0000000..c9c4736
--- /dev/null
+++ b/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/wiremock/MiniHS2WithWireMock.java
@@ -0,0 +1,66 @@
+/**
+ * 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 org.apache.hive.jdbc.miniHS2.wiremock;
+
+import java.util.HashMap;
+
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.hive.jdbc.miniHS2.MiniHS2;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import com.github.tomakehurst.wiremock.client.WireMock;
+import com.github.tomakehurst.wiremock.core.Options;
+import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
+
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
+
+public class MiniHS2WithWireMock {
+
+ MiniHS2 miniHS2;
+ WireMockServer proxyingService;
+ WireMock proxyingServiceAdmin;
+ WireMockTestClient testClient;
+
+ private void setupWireMockServer(WireMockConfiguration options) {
+ if (options.portNumber() == Options.DEFAULT_PORT) {
+ options.dynamicPort();
+ }
+ proxyingService = new WireMockServer(options);
+ proxyingService.start();
+ }
+
+ public void init() throws Exception {
+ HiveConf hiveConf = new HiveConf();
+ hiveConf.setVar(HiveConf.ConfVars.HIVE_SERVER2_TRANSPORT_MODE, "http");
+ miniHS2 = new MiniHS2(hiveConf);
+ miniHS2.start(new HashMap());
+ setupWireMockServer(wireMockConfig());
+ proxyingService.start();
+ proxyingServiceAdmin = new WireMock(proxyingService.port());
+ testClient = new WireMockTestClient(proxyingService.port());
+
+ WireMock.configureFor(miniHS2.getHttpPort());
+ }
+
+ public void destroy() throws Exception {
+ miniHS2.stop();
+ proxyingService.stop();
+ }
+
+}
diff --git a/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/wiremock/WireMockHttpHeader.java b/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/wiremock/WireMockHttpHeader.java
new file mode 100644
index 0000000..6e3117b
--- /dev/null
+++ b/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/wiremock/WireMockHttpHeader.java
@@ -0,0 +1,26 @@
+package org.apache.hive.jdbc.miniHS2.wiremock;
+
+public class WireMockHttpHeader {
+
+ private String name;
+ private String value;
+
+ public static WireMockHttpHeader withHeader(String name, String value) {
+ return new WireMockHttpHeader(name, value);
+ }
+
+ public WireMockHttpHeader(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+
+}
diff --git a/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/wiremock/WireMockResponse.java b/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/wiremock/WireMockResponse.java
new file mode 100644
index 0000000..7a65261
--- /dev/null
+++ b/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/wiremock/WireMockResponse.java
@@ -0,0 +1,53 @@
+package org.apache.hive.jdbc.miniHS2.wiremock;
+
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.Multimap;
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+
+import java.nio.charset.Charset;
+
+import static com.github.tomakehurst.wiremock.common.HttpClientUtils.getEntityAsByteArrayAndCloseStream;
+import static com.google.common.base.Charsets.UTF_8;
+import static com.google.common.collect.Iterables.getFirst;
+
+public class WireMockResponse {
+
+ private final HttpResponse httpResponse;
+ private final byte[] content;
+
+ public WireMockResponse(HttpResponse httpResponse) {
+ this.httpResponse = httpResponse;
+ content = getEntityAsByteArrayAndCloseStream((wiremock.org.apache.http.HttpResponse)(httpResponse));
+ }
+
+ public int statusCode() {
+ return httpResponse.getStatusLine().getStatusCode();
+ }
+
+ public String content() {
+ if(content==null) {
+ return null;
+ }
+ return new String(content, Charset.forName(UTF_8.name()));
+ }
+
+ public byte[] binaryContent() {
+ return content;
+ }
+
+ public String firstHeader(String key) {
+ return getFirst(headers().get(key), null);
+ }
+
+ public Multimap headers() {
+ ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder();
+
+ for (Header header: httpResponse.getAllHeaders()) {
+ builder.put(header.getName(), header.getValue());
+ }
+
+ return builder.build();
+ }
+
+}
diff --git a/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/wiremock/WireMockTestClient.java b/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/wiremock/WireMockTestClient.java
new file mode 100644
index 0000000..dcd6bae
--- /dev/null
+++ b/itests/hive-unit/src/main/java/org/apache/hive/jdbc/miniHS2/wiremock/WireMockTestClient.java
@@ -0,0 +1,222 @@
+package org.apache.hive.jdbc.miniHS2.wiremock;
+
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.*;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.InputStreamEntity;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClientBuilder;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.net.URI;
+
+import static com.github.tomakehurst.wiremock.http.MimeType.JSON;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static java.net.HttpURLConnection.HTTP_CREATED;
+import static java.net.HttpURLConnection.HTTP_OK;
+
+public class WireMockTestClient {
+ public class GenericHttpUriRequest extends HttpRequestBase {
+
+ private final String methodName;
+
+ public GenericHttpUriRequest(String methodName, String url) {
+ this.methodName = methodName;
+ setURI(URI.create(url));
+ }
+
+ @Override
+ public String getMethod() {
+ return methodName;
+ }
+ }
+ private static final String LOCAL_WIREMOCK_ROOT = "http://%s:%d%s";
+ private static final String LOCAL_WIREMOCK_NEW_RESPONSE_URL = "http://%s:%d/__admin/mappings/new";
+ private static final String LOCAL_WIREMOCK_RESET_URL = "http://%s:%d/__admin/reset";
+ private static final String LOCAL_WIREMOCK_RESET_DEFAULT_MAPPINS_URL = "http://%s:%d/__admin/mappings/reset";
+
+ private int port;
+ private String address;
+
+ public WireMockTestClient(int port, String address) {
+ this.port = port;
+ this.address = address;
+ }
+
+ public WireMockTestClient(int port) {
+ this(port, "localhost");
+ }
+
+ public WireMockTestClient() {
+ this(8080);
+ }
+
+ private String mockServiceUrlFor(String path) {
+ return String.format(LOCAL_WIREMOCK_ROOT, address, port, path);
+ }
+
+ private String newMappingUrl() {
+ return String.format(LOCAL_WIREMOCK_NEW_RESPONSE_URL, address, port);
+ }
+
+ private String resetUrl() {
+ return String.format(LOCAL_WIREMOCK_RESET_URL, address, port);
+ }
+
+ private String resetDefaultMappingsUrl() {
+ return String.format(LOCAL_WIREMOCK_RESET_DEFAULT_MAPPINS_URL, address, port);
+ }
+
+ public WireMockResponse get(String url, WireMockHttpHeader... headers) {
+ String actualUrl = URI.create(url).isAbsolute() ? url : mockServiceUrlFor(url);
+ HttpUriRequest httpRequest = new HttpGet(actualUrl);
+ return executeMethodAndCovertExceptions(httpRequest, headers);
+ }
+
+ public WireMockResponse getViaProxy(String url) {
+ return getViaProxy(url, port);
+ }
+
+ public WireMockResponse getViaProxy(String url, int proxyPort) {
+ URI targetUri = URI.create(url);
+ HttpHost proxy = new HttpHost(address, proxyPort, targetUri.getScheme());
+ HttpClient httpClientUsingProxy = HttpClientBuilder.create()
+ .disableAuthCaching()
+ .disableAutomaticRetries()
+ .disableCookieManagement()
+ .disableRedirectHandling()
+ .setProxy(proxy)
+ .build();
+
+ try {
+ HttpHost target = new HttpHost(targetUri.getHost(), targetUri.getPort(), targetUri.getScheme());
+ HttpGet req = new HttpGet(targetUri.getPath() +
+ (isNullOrEmpty(targetUri.getQuery()) ? "" : "?" + targetUri.getQuery()));
+ req.removeHeaders("Host");
+
+ System.out.println("executing request to " + targetUri + "(" + target + ") via " + proxy);
+ HttpResponse httpResponse = httpClientUsingProxy.execute(target, req);
+ return new WireMockResponse(httpResponse);
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ }
+
+ public WireMockResponse put(String url, WireMockHttpHeader... headers) {
+ HttpUriRequest httpRequest = new HttpPut(mockServiceUrlFor(url));
+ return executeMethodAndCovertExceptions(httpRequest, headers);
+ }
+
+ public WireMockResponse putWithBody(String url, String body, String contentType, WireMockHttpHeader... headers) {
+ HttpPut httpPut = new HttpPut(mockServiceUrlFor(url));
+ return requestWithBody(httpPut, body, contentType, headers);
+ }
+
+ public WireMockResponse patchWithBody(String url, String body, String contentType, WireMockHttpHeader... headers) {
+ HttpPatch httpPatch = new HttpPatch(mockServiceUrlFor(url));
+ return requestWithBody(httpPatch, body, contentType, headers);
+ }
+
+ private WireMockResponse requestWithBody(
+ HttpEntityEnclosingRequestBase request, String body, String contentType, WireMockHttpHeader... headers) {
+ request.setEntity(new StringEntity(body, ContentType.create(contentType, "utf-8")));
+ return executeMethodAndCovertExceptions(request, headers);
+ }
+
+ public WireMockResponse postWithBody(String url, String body, String bodyMimeType, String bodyEncoding) {
+ return post(url, new StringEntity(body, ContentType.create(bodyMimeType, bodyEncoding)));
+ }
+
+ public WireMockResponse postWithChunkedBody(String url, byte[] body) {
+ return post(url, new InputStreamEntity(new ByteArrayInputStream(body), -1));
+ }
+
+ public WireMockResponse post(String url, HttpEntity entity) {
+ HttpPost httpPost = new HttpPost(mockServiceUrlFor(url));
+ httpPost.setEntity(entity);
+ return executeMethodAndCovertExceptions(httpPost);
+ }
+
+ public WireMockResponse patchWithBody(String url, String body, String bodyMimeType, String bodyEncoding) {
+ return patch(url, new StringEntity(body, ContentType.create(bodyMimeType, bodyEncoding)));
+ }
+
+ public WireMockResponse patch(String url, HttpEntity entity) {
+ HttpPatch httpPatch = new HttpPatch(mockServiceUrlFor(url));
+ httpPatch.setEntity(entity);
+ return executeMethodAndCovertExceptions(httpPatch);
+ }
+
+ public void addResponse(String responseSpecJson) {
+ int status = postJsonAndReturnStatus(newMappingUrl(), responseSpecJson);
+ if (status != HTTP_CREATED) {
+ throw new RuntimeException("Returned status code was " + status);
+ }
+ }
+
+ public void resetMappings() {
+ int status = postEmptyBodyAndReturnStatus(resetUrl());
+ if (status != HTTP_OK) {
+ throw new RuntimeException("Returned status code was " + status);
+ }
+ }
+
+ public void resetDefaultMappings() {
+ int status = postEmptyBodyAndReturnStatus(resetDefaultMappingsUrl());
+ if (status != HTTP_OK) {
+ throw new RuntimeException("Returned status code was " + status);
+ }
+ }
+
+ private int postJsonAndReturnStatus(String url, String json) {
+ HttpPost post = new HttpPost(url);
+ try {
+ if (json != null) {
+ post.setEntity(new StringEntity(json, ContentType.create(JSON.toString(), "utf-8")));
+ }
+ HttpResponse httpResponse = httpClient().execute(post);
+ return httpResponse.getStatusLine().getStatusCode();
+ } catch (RuntimeException re) {
+ throw re;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private int postEmptyBodyAndReturnStatus(String url) {
+ return postJsonAndReturnStatus(url, null);
+ }
+
+ private WireMockResponse executeMethodAndCovertExceptions(HttpUriRequest httpRequest, WireMockHttpHeader... headers) {
+ try {
+ for (WireMockHttpHeader header : headers) {
+ httpRequest.addHeader(header.getName(), header.getValue());
+ }
+ HttpResponse httpResponse = httpClient().execute(httpRequest);
+ return new WireMockResponse(httpResponse);
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ }
+
+ private static HttpClient httpClient() {
+ return HttpClientBuilder.create()
+ .disableAuthCaching()
+ .disableAutomaticRetries()
+ .disableCookieManagement()
+ .disableRedirectHandling()
+ .disableContentCompression()
+ .build();
+ }
+
+ public WireMockResponse request(final String methodName, String url, WireMockHttpHeader... headers) {
+ HttpUriRequest httpRequest = new GenericHttpUriRequest(methodName, mockServiceUrlFor(url));
+ return executeMethodAndCovertExceptions(httpRequest, headers);
+ }
+
+}
diff --git a/itests/hive-unit/src/test/java/org/apache/hive/jdbc/miniHS2/wiremock/TestMiniHS2WithWireMock.java b/itests/hive-unit/src/test/java/org/apache/hive/jdbc/miniHS2/wiremock/TestMiniHS2WithWireMock.java
new file mode 100644
index 0000000..b6095ab
--- /dev/null
+++ b/itests/hive-unit/src/test/java/org/apache/hive/jdbc/miniHS2/wiremock/TestMiniHS2WithWireMock.java
@@ -0,0 +1,34 @@
+package org.apache.hive.jdbc.miniHS2.wiremock;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.*;
+
+public class TestMiniHS2WithWireMock {
+ MiniHS2WithWireMock miniHS2WithWireMock;
+
+ @Before
+ public void beforeTests() throws Exception {
+ miniHS2WithWireMock.init();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ miniHS2WithWireMock.destroy();
+ }
+
+ @Test
+ public void successfullyGetsResponseFromHS2ViaProxy() {
+ miniHS2WithWireMock.proxyingServiceAdmin.register(any(urlMatching(".*")).atPriority(10).
+ willReturn(aResponse()
+ .proxiedFrom(miniHS2WithWireMock.miniHS2.getJdbcURL("default"))));
+
+ WireMockResponse response = miniHS2WithWireMock.testClient.get("/");
+ assertTrue(response.statusCode() == 200);
+ }
+
+}
diff --git a/itests/pom.xml b/itests/pom.xml
index bf909eb..28c3742 100644
--- a/itests/pom.xml
+++ b/itests/pom.xml
@@ -41,6 +41,59 @@
hive-jmh
+
+
+ com.github.tomakehurst
+ wiremock
+ 1.55
+
+
+ standalone
+
+
+ org.mortbay.jetty
+ jetty
+
+
+ com.google.guava
+ guava
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+ org.skyscreamer
+ jsonassert
+
+
+ xmlunit
+ xmlunit
+
+
+ com.jayway.jsonpath
+ json-path
+
+
+ net.sf.jopt-simple
+ jopt-simple
+
+
+
+
+
hadoop-2