You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2016/10/08 11:40:09 UTC
svn commit: r1763892 [1/2] - in
/httpcomponents/httpcore/trunk/httpcore5-testing/src:
main/java/org/apache/hc/core5/testing/classic/
main/java/org/apache/hc/core5/testing/framework/
test/java/org/apache/hc/core5/testing/framework/
Author: olegk
Date: Sat Oct 8 11:40:09 2016
New Revision: 1763892
URL: http://svn.apache.org/viewvc?rev=1763892&view=rev
Log:
[HTTPCLIENT-1759] Contribute new tests that use the in-process http server.
Contributed by John W. Lewis <johnw.lewis at sas.com>
Added:
httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/
httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientAdapter.java (with props)
httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientTestingAdapter.java (with props)
httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientPOJOAdapter.java (with props)
httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientTestingAdapter.java (with props)
httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/FrameworkTest.java (with props)
httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFramework.java (with props)
httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkException.java (with props)
httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkRequestHandler.java (with props)
httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/framework/
httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/framework/TestClassicTestClientTestingAdapter.java (with props)
httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/framework/TestClientPOJOAdapter.java (with props)
httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/framework/TestClientTestingAdapter.java (with props)
httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/framework/TestFrameworkTest.java (with props)
httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/framework/TestTestingFramework.java (with props)
httpcomponents/httpcore/trunk/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/framework/TestTestingFrameworkRequestHandler.java (with props)
Modified:
httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/ClassicTestServer.java
Modified: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/ClassicTestServer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/ClassicTestServer.java?rev=1763892&r1=1763891&r2=1763892&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/ClassicTestServer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/classic/ClassicTestServer.java Sat Oct 8 11:40:09 2016
@@ -110,10 +110,14 @@ public class ClassicTestServer {
}
public void shutdown() {
+ shutdown(5, TimeUnit.SECONDS);
+ }
+
+ public void shutdown(final long gracePeriod, final TimeUnit timeUnit) {
final org.apache.hc.core5.http.bootstrap.io.HttpServer local = this.server;
this.server = null;
if (local != null) {
- local.shutdown(5, TimeUnit.SECONDS);
+ local.shutdown(gracePeriod, timeUnit);
}
}
Added: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientAdapter.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientAdapter.java?rev=1763892&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientAdapter.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientAdapter.java Sat Oct 8 11:40:09 2016
@@ -0,0 +1,181 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.testing.framework;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.entity.ContentType;
+import org.apache.hc.core5.http.entity.EntityUtils;
+import org.apache.hc.core5.http.entity.StringEntity;
+import org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection;
+import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
+import org.apache.hc.core5.testing.classic.ClassicTestClient;
+
+/**
+ * Implementation of {@link ClientPOJOAdapter} for ClassicTestClient.
+ *
+ * @since 5.0
+ */
+public class ClassicTestClientAdapter extends ClientPOJOAdapter {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<String, Object> execute(final String defaultURI, final Map<String, Object> request) throws Exception {
+ // check the request for missing items.
+ if (defaultURI == null) {
+ throw new HttpException("defaultURL cannot be null");
+ }
+ if (request == null) {
+ throw new HttpException("request cannot be null");
+ }
+ if (! request.containsKey(PATH)) {
+ throw new HttpException("Request path should be set.");
+ }
+ if (! request.containsKey(METHOD)) {
+ throw new HttpException("Request method should be set.");
+ }
+
+ final ClassicTestClient client = new ClassicTestClient();
+
+ // Append the path to the defaultURI.
+ String tempDefaultURI = defaultURI;
+ if (! defaultURI.endsWith("/")) {
+ tempDefaultURI += "/";
+ }
+ final URI startingURI = new URI(tempDefaultURI + request.get(PATH));
+ final URI uri;
+
+ // append each parameter in the query to the uri.
+ @SuppressWarnings("unchecked")
+ final Map<String, String> queryMap = (Map<String, String>) request.get(QUERY);
+ if (queryMap != null) {
+ final String existingQuery = startingURI.getRawQuery();
+ final StringBuilder newQuery = new StringBuilder(existingQuery == null ? "" : existingQuery);
+
+ // append each parm to the query
+ for (Entry<String, String> parm : queryMap.entrySet()) {
+ newQuery.append("&" + parm.getKey() + "=" + parm.getValue());
+ }
+ // create a uri with the new query.
+ uri = new URI(
+ startingURI.getRawSchemeSpecificPart(),
+ startingURI.getRawUserInfo(),
+ startingURI.getHost(),
+ startingURI.getPort(),
+ startingURI.getRawPath(),
+ newQuery.toString(),
+ startingURI.getRawFragment());
+ } else {
+ uri = startingURI;
+ }
+
+ final BasicClassicHttpRequest httpRequest = new BasicClassicHttpRequest(request.get(METHOD).toString(), uri);
+
+ if (request.containsKey(PROTOCOL_VERSION)) {
+ httpRequest.setVersion((ProtocolVersion) request.get(PROTOCOL_VERSION));
+ }
+
+ // call addHeader for each header in headers.
+ @SuppressWarnings("unchecked")
+ final Map<String, String> headersMap = (Map<String, String>) request.get(HEADERS);
+ if (headersMap != null) {
+ for (Entry<String, String> header : headersMap.entrySet()) {
+ httpRequest.addHeader(header.getKey(), header.getValue());
+ }
+ }
+
+ // call setEntity if a body is specified.
+ final String requestBody = (String) request.get(BODY);
+ if (requestBody != null) {
+ final String requestContentType = (String) request.get(CONTENT_TYPE);
+ final StringEntity entity = requestContentType != null ?
+ new StringEntity(requestBody, ContentType.parse(requestContentType)) :
+ new StringEntity(requestBody);
+ httpRequest.setEntity(entity);
+ }
+
+ // timeout
+ if (request.containsKey(TIMEOUT)) {
+ final long timeout = (long) request.get(TIMEOUT);
+ client.setTimeout((int) timeout);
+ }
+
+ // Now execute the request.
+ final DefaultBHttpClientConnection conn = client.createConnection();
+ final HttpHost host = new HttpHost(uri.getHost(), uri.getPort());
+
+ if (!conn.isOpen()) {
+ client.connect(host, conn);
+ }
+
+ final ClassicHttpResponse response = client.execute(httpRequest, host, conn);
+
+ // Prepare the response. It will contain status, body, headers, and contentType.
+ final HttpEntity entity = response.getEntity();
+ final String body = entity == null ? null : EntityUtils.toString(entity);
+ final String contentType = entity == null ? null : entity.getContentType();
+
+ if (!client.keepAlive(httpRequest, response)) {
+ conn.close();
+ }
+
+ // prepare the returned information
+ final Map<String, Object> ret = new HashMap<String, Object>();
+ ret.put(STATUS, response.getCode());
+
+ // convert the headers to a Map
+ final Map<String, Object> headerMap = new HashMap<String, Object>();
+ for (Header header : response.getAllHeaders()) {
+ headerMap.put(header.getName(), header.getValue());
+ }
+ ret.put(HEADERS, headerMap);
+ ret.put(BODY, body);
+ ret.put(CONTENT_TYPE, contentType);
+
+ return ret ;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getClientName() {
+ return "ClassicTestClient";
+ }
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientAdapter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientAdapter.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientAdapter.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientTestingAdapter.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientTestingAdapter.java?rev=1763892&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientTestingAdapter.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientTestingAdapter.java Sat Oct 8 11:40:09 2016
@@ -0,0 +1,40 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.testing.framework;
+
+/**
+ * Implementation of {@link ClientTestingAdapter} for the ClassicTestClient.
+ *
+ * @since 5.0
+ */
+public class ClassicTestClientTestingAdapter extends ClientTestingAdapter {
+
+ public ClassicTestClientTestingAdapter() {
+ super(new ClassicTestClientAdapter());
+ }
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientTestingAdapter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientTestingAdapter.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClassicTestClientTestingAdapter.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientPOJOAdapter.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientPOJOAdapter.java?rev=1763892&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientPOJOAdapter.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientPOJOAdapter.java Sat Oct 8 11:40:09 2016
@@ -0,0 +1,155 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.hc.core5.testing.framework;
+
+import java.util.Map;
+
+/**
+ *
+ * <p>This adapter expects a request to be made up of POJOs such as Maps and Lists. In Groovy
+ * the request could be expressed like this:</p>
+ *
+ * <pre>
+ *
+ * def request = [
+ * path : "a/path",
+ * method : "GET",
+ * query : [
+ * parm1 : "1",
+ * parm2 : "2",
+ * ]
+ * headers : [
+ * header1 : "stuff",
+ * header2 : "more_stuff",
+ * ]
+ * contentType : "application/json",
+ * body : '{"location" : "home" }',
+ * ]
+ * </pre>
+ *
+ * <p>The adapter will translate this request into calls specific to a particular HTTP client.</p>
+ *
+ * <p>The response is then returned with POJOs with this structure:</p>
+ *
+ * <pre>
+ *
+ * def response = [
+ * status : 200,
+ * headers : [
+ * header1 : "response_stuff",
+ * ]
+ * contentType : "application/json",
+ * body : '{"location" : "work" }',
+ * ]
+ * </pre>
+ * @since 5.0
+ */
+public abstract class ClientPOJOAdapter {
+ public static final String BODY = "body";
+ public static final String CONTENT_TYPE = "contentType";
+ public static final String HEADERS = "headers";
+ public static final String METHOD = "method";
+ public static final String NAME = "name";
+ public static final String PATH = "path";
+ public static final String PROTOCOL_VERSION = "protocolVersion";
+ public static final String QUERY = "query";
+ public static final String REQUEST = "request";
+ public static final String RESPONSE = "response";
+ public static final String STATUS = "status";
+ public static final String TIMEOUT = "timeout";
+
+ /**
+ * Name of the HTTP Client that this adapter uses.
+ *
+ * @return name of the HTTP Client.
+ */
+ public abstract String getClientName();
+
+ /**
+ * Execute an HTTP request.
+ *
+ * @param defaultURI the URI used by default. The path in the request is
+ * usually appended to it.
+ * @param request the request as specified above.
+ *
+ * @return the response to the request as specified above.
+ *
+ * @throws Exception in case of a problem
+ */
+ public abstract Map<String, Object> execute(String defaultURI, Map<String, Object> request) throws Exception;
+
+ /**
+ * <p>Check if a request is supported.</p>
+ *
+ * <p>Usually called directly by a testing framework. If an HTTP client does not support
+ * a particular request, a non-null reason should be returned. Otherwise, if
+ * the request is supported, return null.</p>
+ *
+ * <p>If this method is overridden, then the execute method should probably call
+ * assertRequestSupported() at the beginning.</p>
+ *
+ * @param request the request as specified above.
+ *
+ * @return null if the request is supported; Otherwise, return a reason.
+ */
+ public String checkRequestSupport(final Map<String, Object> request) {
+ return null;
+ }
+
+ /**
+ * <p>Assert that the request is supported</p>
+ *
+ * <p>Usually called by the execute method. Throws an exception if the request
+ * is not supported.</p>
+ *
+ * @param request the request as specified above.
+ * @throws Exception if the request is not supported.
+ */
+ public void assertRequestSupported(final Map<String, Object> request) throws Exception {
+ final String reason = checkRequestSupport(request);
+ if (reason != null) {
+ throw new Exception(reason);
+ }
+ }
+
+ /**
+ * <p>Modify the request.</p>
+ *
+ * <p>In a testing context, a testing framework can call this method to allow
+ * the adapter to change the request. The request is then given to a
+ * special request handler of the in-process HttpServer which will later check
+ * an actual HTTP request against what is expected.</p>
+ *
+ * <p>In a production context, this is called by the execute method (if at all).</p>
+ *
+ * @param request the request as specified above.
+ * @return the same request or a modification of it.
+ */
+ public Map<String, Object> modifyRequest(final Map<String, Object> request) {
+ return request;
+ };
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientPOJOAdapter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientPOJOAdapter.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientPOJOAdapter.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientTestingAdapter.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientTestingAdapter.java?rev=1763892&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientTestingAdapter.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientTestingAdapter.java Sat Oct 8 11:40:09 2016
@@ -0,0 +1,186 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.testing.framework;
+
+import java.util.Map;
+
+/**
+*
+* <p>This adapter assists the testing of an HTTP client. This adapter in turn uses an
+* {@link ClientPOJOAdapter} to actually use the HTTP client to make the request.
+* See {@link ClientPOJOAdapter} to see the format of the request and the returned
+* response. The format of the returned response is also the format of the parameter
+* called responseExpectations.</p>
+*
+* <p>This adapter will generally call the {@link ClientPOJOAdapter} methods of the same
+* name when these methods are called:</p>
+*
+* <pre>
+*
+* isRequestSupported
+* modifyRequest
+* execute
+*
+* </pre>
+*
+* <p>See these method's documentation in {@link ClientPOJOAdapter} for details.</p>
+*
+* <p>The value that this adapter adds is with the modifyResponseExpectations method. Each
+* test will specify the response that is expected. The HttpClient5 adapter is able
+* to use these unmodified expectations, but if a different HTTP client (such as Groovy's
+* RESTClient which uses HttpClient) for some reason needs to modify the expectations,
+* it would be done in the modifyResponseExpectations method.</p>
+*
+* @since 5.0
+*/
+public class ClientTestingAdapter {
+ /**
+ * This adapter will perform the HTTP request and return the response in the
+ * expected format.
+ */
+ protected ClientPOJOAdapter adapter;
+
+ /*
+ * The following is not expected to be changed to true, but it is to highlight
+ * where the execute method can call the requestHandler's assertNothingThrown()
+ * method if desired. Since this adapter's execute method does not check
+ * the response, there is no need to call it.
+ */
+ protected boolean callAssertNothingThrown;
+
+ public ClientTestingAdapter() {
+ }
+
+ public ClientTestingAdapter(final ClientPOJOAdapter adapter) {
+ this.adapter = adapter;
+ }
+
+ /**
+ * See the documentation for the same method in {@link ClientPOJOAdapter}. This
+ * method will typically call it. However, this method also has access to the
+ * test's response expectations if that is needed for some reason. Furthermore,
+ * this method also has access to the {@link TestingFrameworkRequestHandler} so
+ * it can optionally call assertNothingThrown() before checking the response
+ * further. It is optional because the test framework will call it later.
+ *
+ * @param defaultURI See execute method of {@link ClientPOJOAdapter}.
+ * @param request See execute method of {@link ClientPOJOAdapter}.
+ * @param requestHandler The request handler that checks the received HTTP request
+ * with the request that was intended. If there is a
+ * mismatch of expectations, then the requestHandler will
+ * throw an exception. If this execute method does not want
+ * to make further checks of the response in the case
+ * the responseHandler threw, then the assertNothingThrown()
+ * method should be called before doing further checks.
+ * @param responseExpectations The response expectations of the test.
+ * @return See return of the execute method of {@link ClientPOJOAdapter}.
+ * @throws TestingFrameworkException in the case of a problem.
+ */
+ public Map<String, Object> execute(final String defaultURI, final Map<String, Object> request,
+ final TestingFrameworkRequestHandler requestHandler,
+ final Map<String, Object> responseExpectations) throws TestingFrameworkException {
+
+ try {
+ if (adapter == null) {
+ throw new TestingFrameworkException("adapter cannot be null");
+ }
+ // Call the adapter's execute method to actually make the HTTP request.
+ final Map<String, Object> response = adapter.execute(defaultURI, request);
+
+ /*
+ * Adapters may call assertNothingThrown() if they would like. This would be to
+ * make sure the following code is not executed in the event there was something
+ * thrown in the request handler.
+ *
+ * Otherwise, the framework will call it when this method returns. So, it is
+ * optional.
+ */
+ if (callAssertNothingThrown) {
+ if (requestHandler == null) {
+ throw new TestingFrameworkException("requestHandler cannot be null");
+ }
+ requestHandler.assertNothingThrown();
+ }
+
+ return response;
+ } catch (TestingFrameworkException e) {
+ throw e;
+ } catch (Exception ex) {
+ throw new TestingFrameworkException(ex);
+ }
+ }
+
+ /**
+ * See the documentation for the same method in {@link ClientPOJOAdapter}.
+ *
+ * @param request
+ * @return
+ */
+ public boolean isRequestSupported(final Map<String, Object> request) {
+ return (adapter == null) ? true : adapter.checkRequestSupport(request) == null;
+ };
+
+ /**
+ * See the documentation for the same method in {@link ClientPOJOAdapter}.
+ *
+ * @param request
+ * @return
+ */
+ public Map<String, Object> modifyRequest(final Map<String, Object> request) {
+ return (adapter == null) ? request : adapter.modifyRequest(request);
+ };
+
+ /**
+ * Generally a test's response expectations should not need to be modified, but
+ * if a particular HTTP client (such as Groovy's RESTClient which uses HttpClient)
+ * needs to modify the response expectations, it should do so here. After this
+ * method returns, the {@link TestingFrameworkRequestHandler} is sent the
+ * expectations so the request handler will return a response that matches the
+ * expectations. When the HTTP response is obtained, the received response
+ * is matched against the expectations.
+ *
+ * @param request for the format, see the documentation for {@link ClientPOJOAdapter}.
+ * @param responseExpectations for the format, see the documentation for {@link ClientPOJOAdapter}.
+ * @return the same or modified response expectations.
+ */
+ public Map<String, Object> modifyResponseExpectations(final Map<String, Object> request,
+ final Map<String, Object> responseExpectations) {
+ return responseExpectations;
+ }
+
+ /**
+ * Getter for the {@link ClientPOJOAdapter} that is actually used to make the
+ * HTTP request.
+ *
+ * @return the {@link ClientPOJOAdapter}.
+ */
+ public ClientPOJOAdapter getClientPOJOAdapter() {
+ return adapter;
+ }
+
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientTestingAdapter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientTestingAdapter.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/ClientTestingAdapter.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/FrameworkTest.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/FrameworkTest.java?rev=1763892&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/FrameworkTest.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/FrameworkTest.java Sat Oct 8 11:40:09 2016
@@ -0,0 +1,172 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.testing.framework;
+
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.BODY;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.CONTENT_TYPE;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.HEADERS;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.METHOD;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.PATH;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.PROTOCOL_VERSION;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.QUERY;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.REQUEST;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.RESPONSE;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.STATUS;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.hc.core5.http.NameValuePair;
+import org.apache.hc.core5.util.URLEncodedUtils;
+
+
+
+/**
+ * <p>This class is not expected to be used directly by the user, but its job is to
+ * supply helpful defaults for tests.</p>
+ *
+ * <p>A test is made up of an HTTP request that the HTTP client will send as well
+ * as a response that is expected.</p>
+ *
+ * <p>See {@link ClientPOJOAdapter} for details on the request and response.</p>
+ *
+ * <p>Generally, if the request does not specify a method, it is assumed to be a GET.
+ * There are also defaults for headers, query parameters, body, contentType, etc.</p>
+ *
+ * @since 5.0
+ */
+public class FrameworkTest {
+ private Map<String, Object> request = new HashMap<String, Object>();
+ private Map<String, Object> response = new HashMap<String, Object>();
+
+ /**
+ * Constructs a test with default values.
+ */
+ public FrameworkTest() {
+ this(null);
+ }
+
+ /**
+ * Constructs a test with values that are passed in as well as defaults
+ * for values that are not passed in.
+ *
+ * @param test Contains a REQUEST and an expected RESPONSE.
+ * See {@link ClientPOJOAdapter} for details.
+ */
+ @SuppressWarnings("unchecked")
+ public FrameworkTest(final Map<String, Object> test) {
+ if (test != null) {
+ if (test.containsKey(REQUEST)) {
+ request = (Map<String, Object>) test.get(REQUEST);
+ }
+ if (test.containsKey(RESPONSE)) {
+ response = (Map<String, Object>) test.get(RESPONSE);
+ }
+ }
+ }
+
+ /**
+ * Returns a request with defaults for any parameter that is not specified.
+ *
+ * @return a REQUEST map.
+ * @throws TestingFrameworkException a problem such as an invalid URL
+ */
+ public Map<String, Object> initRequest() throws TestingFrameworkException {
+ // initialize to some helpful defaults
+ final Map<String, Object> ret = new HashMap<String, Object>();
+ ret.put(PATH, TestingFramework.DEFAULT_REQUEST_PATH);
+ ret.put(BODY, TestingFramework.DEFAULT_REQUEST_BODY);
+ ret.put(CONTENT_TYPE, TestingFramework.DEFAULT_REQUEST_CONTENT_TYPE);
+ ret.put(QUERY, new HashMap<String, String>(TestingFramework.DEFAULT_REQUEST_QUERY));
+ ret.put(HEADERS, new HashMap<String, String>(TestingFramework.DEFAULT_REQUEST_HEADERS));
+ ret.put(PROTOCOL_VERSION, TestingFramework.DEFAULT_REQUEST_PROTOCOL_VERSION);
+
+ // GET is the default method.
+ if (! request.containsKey(METHOD)) {
+ request.put(METHOD, "GET");
+ }
+ ret.putAll(request);
+
+ moveAnyParametersInPathToQuery(ret);
+
+ return ret;
+ }
+
+ private void moveAnyParametersInPathToQuery(final Map<String, Object> request) throws TestingFrameworkException {
+ try {
+ final String path = (String) request.get(PATH);
+ if (path != null) {
+ final URI uri = path.startsWith("/") ? new URI("http://localhost:8080" + path) :
+ new URI("http://localhost:8080/");
+ final List<NameValuePair> params = URLEncodedUtils.parse(uri, StandardCharsets.UTF_8);
+ @SuppressWarnings("unchecked")
+ final Map<String, Object> queryMap = (Map<String, Object>) request.get(QUERY);
+ for (NameValuePair param : params) {
+ queryMap.put(param.getName(), param.getValue());
+ }
+ if (! params.isEmpty()) {
+ request.put(PATH, uri.getPath());
+ }
+ }
+ } catch (URISyntaxException e) {
+ throw new TestingFrameworkException(e);
+ }
+ }
+
+ /**
+ * Returns an expected response with defaults for any parameter that is not specified.
+ *
+ * @return the RESPONSE map.
+ */
+ public Map<String, Object> initResponseExpectations() {
+ // 200 is the default status.
+ if (! response.containsKey(STATUS)) {
+ response.put(STATUS, 200);
+ }
+
+ final Map<String, Object> responseExpectations = new HashMap<String, Object>();
+ // initialize to some helpful defaults
+ responseExpectations.put(BODY, TestingFramework.DEFAULT_RESPONSE_BODY);
+ responseExpectations.put(CONTENT_TYPE, TestingFramework.DEFAULT_RESPONSE_CONTENT_TYPE);
+ responseExpectations.put(HEADERS, new HashMap<String, String>(TestingFramework.DEFAULT_RESPONSE_HEADERS));
+
+ // Now override any defaults with what is requested.
+ responseExpectations.putAll(response);
+
+ return responseExpectations;
+ }
+
+ @Override
+ public String toString() {
+ return "request: " + request + "\nresponse: " + response;
+ }
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/FrameworkTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/FrameworkTest.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/FrameworkTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFramework.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFramework.java?rev=1763892&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFramework.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFramework.java Sat Oct 8 11:40:09 2016
@@ -0,0 +1,492 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.testing.framework;
+
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.BODY;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.CONTENT_TYPE;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.HEADERS;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.METHOD;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.REQUEST;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.RESPONSE;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.STATUS;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.hc.core5.http.HttpVersion;
+import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.bootstrap.io.HttpServer;
+import org.apache.hc.core5.http.bootstrap.io.ServerBootstrap;
+import org.apache.hc.core5.http.config.SocketConfig;
+
+/**
+ * <p>This testing framework starts an in-process {@link HttpServer} which will use an
+ * {@link TestingFrameworkRequestHandler} to check HTTP requests that are sent
+ * to it. Before the request is sent, the handler is told what request to expect.
+ * If the received request does not match the request expectations, an exception
+ * is thrown.</p>
+ *
+ * <p>The handler is also told what response to return. This testing framework will
+ * then check the response it receives with what it desired. If they do not
+ * match, an exception is thrown.</p>
+ *
+ * <p>This has been designed to work with any HTTP client. So, for instance, Groovy's
+ * HttpBuilder or RESTClient which uses Apache HttpClient can also be tested with this
+ * testing framework. A different {@link ClientTestingAdapter} is used with
+ * different HTTP clients. If testing Apache HttpClient5, the {@link ClassicTestClientTestingAdapter}
+ * is used. Since use of this testing framework with other projects is desired,
+ * the testframework package has been placed outside the test directory. Care has
+ * been taken to make sure no testing dependency such as JUnit or EasyMock is used
+ * in the framework.</p>
+ *
+ * <p>The {@link ClassicTestClientTestingAdapter} that is used is either passed into the
+ * constructor or set with setAdapter().</p>
+ *
+ * <p>By default, this framework will go through a series of tests that will exercise
+ * all HTTP methods. If the default tests are not desired, then the deleteTests()
+ * method can be called. Then, custom tests can be added with the addTest() methods.
+ * Of course additional tests can be added with the addTest() method without first
+ * calling deleteTests(). In that case, the default tests and the additional tests
+ * will all run.</p>
+ *
+ * <p>Since this framework has been designed to be used with any HTTP client, the test
+ * is specified with POJO's such as Map, List, and primitives. The test is a Map with
+ * two keys - request and response. See {@link ClientPOJOAdapter} for details
+ * on the format of the request and response.</p>
+ *
+ * <p>Once any additional tests have been added, the runTests() method is called to
+ * actually do the testing.</p>
+ *
+ * @since 5.0
+ *
+ */
+public class TestingFramework {
+ /**
+ * Use the ALL_METHODS list to conveniently cycle through all HTTP methods.
+ */
+ public static final List<String> ALL_METHODS = Arrays.asList("HEAD", "GET", "DELETE", "POST", "PUT", "PATCH");
+
+ /**
+ * If an {@link ClassicTestClientTestingAdapter} is unable to return a response in
+ * the format this testing framework is needing, then it will need to check the
+ * item in the response (such as body, status, headers, or contentType) itself and set
+ * the returned value of the item as ALREADY_CHECKED.
+ */
+ public static final Object ALREADY_CHECKED = new Object();
+
+ /**
+ * If a test does not specify a path, this one is used.
+ */
+ public static final String DEFAULT_REQUEST_PATH = "a/path";
+
+ /**
+ * If a test does not specify a body, this one is used.
+ */
+ public static final String DEFAULT_REQUEST_BODY = "{\"location\":\"home\"}";
+
+ /**
+ * If a test does not specify a request contentType, this one is used.
+ */
+ public static final String DEFAULT_REQUEST_CONTENT_TYPE = "application/json";
+
+ /**
+ * If a test does not specify query parameters, these are used.
+ */
+ public static final Map<String, String> DEFAULT_REQUEST_QUERY;
+
+ /**
+ * If a test does not specify a request headers, these are used.
+ */
+ public static final Map<String, String> DEFAULT_REQUEST_HEADERS;
+
+ /**
+ * If a test does not specify a protocol version, this one is used.
+ */
+ public static final ProtocolVersion DEFAULT_REQUEST_PROTOCOL_VERSION = HttpVersion.HTTP_1_1;
+
+ /**
+ * If a test does not specify an expected response status, this one is used.
+ */
+ public static final int DEFAULT_RESPONSE_STATUS = 200;
+
+ /**
+ * If a test does not specify an expected response body, this one is used.
+ */
+ public static final String DEFAULT_RESPONSE_BODY = "{\"location\":\"work\"}";
+
+ /**
+ * If a test does not specify an expected response contentType, this one is used.
+ */
+ public static final String DEFAULT_RESPONSE_CONTENT_TYPE = "application/json";
+
+ /**
+ * If a test does not specify expected response headers, these are used.
+ */
+ public static final Map<String, String> DEFAULT_RESPONSE_HEADERS;
+
+ static {
+ final Map<String, String> request = new HashMap<String, String>();
+ request.put("p1", "this");
+ request.put("p2", "that");
+ DEFAULT_REQUEST_QUERY = Collections.unmodifiableMap(request);
+
+ Map<String, String> headers = new HashMap<String, String>();
+ headers.put("header1", "stuff");
+ headers.put("header2", "more stuff");
+ DEFAULT_REQUEST_HEADERS = Collections.unmodifiableMap(headers);
+
+ headers = new HashMap<String, String>();
+ headers.put("header3", "header_three");
+ headers.put("header4", "header_four");
+ DEFAULT_RESPONSE_HEADERS = Collections.unmodifiableMap(headers);
+ }
+
+ private ClientTestingAdapter adapter;
+ private TestingFrameworkRequestHandler requestHandler = new TestingFrameworkRequestHandler();
+ private List<FrameworkTest> tests = new ArrayList<FrameworkTest>();
+
+ private HttpServer server;
+ private int port;
+
+ public TestingFramework() throws TestingFrameworkException {
+ this(null);
+ }
+
+ public TestingFramework(final ClientTestingAdapter adapter) throws TestingFrameworkException {
+ this.adapter = adapter;
+
+ /*
+ * By default, a set of tests that will exercise each HTTP method are pre-loaded.
+ */
+ for (String method : ALL_METHODS) {
+ final List<Integer> statusList = Arrays.asList(200, 201);
+ for (Integer status : statusList) {
+ final Map<String, Object> request = new HashMap<String, Object>();
+ request.put(METHOD, method);
+
+ final Map<String, Object> response = new HashMap<String, Object>();
+ response.put(STATUS, status);
+
+ final Map<String, Object> test = new HashMap<String, Object>();
+ test.put(REQUEST, request);
+ test.put(RESPONSE, response);
+
+ addTest(test);
+ }
+ }
+ }
+
+ /**
+ * This is not likely to be used except during the testing of this class.
+ * It is used to inject a mocked request handler.
+ *
+ * @param requestHandler
+ */
+ public void setRequestHandler(final TestingFrameworkRequestHandler requestHandler) {
+ this.requestHandler = requestHandler;
+ }
+
+ /**
+ * Run the tests that have been previously added. First, an in-process {@link HttpServer} is
+ * started. Then, all the tests are completed by passing each test to the adapter
+ * which will make the HTTP request.
+ *
+ * @throws TestingFrameworkException if there is a test failure or unexpected problem.
+ */
+ public void runTests() throws TestingFrameworkException {
+ if (adapter == null) {
+ throw new TestingFrameworkException("adapter should not be null");
+ }
+
+ startServer();
+
+ try {
+ for (FrameworkTest test : tests) {
+ try {
+ callAdapter(test);
+ } catch (Throwable t) {
+ processThrowable(t, test);
+ }
+ }
+ } finally {
+ stopServer();
+ }
+ }
+
+ private void processThrowable(final Throwable t, final FrameworkTest test) throws TestingFrameworkException {
+ final TestingFrameworkException e;
+ if (t instanceof TestingFrameworkException) {
+ e = (TestingFrameworkException) t;
+ } else {
+ e = new TestingFrameworkException(t);
+ }
+ e.setAdapter(adapter);
+ e.setTest(test);
+ throw e;
+ }
+
+ private void startServer() throws TestingFrameworkException {
+ /*
+ * Start an in-process server and handle all HTTP requests
+ * with the requestHandler.
+ */
+ final SocketConfig socketConfig = SocketConfig.custom()
+ .setSoTimeout(15000)
+ .build();
+
+ final ServerBootstrap serverBootstrap = ServerBootstrap.bootstrap()
+ .setSocketConfig(socketConfig)
+ .registerHandler("/*", requestHandler);
+
+ server = serverBootstrap.create();
+ try {
+ server.start();
+ } catch (IOException e) {
+ throw new TestingFrameworkException(e);
+ }
+
+ port = server.getLocalPort();
+ }
+
+ private void stopServer() {
+ if (server != null) {
+ server.shutdown(0, TimeUnit.SECONDS);
+ server = null;
+ }
+ }
+
+ private void callAdapter(final FrameworkTest test) throws TestingFrameworkException {
+ Map<String, Object> request = test.initRequest();
+
+ /*
+ * If the adapter does not support the particular request, skip the test.
+ */
+ if (! adapter.isRequestSupported(request)) {
+ return;
+ }
+
+ /*
+ * Allow the adapter to modify the request before the request expectations
+ * are given to the requestHandler. Typically, adapters should not have
+ * to modify the request.
+ */
+ request = adapter.modifyRequest(request);
+
+ // Tell the request handler what to expect in the request.
+ requestHandler.setRequestExpectations(request);
+
+ Map<String, Object> responseExpectations = test.initResponseExpectations();
+ /*
+ * Allow the adapter to modify the response expectations before the handler
+ * is told what to return. Typically, adapters should not have to modify
+ * the response expectations.
+ */
+ responseExpectations = adapter.modifyResponseExpectations(request, responseExpectations);
+
+ // Tell the request handler what response to return.
+ requestHandler.setDesiredResponse(responseExpectations);
+
+ /*
+ * Use the adapter to make the HTTP call. Make sure the responseExpectations are not changed
+ * since they have already been sent to the request handler and they will later be used
+ * to check the response.
+ */
+ final String defaultURI = getDefaultURI();
+ final Map<String, Object> response = adapter.execute(
+ defaultURI,
+ request,
+ requestHandler,
+ Collections.unmodifiableMap(responseExpectations));
+ /*
+ * The adapter is welcome to call assertNothingThrown() earlier, but we will
+ * do it here to make sure it is done. If the handler threw any exception
+ * while checking the request it received, it will be re-thrown here.
+ */
+ requestHandler.assertNothingThrown();
+
+ assertResponseMatchesExpectation(request.get(METHOD), response, responseExpectations);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void assertResponseMatchesExpectation(final Object method, final Map<String, Object> actualResponse,
+ final Map<String, Object> expectedResponse)
+ throws TestingFrameworkException {
+ if (actualResponse == null) {
+ throw new TestingFrameworkException("response should not be null");
+ }
+ /*
+ * Now check the items in the response unless the adapter says they
+ * already checked something.
+ */
+ if (actualResponse.get(STATUS) != TestingFramework.ALREADY_CHECKED) {
+ assertStatusMatchesExpectation(actualResponse.get(STATUS), expectedResponse.get(STATUS));
+ }
+ if (! method.equals("HEAD")) {
+ if (actualResponse.get(BODY) != TestingFramework.ALREADY_CHECKED) {
+ assertBodyMatchesExpectation(actualResponse.get(BODY), expectedResponse.get(BODY));
+ }
+ if (actualResponse.get(CONTENT_TYPE) != TestingFramework.ALREADY_CHECKED) {
+ assertContentTypeMatchesExpectation(actualResponse.get(CONTENT_TYPE), expectedResponse.get(CONTENT_TYPE));
+ }
+ }
+ if (actualResponse.get(HEADERS) != TestingFramework.ALREADY_CHECKED) {
+ assertHeadersMatchExpectation((Map<String, String>) actualResponse.get(HEADERS),
+ (Map<String, String>) expectedResponse.get(HEADERS));
+ }
+ }
+
+ private void assertStatusMatchesExpectation(final Object actualStatus, final Object expectedStatus)
+ throws TestingFrameworkException {
+ if (actualStatus == null) {
+ throw new TestingFrameworkException("Returned status is null.");
+ }
+ if ((expectedStatus != null) && (! actualStatus.equals(expectedStatus))) {
+ throw new TestingFrameworkException("Expected status not found. expected="
+ + expectedStatus + "; actual=" + actualStatus);
+ }
+ }
+
+ private void assertBodyMatchesExpectation(final Object actualBody, final Object expectedBody)
+ throws TestingFrameworkException {
+ if (actualBody == null) {
+ throw new TestingFrameworkException("Returned body is null.");
+ }
+ if ((expectedBody != null) && (! actualBody.equals(expectedBody))) {
+ throw new TestingFrameworkException("Expected body not found. expected="
+ + expectedBody + "; actual=" + actualBody);
+ }
+ }
+
+ private void assertContentTypeMatchesExpectation(final Object actualContentType, final Object expectedContentType)
+ throws TestingFrameworkException {
+ if (expectedContentType != null) {
+ if (actualContentType == null) {
+ throw new TestingFrameworkException("Returned contentType is null.");
+ }
+ if (! actualContentType.equals(expectedContentType)) {
+ throw new TestingFrameworkException("Expected content type not found. expected="
+ + expectedContentType + "; actual=" + actualContentType);
+ }
+ }
+ }
+
+ private void assertHeadersMatchExpectation(final Map<String, String> actualHeaders,
+ final Map<String, String> expectedHeaders)
+ throws TestingFrameworkException {
+ if (expectedHeaders == null) {
+ return;
+ }
+ for (Map.Entry<String, String> expectedHeader : ((Map<String, String>) expectedHeaders).entrySet()) {
+ final String expectedHeaderName = expectedHeader.getKey();
+ if (! actualHeaders.containsKey(expectedHeaderName)) {
+ throw new TestingFrameworkException("Expected header not found: name=" + expectedHeaderName);
+ }
+ if (! actualHeaders.get(expectedHeaderName).equals(expectedHeaders.get(expectedHeaderName))) {
+ throw new TestingFrameworkException("Header value not expected: name=" + expectedHeaderName
+ + "; expected=" + expectedHeaders.get(expectedHeaderName)
+ + "; actual=" + actualHeaders.get(expectedHeaderName));
+ }
+ }
+ }
+
+ private String getDefaultURI() {
+ return "http://localhost:" + port + "/";
+ }
+
+ /**
+ * Sets the {@link ClientTestingAdapter}.
+ *
+ * @param adapter
+ */
+ public void setAdapter(final ClientTestingAdapter adapter) {
+ this.adapter = adapter;
+ }
+
+ /**
+ * Deletes all tests.
+ */
+ public void deleteTests() {
+ tests = new ArrayList<FrameworkTest>();
+ }
+
+ /**
+ * Call to add a test with defaults.
+ *
+ * @throws TestingFrameworkException
+ */
+ public void addTest() throws TestingFrameworkException {
+ addTest(null);
+ }
+
+ /**
+ * Call to add a test. The test is a map with a REQUEST and a RESPONSE key.
+ * See {@link ClientPOJOAdapter} for details on the format of the request and response.
+ *
+ * @param test Map with a REQUEST and a RESPONSE key.
+ * @throws TestingFrameworkException
+ */
+ @SuppressWarnings("unchecked")
+ public void addTest(final Map<String, Object> test) throws TestingFrameworkException {
+ final Map<String, Object> testCopy = (Map<String, Object>) deepcopy(test);
+
+ tests.add(new FrameworkTest(testCopy));
+ }
+
+ /**
+ * Used to make a "deep" copy of an object. This testing framework makes deep copies
+ * of tests that are added as well as requestExpectations Maps and response Maps.
+ *
+ * @param orig a serializable object.
+ * @return a deep copy of the orig object.
+ * @throws TestingFrameworkException
+ */
+ public static Object deepcopy(final Object orig) throws TestingFrameworkException {
+ try {
+ // this is from http://stackoverflow.com/questions/13155127/deep-copy-map-in-groovy
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ final ObjectOutputStream oos = new ObjectOutputStream(bos);
+ oos.writeObject(orig);
+ oos.flush();
+ final ByteArrayInputStream bin = new ByteArrayInputStream(bos.toByteArray());
+ final ObjectInputStream ois = new ObjectInputStream(bin);
+ return ois.readObject();
+ } catch (ClassNotFoundException | IOException e) {
+ throw new TestingFrameworkException(e);
+ }
+ }
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFramework.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFramework.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFramework.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkException.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkException.java?rev=1763892&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkException.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkException.java Sat Oct 8 11:40:09 2016
@@ -0,0 +1,91 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.testing.framework;
+
+
+/**
+ * <p>Signals a problem or an assertion failure while using the {@link TestingFramework}.</p>
+ *
+ * <p>Optionally, an adapter and a test can be added to the exception. If this is done,
+ * the adapter name and the test information is appended to the exception message to help
+ * determine what test is having a problem.</p>
+ *
+ * @since 5.0
+ */
+public class TestingFrameworkException extends Exception {
+ public static final String NO_HTTP_CLIENT = "none";
+
+ private ClientTestingAdapter adapter;
+
+ private FrameworkTest test;
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -1010516169283589675L;
+
+ /**
+ * Creates a WebServerTestingFrameworkException with the specified detail message.
+ */
+ public TestingFrameworkException(final String message) {
+ super(message);
+ }
+
+ public TestingFrameworkException(final Throwable cause) {
+ super(cause);
+ }
+
+ @Override
+ public String getMessage() {
+ String message = super.getMessage();
+ if (adapter != null) {
+ final ClientPOJOAdapter pojoAdapter = adapter.getClientPOJOAdapter();
+ final String tempHttpClient = pojoAdapter == null ? null : pojoAdapter.getClientName();
+ final String httpClient = tempHttpClient == null ? NO_HTTP_CLIENT : tempHttpClient;
+ if (message == null) {
+ message = "null";
+ }
+ message += "\nHTTP Client=" + httpClient;
+ }
+ if (test != null) {
+ if (message == null) {
+ message = "null";
+ }
+ message += "\ntest:\n" + test;
+ }
+ return message;
+ }
+
+ public void setAdapter(final ClientTestingAdapter adapter) {
+ this.adapter = adapter;
+ }
+
+ public void setTest(final FrameworkTest test) {
+ this.test = test;
+ }
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkException.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkException.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkException.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkRequestHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkRequestHandler.java?rev=1763892&view=auto
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkRequestHandler.java (added)
+++ httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkRequestHandler.java Sat Oct 8 11:40:09 2016
@@ -0,0 +1,267 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.core5.testing.framework;
+
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.BODY;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.CONTENT_TYPE;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.HEADERS;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.METHOD;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.PROTOCOL_VERSION;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.QUERY;
+import static org.apache.hc.core5.testing.framework.ClientPOJOAdapter.STATUS;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.NameValuePair;
+import org.apache.hc.core5.http.ProtocolVersion;
+import org.apache.hc.core5.http.entity.ContentType;
+import org.apache.hc.core5.http.entity.EntityUtils;
+import org.apache.hc.core5.http.entity.StringEntity;
+import org.apache.hc.core5.http.io.HttpRequestHandler;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.apache.hc.core5.util.URLEncodedUtils;
+
+/**
+ * <p>This request handler is used with an in-process instance of HttpServer during testing.
+ * The handler is told what to expect in the request. If the request does not match
+ * the expectations, the handler will throw an exception which is then caught and
+ * saved in the "thrown" member. The testing framework will later call assertNothingThrown().
+ * If something was thrown earlier by the handler, an exception will be thrown by the method.</p>
+ *
+ * <p>The handler is also told what response to return.</p>
+ *
+ * <p>See {@link ClientPOJOAdapter} for details on the format of the request and response.</p>
+ *
+ * @since 5.0
+ *
+ */
+public class TestingFrameworkRequestHandler implements HttpRequestHandler {
+ protected Throwable thrown;
+ protected Map<String, Object> requestExpectations;
+ protected Map<String, Object> desiredResponse;
+
+ /**
+ * Sets the request expectations.
+ *
+ * @param requestExpectations the expected values of the request.
+ * @throws TestingFrameworkException
+ */
+ @SuppressWarnings("unchecked")
+ public void setRequestExpectations(final Map<String, Object> requestExpectations) throws TestingFrameworkException {
+ this.requestExpectations = (Map<String, Object>) TestingFramework.deepcopy(requestExpectations);
+ }
+
+ /**
+ * Sets the desired response. The handler will return a response that matches this.
+ *
+ * @param desiredResponse the desired response.
+ * @throws TestingFrameworkException
+ */
+ @SuppressWarnings("unchecked")
+ public void setDesiredResponse(final Map<String, Object> desiredResponse) throws TestingFrameworkException {
+ this.desiredResponse = (Map<String, Object>) TestingFramework.deepcopy(desiredResponse);
+ }
+
+ /**
+ * After the handler returns the response, any exception or failed assertion will be
+ * in the member called "thrown". A testing framework can later call this method
+ * which will rethrow the exception that was thrown before.
+ *
+ * @throws TestingFrameworkException
+ */
+ public void assertNothingThrown() throws TestingFrameworkException {
+ if (thrown != null) {
+ final TestingFrameworkException e = (thrown instanceof TestingFrameworkException ?
+ (TestingFrameworkException) thrown :
+ new TestingFrameworkException(thrown));
+ thrown = null;
+ throw e;
+ }
+ }
+
+ /**
+ * <p>Checks the HTTP request against the requestExpectations that it was previously given.
+ * If there is a mismatch, an exception will be saved in the "thrown" member.</p>
+ *
+ * <p>Also, a response will be returned that matches the desiredResponse.</p>
+ */
+ @Override
+ public void handle(final ClassicHttpRequest request, final ClassicHttpResponse response, final HttpContext context)
+ throws HttpException, IOException {
+
+ try {
+ /*
+ * Check the method against the method in the requestExpectations.
+ */
+ final String actualMethod = request.getMethod();
+ final String expectedMethod = (String) requestExpectations.get(METHOD);
+ if (! actualMethod.equals(expectedMethod)) {
+ throw new TestingFrameworkException("Method not expected. " +
+ " expected=" + expectedMethod + "; actual=" + actualMethod);
+ }
+
+ /*
+ * Set the status to the status that is in the desiredResponse.
+ */
+ final Object desiredStatus = desiredResponse.get(STATUS);
+ if (desiredStatus != null) {
+ response.setCode((int) desiredStatus);
+ }
+
+ /*
+ * Check the query parameters against the parameters in requestExpectations.
+ */
+ @SuppressWarnings("unchecked")
+ final Map<String, String> expectedQuery = (Map<String, String>) requestExpectations.get(QUERY);
+ if (expectedQuery != null) {
+ final URI uri = request.getUri();
+ final List<NameValuePair> actualParams = URLEncodedUtils.parse(uri, StandardCharsets.UTF_8);
+ final Map<String, String> actualParamsMap = new HashMap<String, String>();
+ for (NameValuePair actualParam : actualParams) {
+ actualParamsMap.put(actualParam.getName(), actualParam.getValue());
+ }
+ for (Map.Entry<String, String> expectedParam : expectedQuery.entrySet()) {
+ final String key = expectedParam.getKey();
+ if (! actualParamsMap.containsKey(key)) {
+ throw new TestingFrameworkException("Expected parameter not found: " + key);
+ }
+ final String actualParamValue = actualParamsMap.get(key);
+ final String expectedParamValue = expectedParam.getValue();
+ if (! actualParamValue.equals(expectedParamValue)) {
+ throw new TestingFrameworkException("Expected parameter value not found. " +
+ " Parameter=" + key + "; expected=" + expectedParamValue + "; actual=" + actualParamValue);
+ }
+ }
+ }
+
+ /*
+ * Check the headers against the headers in requestExpectations.
+ */
+ @SuppressWarnings("unchecked")
+ final Map<String, String> expectedHeaders = (Map<String, String>) requestExpectations.get(HEADERS);
+ if (expectedHeaders != null) {
+ final Map<String, String> actualHeadersMap = new HashMap<String, String>();
+ final Header[] actualHeaders = request.getAllHeaders();
+ for (Header header : actualHeaders) {
+ actualHeadersMap.put(header.getName(), header.getValue());
+ }
+ for (Entry<String, String> expectedHeader : expectedHeaders.entrySet()) {
+ final String key = expectedHeader.getKey();
+ if (! actualHeadersMap.containsKey(key)) {
+ throw new TestingFrameworkException("Expected header not found: " + key);
+ }
+ final String actualHeaderValue = actualHeadersMap.get(key);
+ final String expectedHeaderValue = expectedHeader.getValue();
+ if (! actualHeaderValue.equals(expectedHeaderValue)) {
+ throw new TestingFrameworkException("Expected header value not found. " +
+ " Name=" + key + "; expected=" + expectedHeaderValue + "; actual=" + actualHeaderValue);
+ }
+ }
+ }
+
+ /*
+ * Check the body.
+ */
+ final String expectedBody = (String) requestExpectations.get(BODY);
+ if (expectedBody != null) {
+ final HttpEntity entity = request.getEntity();
+ final String data = EntityUtils.toString(entity);
+ if (! data.equals(expectedBody)) {
+ throw new TestingFrameworkException("Expected body not found. " +
+ " Body=" + data + "; expected=" + expectedBody);
+ }
+ }
+
+ /*
+ * Check the contentType of the request.
+ */
+ final String requestContentType = (String) requestExpectations.get(CONTENT_TYPE);
+ if (requestContentType != null) {
+ final HttpEntity entity = request.getEntity();
+ final String contentType = entity.getContentType();
+ final String expectedContentType = (String) requestExpectations.get(CONTENT_TYPE);
+ if (! contentType.equals(expectedContentType)) {
+ throw new TestingFrameworkException("Expected request content type not found. " +
+ " Content Type=" + contentType + "; expected=" + expectedContentType);
+ }
+ }
+
+ /*
+ * Check the protocolVersion.
+ */
+ if (requestExpectations.containsKey(PROTOCOL_VERSION)) {
+ final ProtocolVersion protocolVersion = request.getVersion();
+ final ProtocolVersion expectedProtocolVersion = (ProtocolVersion) requestExpectations.get(PROTOCOL_VERSION);
+ if (! protocolVersion.equals(expectedProtocolVersion)) {
+ throw new TestingFrameworkException("Expected request protocol version not found. " +
+ " Protocol Version=" + protocolVersion + "; expected=" + expectedProtocolVersion);
+ }
+ }
+
+ /*
+ * Return the body in desiredResponse using the contentType in desiredResponse.
+ */
+ final String desiredBody = (String) desiredResponse.get(BODY);
+ if (desiredBody != null) {
+ final String desiredContentType = (String) desiredResponse.get(CONTENT_TYPE);
+ final StringEntity entity = desiredContentType != null ?
+ new StringEntity(desiredBody, ContentType.parse(desiredContentType)) :
+ new StringEntity(desiredBody);
+ response.setEntity(entity);
+ }
+
+ /*
+ * Return the headers in desiredResponse.
+ */
+ @SuppressWarnings("unchecked")
+ final Map<String, String> desiredHeaders = (Map<String, String>) desiredResponse.get(HEADERS);
+ if (desiredHeaders != null) {
+ for (Entry<String, String> entry : desiredHeaders.entrySet()) {
+ response.setHeader(entry.getKey(), entry.getValue());
+ }
+ }
+
+ } catch (Throwable t) {
+ /*
+ * Save the throwable to be later retrieved by a call to assertNothingThrown().
+ */
+ thrown = t;
+ }
+ }
+}
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkRequestHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkRequestHandler.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpcore/trunk/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/framework/TestingFrameworkRequestHandler.java
------------------------------------------------------------------------------
svn:mime-type = text/plain