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 2010/04/30 23:00:10 UTC
svn commit: r939814 [3/6] - in /httpcomponents/httpclient/trunk: ./
httpclient-cache/ httpclient-cache/src/ httpclient-cache/src/main/
httpclient-cache/src/main/java/ httpclient-cache/src/main/java/org/
httpclient-cache/src/main/java/org/apache/ httpcl...
Added: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/client/cache/impl/URIExtractor.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/client/cache/impl/URIExtractor.java?rev=939814&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/client/cache/impl/URIExtractor.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/client/cache/impl/URIExtractor.java Fri Apr 30 21:00:08 2010
@@ -0,0 +1,101 @@
+/*
+ * ====================================================================
+ * 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.http.client.cache.impl;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+
+/**
+ * @since 4.1
+ */
+public class URIExtractor {
+
+ public String getURI(HttpHost host, HttpRequest req) {
+ return String.format("%s%s", host.toString(), req.getRequestLine().getUri());
+ }
+
+ protected String getFullHeaderValue(Header[] headers) {
+ if (headers == null)
+ return "";
+
+ StringBuilder buf = new StringBuilder("");
+ boolean first = true;
+ for (Header hdr : headers) {
+ if (!first) {
+ buf.append(", ");
+ }
+ buf.append(hdr.getValue().trim());
+ first = false;
+
+ }
+ return buf.toString();
+ }
+
+ public String getVariantURI(HttpHost host, HttpRequest req, CacheEntry entry) {
+ Header[] varyHdrs = entry.getHeaders(HeaderConstants.VARY);
+ if (varyHdrs == null || varyHdrs.length == 0) {
+ return getURI(host, req);
+ }
+
+ List<String> variantHeaderNames = new ArrayList<String>();
+ for (Header varyHdr : varyHdrs) {
+ for (HeaderElement elt : varyHdr.getElements()) {
+ variantHeaderNames.add(elt.getName());
+ }
+ }
+ Collections.sort(variantHeaderNames);
+
+ try {
+ StringBuilder buf = new StringBuilder("{");
+ boolean first = true;
+ for (String headerName : variantHeaderNames) {
+ if (!first) {
+ buf.append("&");
+ }
+ buf.append(URLEncoder.encode(headerName, "UTF-8"));
+ buf.append("=");
+ buf.append(URLEncoder.encode(getFullHeaderValue(req.getHeaders(headerName)),
+ "UTF-8"));
+ first = false;
+ }
+ buf.append("}");
+ buf.append(getURI(host, req));
+ return buf.toString();
+ } catch (UnsupportedEncodingException uee) {
+ throw new RuntimeException("couldn't encode to UTF-8", uee);
+ }
+ }
+
+}
\ No newline at end of file
Added: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/Counter.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/Counter.java?rev=939814&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/Counter.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/Counter.java Fri Apr 30 21:00:08 2010
@@ -0,0 +1,41 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * 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.http.client.cache.impl;
+
+public class Counter {
+
+ private int count;
+
+ public void incr() {
+ count++;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+}
\ No newline at end of file
Added: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/DoNotTestProtocolRequirements.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/DoNotTestProtocolRequirements.java?rev=939814&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/DoNotTestProtocolRequirements.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/DoNotTestProtocolRequirements.java Fri Apr 30 21:00:08 2010
@@ -0,0 +1,187 @@
+/*
+ * ====================================================================
+ * 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.http.client.cache.impl;
+
+import java.util.Date;
+import java.util.Random;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.NameValuePair;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.cache.HttpCache;
+import org.apache.http.client.cache.impl.BasicHttpCache;
+import org.apache.http.client.cache.impl.CachingHttpClient;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.impl.cookie.DateUtils;
+import org.apache.http.message.BasicHttpRequest;
+import org.apache.http.message.BasicHttpResponse;
+import org.apache.http.protocol.HttpContext;
+import org.easymock.classextension.EasyMock;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class DoNotTestProtocolRequirements {
+
+ private static ProtocolVersion HTTP_1_1 = new ProtocolVersion("HTTP", 1, 1);
+
+ private static int MAX_BYTES = 1024;
+ private static int MAX_ENTRIES = 100;
+
+ private HttpHost host;
+ private HttpEntity mockEntity;
+ private HttpClient mockBackend;
+ private HttpCache<CacheEntry> mockCache;
+ private HttpRequest request;
+ private HttpResponse originResponse;
+
+ private CachingHttpClient impl;
+
+ @SuppressWarnings("unchecked")
+ @Before
+ public void setUp() {
+ host = new HttpHost("foo.example.com");
+
+ request = new BasicHttpRequest("GET", "/foo", HTTP_1_1);
+
+ originResponse = make200Response();
+
+ HttpCache<CacheEntry> cache = new BasicHttpCache(MAX_ENTRIES);
+ mockBackend = EasyMock.createMock(HttpClient.class);
+ mockEntity = EasyMock.createMock(HttpEntity.class);
+ mockCache = EasyMock.createMock(HttpCache.class);
+ impl = new CachingHttpClient(mockBackend, cache, MAX_BYTES);
+ }
+
+ private HttpResponse make200Response() {
+ HttpResponse out = new BasicHttpResponse(HTTP_1_1, HttpStatus.SC_OK, "OK");
+ out.setHeader("Date", DateUtils.formatDate(new Date()));
+ out.setHeader("Server", "MockOrigin/1.0");
+ out.setEntity(makeBody(128));
+ return out;
+ }
+
+ private void replayMocks() {
+ EasyMock.replay(mockBackend);
+ EasyMock.replay(mockCache);
+ EasyMock.replay(mockEntity);
+ }
+
+ private HttpEntity makeBody(int nbytes) {
+ byte[] bytes = new byte[nbytes];
+ (new Random()).nextBytes(bytes);
+ return new ByteArrayEntity(bytes);
+ }
+
+ /*
+ * "10.2.7 206 Partial Content ... The response MUST include the following
+ * header fields:
+ *
+ * - Either a Content-Range header field (section 14.16) indicating the
+ * range included with this response, or a multipart/byteranges Content-Type
+ * including Content-Range fields for each part. If a Content-Length header
+ * field is present in the response, its value MUST match the actual number
+ * of OCTETs transmitted in the message-body.
+ *
+ * - Date
+ *
+ * - ETag and/or Content-Location, if the header would have been sent in a
+ * 200 response to the same request
+ *
+ * - Expires, Cache-Control, and/or Vary, if the field-value might differ
+ * from that sent in any previous response for the same variant
+ *
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.7
+ */
+ @Test
+ @Ignore
+ public void test206ResponseReturnedToClientMustHaveContentRangeOrByteRangesContentType()
+ throws Exception {
+ request.addHeader("Range", "bytes 0-499/1234");
+ originResponse = new BasicHttpResponse(HTTP_1_1, HttpStatus.SC_PARTIAL_CONTENT,
+ "Partial Content");
+ originResponse.setHeader("Date", DateUtils.formatDate(new Date()));
+ originResponse.setHeader("Server", "MockOrigin/1.0");
+ originResponse.setEntity(makeBody(500));
+
+ org.easymock.EasyMock.expect(
+ mockBackend.execute(org.easymock.EasyMock.isA(HttpHost.class),
+ org.easymock.EasyMock.isA(HttpRequest.class),
+ (HttpContext) org.easymock.EasyMock.isNull())).andReturn(originResponse);
+
+ replayMocks();
+
+ try {
+ HttpResponse result = impl.execute(host, request);
+ Header crHdr = result.getFirstHeader("Content-Range");
+ Header ctHdr = result.getFirstHeader("Content-Type");
+ if (result.getStatusLine().getStatusCode() == HttpStatus.SC_PARTIAL_CONTENT) {
+ if (crHdr == null) {
+ Assert.assertNotNull(ctHdr);
+ boolean foundMultipartByteRanges = false;
+ for (HeaderElement elt : ctHdr.getElements()) {
+ if ("multipart/byteranges".equalsIgnoreCase(elt.getName())) {
+ NameValuePair param = elt.getParameterByName("boundary");
+ Assert.assertNotNull(param);
+ String boundary = param.getValue();
+ Assert.assertNotNull(boundary);
+ // perhaps eventually should parse out the
+ // request body to check proper formatting
+ // but that might be excessive; HttpClient
+ // developers have indicated that
+ // HttpClient's job does not involve
+ // parsing a response body
+ }
+ }
+ Assert.assertTrue(foundMultipartByteRanges);
+ }
+ }
+ } catch (ClientProtocolException acceptableBehavior) {
+ }
+ }
+
+ @Test
+ @Ignore
+ public void test206ResponseReturnedToClientWithAContentLengthMustMatchActualOctetsTransmitted() {
+ // We are explicitly saying that CachingHttpClient does not care about
+ // this:
+ // We do not attempt to cache 206, nor do we ever construct a 206. We
+ // simply pass along a 206,
+ // which could be malformed. But protocol compliance of a downstream
+ // server is not our responsibility
+ }
+
+}
Added: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/HttpTestUtils.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/HttpTestUtils.java?rev=939814&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/HttpTestUtils.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/HttpTestUtils.java Fri Apr 30 21:00:08 2010
@@ -0,0 +1,194 @@
+/*
+ * ====================================================================
+ * 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.http.client.cache.impl;
+
+import java.io.InputStream;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpMessage;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.RequestLine;
+import org.apache.http.StatusLine;
+
+public class HttpTestUtils {
+
+ /*
+ * "The following HTTP/1.1 headers are hop-by-hop headers..."
+ *
+ * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
+ */
+ public static String[] HOP_BY_HOP_HEADERS = { "Connection", "Keep-Alive", "Proxy-Authenticate",
+ "Proxy-Authorization", "TE", "Trailers", "Transfer-Encoding", "Upgrade" };
+
+ /*
+ * "Multiple message-header fields with the same field-name MAY be present
+ * in a message if and only if the entire field-value for that header field
+ * is defined as a comma-separated list [i.e., #(values)]."
+ *
+ * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
+ */
+ public static String[] MULTI_HEADERS = { "Accept", "Accept-Charset", "Accept-Encoding",
+ "Accept-Language", "Allow", "Cache-Control", "Connection", "Content-Encoding",
+ "Content-Language", "Expect", "Pragma", "Proxy-Authenticate", "TE", "Trailer",
+ "Transfer-Encoding", "Upgrade", "Via", "Warning", "WWW-Authenticate" };
+ public static String[] SINGLE_HEADERS = { "Accept-Ranges", "Age", "Authorization",
+ "Content-Length", "Content-Location", "Content-MD5", "Content-Range", "Content-Type",
+ "Date", "ETag", "Expires", "From", "Host", "If-Match", "If-Modified-Since",
+ "If-None-Match", "If-Range", "If-Unmodified-Since", "Last-Modified", "Location",
+ "Max-Forwards", "Proxy-Authorization", "Range", "Referer", "Retry-After", "Server",
+ "User-Agent", "Vary" };
+
+ /*
+ * Determines whether the given header name is considered a hop-by-hop
+ * header.
+ *
+ * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
+ */
+ public static boolean isHopByHopHeader(String name) {
+ for (String s : HOP_BY_HOP_HEADERS) {
+ if (s.equalsIgnoreCase(name))
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ * Determines whether a given header name may only appear once in a message.
+ */
+ public static boolean isSingleHeader(String name) {
+ for (String s : SINGLE_HEADERS) {
+ if (s.equalsIgnoreCase(name))
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ * Assert.asserts that two request or response bodies are byte-equivalent.
+ */
+ public static boolean equivalent(HttpEntity e1, HttpEntity e2) throws Exception {
+ InputStream i1 = e1.getContent();
+ InputStream i2 = e2.getContent();
+ if (i1 == null && i2 == null)
+ return true;
+ int b1 = -1;
+ while ((b1 = i1.read()) != -1) {
+ if (b1 != i2.read())
+ return false;
+ }
+ return (-1 == i2.read());
+ }
+
+ /*
+ * Assert.asserts that the components of two status lines match in a way
+ * that differs only by hop-by-hop information. "2.1 Proxy Behavior ...We
+ * remind the reader that HTTP version numbers are hop-by-hop components of
+ * HTTP meesages, and are not end-to-end."
+ *
+ * @see http://www.ietf.org/rfc/rfc2145.txt
+ */
+ public static boolean semanticallyTransparent(StatusLine l1, StatusLine l2) {
+ return (l1.getReasonPhrase().equals(l2.getReasonPhrase()) && l1.getStatusCode() == l2
+ .getStatusCode());
+ }
+
+ /* Assert.asserts that the components of two status lines match. */
+ public static boolean equivalent(StatusLine l1, StatusLine l2) {
+ return (l1.getProtocolVersion().equals(l2.getProtocolVersion()) && semanticallyTransparent(
+ l1, l2));
+ }
+
+ /* Assert.asserts that the components of two request lines match. */
+ public static boolean equivalent(RequestLine l1, RequestLine l2) {
+ return (l1.getMethod().equals(l2.getMethod())
+ && l1.getProtocolVersion().equals(l2.getProtocolVersion()) && l1.getUri().equals(
+ l2.getUri()));
+ }
+
+ /*
+ * Retrieves the full header value by combining multiple headers and
+ * separating with commas, canonicalizing whitespace along the way.
+ *
+ * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
+ */
+ public static String getCanonicalHeaderValue(HttpMessage r, String name) {
+ if (isSingleHeader(name)) {
+ Header h = r.getFirstHeader(name);
+ return (h != null) ? h.getValue() : null;
+ }
+ StringBuilder buf = new StringBuilder();
+ boolean first = true;
+ for (Header h : r.getHeaders(name)) {
+ if (!first) {
+ buf.append(", ");
+ }
+ buf.append(h.getValue().trim());
+ first = false;
+ }
+ return buf.toString();
+ }
+
+ /*
+ * Assert.asserts that all the headers appearing in r1 also appear in r2
+ * with the same canonical header values.
+ */
+ public static boolean isEndToEndHeaderSubset(HttpMessage r1, HttpMessage r2) {
+ for (Header h : r1.getAllHeaders()) {
+ if (!isHopByHopHeader(h.getName())) {
+ String r1val = getCanonicalHeaderValue(r1, h.getName());
+ String r2val = getCanonicalHeaderValue(r2, h.getName());
+ if (!r1val.equals(r2val))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*
+ * Assert.asserts that message <code>r2</code> represents exactly the same
+ * message as <code>r1</code>, except for hop-by-hop headers. "When a cache
+ * is semantically transparent, the client receives exactly the same
+ * response (except for hop-by-hop headers) that it would have received had
+ * its request been handled directly by the origin server."
+ *
+ * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec1.html#sec1.3
+ */
+ public static boolean semanticallyTransparent(HttpResponse r1, HttpResponse r2)
+ throws Exception {
+ return (equivalent(r1.getEntity(), r2.getEntity())
+ && semanticallyTransparent(r1.getStatusLine(), r2.getStatusLine()) && isEndToEndHeaderSubset(
+ r1, r2));
+ }
+
+ /* Assert.asserts that two requests are morally equivalent. */
+ public static boolean equivalent(HttpRequest r1, HttpRequest r2) {
+ return (equivalent(r1.getRequestLine(), r2.getRequestLine()) && isEndToEndHeaderSubset(r1,
+ r2));
+ }
+}
\ No newline at end of file
Added: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/RequestEquivalent.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/RequestEquivalent.java?rev=939814&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/RequestEquivalent.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/RequestEquivalent.java Fri Apr 30 21:00:08 2010
@@ -0,0 +1,53 @@
+/*
+ * ====================================================================
+ * 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.http.client.cache.impl;
+
+import org.apache.http.HttpRequest;
+import org.easymock.IArgumentMatcher;
+
+public class RequestEquivalent implements IArgumentMatcher {
+
+ private HttpRequest expected;
+
+ public RequestEquivalent(HttpRequest expected) {
+ this.expected = expected;
+ }
+
+ public boolean matches(Object actual) {
+ if (!(actual instanceof HttpRequest))
+ return false;
+ HttpRequest other = (HttpRequest) actual;
+ return HttpTestUtils.equivalent(expected, other);
+ }
+
+ public void appendTo(StringBuffer buf) {
+ buf.append("eqRequest(");
+ buf.append(expected);
+ buf.append(")");
+ }
+
+}
\ No newline at end of file
Added: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/Serializer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/Serializer.java?rev=939814&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/Serializer.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/Serializer.java Fri Apr 30 21:00:08 2010
@@ -0,0 +1,51 @@
+/*
+ * ====================================================================
+ * 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.http.client.cache.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+public class Serializer<T> {
+
+ public byte[] serialize(T object) throws Exception {
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ ObjectOutputStream objectStream = new ObjectOutputStream(byteStream);
+ objectStream.writeObject(object);
+ return byteStream.toByteArray();
+ }
+
+ @SuppressWarnings("unchecked")
+ public T deserialize(byte[] serialized) throws Exception {
+ ByteArrayInputStream byteStream = new ByteArrayInputStream(serialized);
+ ObjectInputStream objectStream = new ObjectInputStream(byteStream);
+ T object = (T) objectStream.readObject();
+ return object;
+ }
+
+}
Added: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheEntry.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheEntry.java?rev=939814&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheEntry.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheEntry.java Fri Apr 30 21:00:08 2010
@@ -0,0 +1,494 @@
+/*
+ * ====================================================================
+ * 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.http.client.cache.impl;
+
+import java.util.Date;
+import java.util.Set;
+
+import org.apache.http.Header;
+import org.apache.http.client.cache.impl.CacheEntry;
+import org.apache.http.impl.cookie.DateUtils;
+import org.apache.http.message.BasicHeader;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestCacheEntry {
+
+ @Test
+ public void testGetHeadersReturnsCorrectHeaders() {
+ Header[] headers = new Header[] { new BasicHeader("foo", "fooValue"),
+ new BasicHeader("bar", "barValue1"), new BasicHeader("bar", "barValue2") };
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+ Assert.assertEquals(2, entry.getHeaders("bar").length);
+ }
+
+ @Test
+ public void testGetFirstHeaderReturnsCorrectHeader() {
+ Header[] headers = new Header[] { new BasicHeader("foo", "fooValue"),
+ new BasicHeader("bar", "barValue1"), new BasicHeader("bar", "barValue2") };
+
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+ Assert.assertEquals("barValue1", entry.getFirstHeader("bar").getValue());
+ }
+
+ @Test
+ public void testGetHeadersReturnsEmptyArrayIfNoneMatch() {
+ Header[] headers = new Header[] { new BasicHeader("foo", "fooValue"),
+ new BasicHeader("bar", "barValue1"), new BasicHeader("bar", "barValue2") };
+
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+
+ Assert.assertEquals(0, entry.getHeaders("baz").length);
+ }
+
+ @Test
+ public void testGetFirstHeaderReturnsNullIfNoneMatch() {
+ Header[] headers = new Header[] { new BasicHeader("foo", "fooValue"),
+ new BasicHeader("bar", "barValue1"), new BasicHeader("bar", "barValue2") };
+
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+
+ Assert.assertEquals(null, entry.getFirstHeader("quux"));
+ }
+
+ @Test
+ public void testApparentAgeIsMaxIntIfDateHeaderNotPresent() {
+ Header[] headers = new Header[0];
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+ Assert.assertEquals(2147483648L, entry.getApparentAgeSecs());
+ }
+
+ @Test
+ public void testApparentAgeIsResponseReceivedTimeLessDateHeader() {
+ Date now = new Date();
+ Date sixSecondsAgo = new Date(now.getTime() - 6 * 1000L);
+ Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
+
+ Header[] headers = new Header[] { new BasicHeader("Date", DateUtils
+ .formatDate(tenSecondsAgo)) };
+
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+ entry.setResponseDate(sixSecondsAgo);
+
+ Assert.assertEquals(4, entry.getApparentAgeSecs());
+ }
+
+ @Test
+ public void testNegativeApparentAgeIsBroughtUpToZero() {
+ Date now = new Date();
+ Date sixSecondsAgo = new Date(now.getTime() - 6 * 1000L);
+ Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
+
+ Header[] headers = new Header[] { new BasicHeader("Date", DateUtils
+ .formatDate(sixSecondsAgo)) };
+
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+ entry.setResponseDate(tenSecondsAgo);
+
+ Assert.assertEquals(0, entry.getApparentAgeSecs());
+ }
+
+ @Test
+ public void testCorrectedReceivedAgeIsAgeHeaderIfLarger() {
+ Header[] headers = new Header[] { new BasicHeader("Age", "10"), };
+ CacheEntry entry = new CacheEntry() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected long getApparentAgeSecs() {
+ return 6;
+ }
+ };
+ entry.setResponseHeaders(headers);
+
+ Assert.assertEquals(10, entry.getCorrectedReceivedAgeSecs());
+ }
+
+ @Test
+ public void testCorrectedReceivedAgeIsApparentAgeIfLarger() {
+ Header[] headers = new Header[] { new BasicHeader("Age", "6"), };
+ CacheEntry entry = new CacheEntry() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected long getApparentAgeSecs() {
+ return 10;
+ }
+ };
+ entry.setResponseHeaders(headers);
+
+ Assert.assertEquals(10, entry.getCorrectedReceivedAgeSecs());
+ }
+
+ @Test
+ public void testResponseDelayIsDifferenceBetweenResponseAndRequestTimes() {
+ Date now = new Date();
+ Date sixSecondsAgo = new Date(now.getTime() - 6 * 1000L);
+ Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
+
+ CacheEntry entry = new CacheEntry();
+ entry.setRequestDate(tenSecondsAgo);
+ entry.setResponseDate(sixSecondsAgo);
+
+ Assert.assertEquals(4, entry.getResponseDelaySecs());
+ }
+
+ @Test
+ public void testCorrectedInitialAgeIsCorrectedReceivedAgePlusResponseDelay() {
+ CacheEntry entry = new CacheEntry() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected long getCorrectedReceivedAgeSecs() {
+ return 7;
+ }
+
+ @Override
+ protected long getResponseDelaySecs() {
+ return 13;
+ }
+ };
+ Assert.assertEquals(20, entry.getCorrectedInitialAgeSecs());
+ }
+
+ @Test
+ public void testResidentTimeSecondsIsTimeSinceResponseTime() {
+ final Date now = new Date();
+ Date sixSecondsAgo = new Date(now.getTime() - 6 * 1000L);
+
+ CacheEntry entry = new CacheEntry() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected Date getCurrentDate() {
+ return now;
+ }
+ };
+ entry.setResponseDate(sixSecondsAgo);
+
+ Assert.assertEquals(6, entry.getResidentTimeSecs());
+ }
+
+ @Test
+ public void testCurrentAgeIsCorrectedInitialAgePlusResidentTime() {
+ CacheEntry entry = new CacheEntry() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected long getCorrectedInitialAgeSecs() {
+ return 11;
+ }
+
+ @Override
+ protected long getResidentTimeSecs() {
+ return 17;
+ }
+ };
+ Assert.assertEquals(28, entry.getCurrentAgeSecs());
+ }
+
+ @Test
+ public void testFreshnessLifetimeIsSMaxAgeIfPresent() {
+ Header[] headers = new Header[] { new BasicHeader("Cache-Control", "s-maxage=10") };
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+ Assert.assertEquals(10, entry.getFreshnessLifetimeSecs());
+ }
+
+ @Test
+ public void testFreshnessLifetimeIsMaxAgeIfPresent() {
+ Header[] headers = new Header[] { new BasicHeader("Cache-Control", "max-age=10") };
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+ Assert.assertEquals(10, entry.getFreshnessLifetimeSecs());
+ }
+
+ @Test
+ public void testFreshnessLifetimeIsMostRestrictiveOfMaxAgeAndSMaxAge() {
+ Header[] headers = new Header[] { new BasicHeader("Cache-Control", "max-age=10"),
+ new BasicHeader("Cache-Control", "s-maxage=20") };
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+ Assert.assertEquals(10, entry.getFreshnessLifetimeSecs());
+
+ headers = new Header[] { new BasicHeader("Cache-Control", "max-age=20"),
+ new BasicHeader("Cache-Control", "s-maxage=10") };
+ entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+ Assert.assertEquals(10, entry.getFreshnessLifetimeSecs());
+ }
+
+ @Test
+ public void testFreshnessLifetimeIsMaxAgeEvenIfExpiresIsPresent() {
+ Date now = new Date();
+ Date sixSecondsAgo = new Date(now.getTime() - 6 * 1000L);
+ Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
+ Header[] headers = new Header[] { new BasicHeader("Cache-Control", "max-age=10"),
+ new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+ new BasicHeader("Expires", DateUtils.formatDate(sixSecondsAgo)) };
+
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+ Assert.assertEquals(10, entry.getFreshnessLifetimeSecs());
+ }
+
+ @Test
+ public void testFreshnessLifetimeIsSMaxAgeEvenIfExpiresIsPresent() {
+ Date now = new Date();
+ Date sixSecondsAgo = new Date(now.getTime() - 6 * 1000L);
+ Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
+ Header[] headers = new Header[] { new BasicHeader("Cache-Control", "s-maxage=10"),
+ new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+ new BasicHeader("Expires", DateUtils.formatDate(sixSecondsAgo)) };
+
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+ Assert.assertEquals(10, entry.getFreshnessLifetimeSecs());
+ }
+
+ @Test
+ public void testFreshnessLifetimeIsFromExpiresHeaderIfNoMaxAge() {
+ Date now = new Date();
+ Date sixSecondsAgo = new Date(now.getTime() - 6 * 1000L);
+ Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
+ Header[] headers = new Header[] {
+ new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)),
+ new BasicHeader("Expires", DateUtils.formatDate(sixSecondsAgo)) };
+
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+ Assert.assertEquals(4, entry.getFreshnessLifetimeSecs());
+ }
+
+ @Test
+ public void testResponseIsFreshIfFreshnessLifetimeExceedsCurrentAge() {
+ CacheEntry entry = new CacheEntry() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public long getCurrentAgeSecs() {
+ return 6;
+ }
+
+ @Override
+ public long getFreshnessLifetimeSecs() {
+ return 10;
+ }
+ };
+
+ Assert.assertTrue(entry.isResponseFresh());
+ }
+
+ @Test
+ public void testResponseIsNotFreshIfFreshnessLifetimeEqualsCurrentAge() {
+ CacheEntry entry = new CacheEntry() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public long getCurrentAgeSecs() {
+ return 6;
+ }
+
+ @Override
+ public long getFreshnessLifetimeSecs() {
+ return 6;
+ }
+ };
+
+ Assert.assertFalse(entry.isResponseFresh());
+ }
+
+ @Test
+ public void testResponseIsNotFreshIfCurrentAgeExceedsFreshnessLifetime() {
+ CacheEntry entry = new CacheEntry() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public long getCurrentAgeSecs() {
+ return 10;
+ }
+
+ @Override
+ public long getFreshnessLifetimeSecs() {
+ return 6;
+ }
+ };
+
+ Assert.assertFalse(entry.isResponseFresh());
+ }
+
+ @Test
+ public void testCacheEntryIsRevalidatableIfHeadersIncludeETag() {
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(new Header[] {
+ new BasicHeader("Expires", DateUtils.formatDate(new Date())),
+ new BasicHeader("ETag", "somevalue") });
+
+ Assert.assertTrue(entry.isRevalidatable());
+ }
+
+ @Test
+ public void testCacheEntryIsRevalidatableIfHeadersIncludeLastModifiedDate() {
+ CacheEntry entry = new CacheEntry();
+
+ entry.setResponseHeaders(new Header[] {
+ new BasicHeader("Expires", DateUtils.formatDate(new Date())),
+ new BasicHeader("Last-Modified", DateUtils.formatDate(new Date())) });
+
+ Assert.assertTrue(entry.isRevalidatable());
+ }
+
+ @Test
+ public void testCacheEntryIsNotRevalidatableIfNoAppropriateHeaders() {
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(new Header[] {
+ new BasicHeader("Expires", DateUtils.formatDate(new Date())),
+ new BasicHeader("Cache-Control", "public") });
+ }
+
+ @Test
+ public void testCacheEntryWithNoVaryHeaderDoesNotHaveVariants() {
+ Header[] headers = new Header[0];
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+ Assert.assertFalse(entry.hasVariants());
+ }
+
+ @Test
+ public void testCacheEntryWithOneVaryHeaderHasVariants() {
+ Header[] headers = { new BasicHeader("Vary", "User-Agent") };
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+ Assert.assertTrue(entry.hasVariants());
+ }
+
+ @Test
+ public void testCacheEntryWithMultipleVaryHeadersHasVariants() {
+ Header[] headers = { new BasicHeader("Vary", "User-Agent"),
+ new BasicHeader("Vary", "Accept-Encoding") };
+ CacheEntry entry = new CacheEntry();
+ entry.setResponseHeaders(headers);
+ Assert.assertTrue(entry.hasVariants());
+ }
+
+ @Test
+ public void testCacheEntryCanStoreMultipleVariantUris() {
+
+ CacheEntry entry = new CacheEntry();
+
+ entry.addVariantURI("foo");
+ entry.addVariantURI("bar");
+
+ Set<String> variants = entry.getVariantURIs();
+
+ Assert.assertTrue(variants.contains("foo"));
+ Assert.assertTrue(variants.contains("bar"));
+ }
+
+ @Test
+ public void testMalformedDateHeaderIsIgnored() {
+
+ Header[] h = new Header[] { new BasicHeader("Date", "asdf") };
+ CacheEntry e = new CacheEntry();
+ e.setResponseHeaders(h);
+
+ Date d = e.getDateValue();
+
+ Assert.assertNull(d);
+
+ }
+
+ @Test
+ public void testMalformedContentLengthReturnsNegativeOne() {
+
+ Header[] h = new Header[] { new BasicHeader("Content-Length", "asdf") };
+ CacheEntry e = new CacheEntry();
+ e.setResponseHeaders(h);
+
+ long length = e.getContentLengthValue();
+
+ Assert.assertEquals(-1, length);
+
+ }
+
+ @Test
+ public void testNegativeAgeHeaderValueReturnsMaxAge() {
+
+ Header[] h = new Header[] { new BasicHeader("Age", "-100") };
+ CacheEntry e = new CacheEntry();
+ e.setResponseHeaders(h);
+
+ long length = e.getAgeValue();
+
+ Assert.assertEquals(CacheEntry.MAX_AGE, length);
+
+ }
+
+ @Test
+ public void testMalformedAgeHeaderValueReturnsMaxAge() {
+
+ Header[] h = new Header[] { new BasicHeader("Age", "asdf") };
+ CacheEntry e = new CacheEntry();
+ e.setResponseHeaders(h);
+
+ long length = e.getAgeValue();
+
+ Assert.assertEquals(CacheEntry.MAX_AGE, length);
+
+ }
+
+ @Test
+ public void testMalformedCacheControlMaxAgeHeaderReturnsZero() {
+
+ Header[] h = new Header[] { new BasicHeader("Cache-Control", "max-age=asdf") };
+ CacheEntry e = new CacheEntry();
+ e.setResponseHeaders(h);
+
+ long maxage = e.getMaxAge();
+
+ Assert.assertEquals(0, maxage);
+
+ }
+
+ @Test
+ public void testMalformedExpirationDateReturnsNull() {
+ Header[] h = new Header[] { new BasicHeader("Expires", "asdf") };
+ CacheEntry e = new CacheEntry();
+ e.setResponseHeaders(h);
+
+ Date expirationDate = e.getExpirationDate();
+
+ Assert.assertNull(expirationDate);
+ }
+}
Added: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheEntryGenerator.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheEntryGenerator.java?rev=939814&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheEntryGenerator.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheEntryGenerator.java Fri Apr 30 21:00:08 2010
@@ -0,0 +1,64 @@
+/*
+ * ====================================================================
+ * 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.http.client.cache.impl;
+
+import java.io.IOException;
+import java.util.Date;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.client.cache.impl.CacheEntry;
+import org.apache.http.client.cache.impl.CacheEntryGenerator;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.message.BasicHttpResponse;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestCacheEntryGenerator {
+
+ @Test
+ public void testEntryMatchesInputs() throws IOException {
+
+ CacheEntryGenerator gen = new CacheEntryGenerator();
+
+ HttpResponse response = new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 1),
+ HttpStatus.SC_OK, "Success");
+ HttpEntity entity = new ByteArrayEntity(new byte[] {});
+ response.setEntity(entity);
+
+ response.setHeader("fooHeader", "fooHeaderValue");
+
+ CacheEntry entry = gen.generateEntry(new Date(), new Date(), response, new byte[] {});
+
+ Assert.assertEquals("HTTP", entry.getProtocolVersion().getProtocol());
+ Assert.assertEquals(1, entry.getProtocolVersion().getMajor());
+ Assert.assertEquals(1, entry.getProtocolVersion().getMinor());
+ Assert.assertEquals("fooHeaderValue", entry.getFirstHeader("fooHeader").getValue());
+ }
+}
Added: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheEntryUpdater.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheEntryUpdater.java?rev=939814&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheEntryUpdater.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheEntryUpdater.java Fri Apr 30 21:00:08 2010
@@ -0,0 +1,187 @@
+/*
+ * ====================================================================
+ * 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.http.client.cache.impl;
+
+import java.util.Date;
+
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.client.cache.impl.CacheEntry;
+import org.apache.http.client.cache.impl.CacheEntryUpdater;
+import org.apache.http.impl.cookie.DateUtils;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.message.BasicHttpResponse;
+import org.apache.http.message.BasicStatusLine;
+import org.easymock.classextension.EasyMock;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestCacheEntryUpdater {
+
+ private HttpResponse mockResponse;
+ private CacheEntry mockCacheEntry;
+ private Date requestDate;
+ private Date responseDate;
+
+ private boolean implMocked = false;
+ private CacheEntryUpdater impl;
+
+ @Before
+ public void setUp() throws Exception {
+ mockResponse = EasyMock.createMock(HttpResponse.class);
+ mockCacheEntry = EasyMock.createMock(CacheEntry.class);
+
+ requestDate = new Date(System.currentTimeMillis() - 1000);
+ responseDate = new Date();
+
+ impl = new CacheEntryUpdater();
+ }
+
+ private void replayMocks() {
+ EasyMock.replay(mockResponse);
+ EasyMock.replay(mockCacheEntry);
+ if (implMocked) {
+ EasyMock.replay(impl);
+ }
+ }
+
+ private void verifyMocks() {
+ EasyMock.verify(mockResponse);
+ EasyMock.verify(mockCacheEntry);
+ if (implMocked) {
+ EasyMock.verify(impl);
+ }
+ }
+
+ @Test
+ public void testUpdateCacheEntry() {
+ mockImplMethods("mergeHeaders");
+ mockCacheEntry.setRequestDate(requestDate);
+ mockCacheEntry.setResponseDate(responseDate);
+ impl.mergeHeaders(mockCacheEntry, mockResponse);
+
+ replayMocks();
+
+ impl.updateCacheEntry(mockCacheEntry, requestDate, responseDate, mockResponse);
+
+ verifyMocks();
+ }
+
+ @Test
+ public void testExistingHeadersNotInResponseDontChange() {
+
+ CacheEntry cacheEntry = new CacheEntry();
+ cacheEntry.setResponseHeaders(new Header[] {
+ new BasicHeader("Date", DateUtils.formatDate(responseDate)),
+ new BasicHeader("ETag", "eTag") });
+
+ HttpResponse response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion(
+ "http", 1, 1), HttpStatus.SC_NOT_MODIFIED, ""));
+ response.setHeaders(new Header[] {});
+
+ impl.mergeHeaders(cacheEntry, response);
+
+ Assert.assertEquals(2, cacheEntry.getAllHeaders().length);
+
+ headersContain(cacheEntry.getAllHeaders(), "Date", DateUtils.formatDate(responseDate));
+ headersContain(cacheEntry.getAllHeaders(), "ETag", "eTag");
+
+ }
+
+ @Test
+ public void testNewerHeadersReplaceExistingHeaders() {
+ CacheEntry cacheEntry = new CacheEntry();
+ cacheEntry.setResponseHeaders(new Header[] {
+ new BasicHeader("Date", DateUtils.formatDate(requestDate)),
+ new BasicHeader("Cache-Control", "private"), new BasicHeader("ETag", "eTag"),
+ new BasicHeader("Last-Modified", DateUtils.formatDate(requestDate)),
+ new BasicHeader("Cache-Control", "max-age=0"), });
+
+ HttpResponse response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion(
+ "http", 1, 1), HttpStatus.SC_NOT_MODIFIED, ""));
+ response.setHeaders(new Header[] {
+ new BasicHeader("Last-Modified", DateUtils.formatDate(responseDate)),
+ new BasicHeader("Cache-Control", "public"), });
+
+ impl.mergeHeaders(cacheEntry, response);
+
+ Assert.assertEquals(4, cacheEntry.getAllHeaders().length);
+
+ headersContain(cacheEntry.getAllHeaders(), "Date", DateUtils.formatDate(requestDate));
+ headersContain(cacheEntry.getAllHeaders(), "ETag", "eTag");
+ headersContain(cacheEntry.getAllHeaders(), "Last-Modified", DateUtils
+ .formatDate(responseDate));
+ headersContain(cacheEntry.getAllHeaders(), "Cache-Control", "public");
+ }
+
+ @Test
+ public void testNewHeadersAreAddedByMerge() {
+
+ CacheEntry cacheEntry = new CacheEntry();
+ cacheEntry.setResponseHeaders(new Header[] {
+ new BasicHeader("Date", DateUtils.formatDate(requestDate)),
+ new BasicHeader("ETag", "eTag"), });
+
+ HttpResponse response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion(
+ "http", 1, 1), HttpStatus.SC_NOT_MODIFIED, ""));
+ response.setHeaders(new Header[] {
+ new BasicHeader("Last-Modified", DateUtils.formatDate(responseDate)),
+ new BasicHeader("Cache-Control", "public"), });
+
+ impl.mergeHeaders(cacheEntry, response);
+
+ Assert.assertEquals(4, cacheEntry.getAllHeaders().length);
+
+ headersContain(cacheEntry.getAllHeaders(), "Date", DateUtils.formatDate(requestDate));
+ headersContain(cacheEntry.getAllHeaders(), "ETag", "eTag");
+ headersContain(cacheEntry.getAllHeaders(), "Last-Modified", DateUtils
+ .formatDate(responseDate));
+ headersContain(cacheEntry.getAllHeaders(), "Cache-Control", "public");
+
+ }
+
+ private void headersContain(Header[] headers, String name, String value) {
+ for (Header header : headers) {
+ if (header.getName().equals(name)) {
+ if (header.getValue().equals(value)) {
+ return;
+ }
+ }
+ }
+ Assert.fail("Header [" + name + ": " + value + "] not found in headers.");
+ }
+
+ private void mockImplMethods(String... methods) {
+ implMocked = true;
+ impl = EasyMock.createMockBuilder(CacheEntryUpdater.class).addMockedMethods(methods)
+ .createMock();
+ }
+
+}
Added: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheInvalidator.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheInvalidator.java?rev=939814&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheInvalidator.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheInvalidator.java Fri Apr 30 21:00:08 2010
@@ -0,0 +1,276 @@
+/*
+ * ====================================================================
+ * 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.http.client.cache.impl;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.RequestLine;
+import org.apache.http.client.cache.HttpCacheOperationException;
+import org.apache.http.client.cache.HttpCache;
+import org.apache.http.client.cache.impl.CacheEntry;
+import org.apache.http.client.cache.impl.CacheInvalidator;
+import org.apache.http.client.cache.impl.URIExtractor;
+import org.easymock.classextension.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestCacheInvalidator {
+
+ private CacheInvalidator impl;
+ private HttpCache<CacheEntry> mockCache;
+ private Header mockHeader;
+ private Header[] mockHeaderArray = new Header[1];
+ private HttpHost host;
+ private HttpRequest mockRequest;
+ private RequestLine mockRequestLine;
+ private URIExtractor mockExtractor;
+ private CacheEntry mockEntry;
+
+ private boolean mockedImpl;
+ private HeaderElement mockElement;
+ private HeaderElement[] mockElementArray = new HeaderElement[1];
+
+ @SuppressWarnings("unchecked")
+ @Before
+ public void setUp() {
+ host = new HttpHost("foo.example.com");
+ mockCache = EasyMock.createMock(HttpCache.class);
+ mockExtractor = EasyMock.createMock(URIExtractor.class);
+ mockHeader = EasyMock.createMock(Header.class);
+ mockElement = EasyMock.createMock(HeaderElement.class);
+ mockRequest = EasyMock.createMock(HttpRequest.class);
+ mockRequestLine = EasyMock.createMock(RequestLine.class);
+ mockEntry = EasyMock.createMock(CacheEntry.class);
+ mockHeaderArray[0] = mockHeader;
+ mockElementArray[0] = mockElement;
+
+ impl = new CacheInvalidator(mockExtractor, mockCache);
+ }
+
+ private void mockImplMethods(String... methods) {
+ mockedImpl = true;
+ impl = EasyMock.createMockBuilder(CacheInvalidator.class).withConstructor(mockExtractor,
+ mockCache).addMockedMethods(methods).createMock();
+ }
+
+ private void replayMocks() {
+ EasyMock.replay(mockCache);
+ EasyMock.replay(mockExtractor);
+ EasyMock.replay(mockHeader);
+ EasyMock.replay(mockRequest);
+ EasyMock.replay(mockRequestLine);
+ EasyMock.replay(mockEntry);
+ EasyMock.replay(mockElement);
+
+ if (mockedImpl)
+ EasyMock.replay(impl);
+ }
+
+ private void verifyMocks() {
+ EasyMock.verify(mockCache);
+ EasyMock.verify(mockExtractor);
+ EasyMock.verify(mockHeader);
+ EasyMock.verify(mockRequest);
+ EasyMock.verify(mockRequestLine);
+ EasyMock.verify(mockEntry);
+ EasyMock.verify(mockElement);
+
+ if (mockedImpl)
+ EasyMock.verify(impl);
+ }
+
+ // Tests
+ @Test
+ public void testInvalidatesRequestsThatArentGETorHEAD() throws Exception {
+ final String theUri = "theUri";
+ Set<String> variantURIs = new HashSet<String>();
+ cacheEntryHasVariantURIs(variantURIs);
+
+ cacheReturnsEntryForUri(theUri);
+ requestLineIsRead();
+ requestMethodIs("POST");
+ extractorReturns(theUri);
+ entryIsRemoved(theUri);
+ replayMocks();
+
+ impl.flushInvalidatedCacheEntries(host, mockRequest);
+
+ verifyMocks();
+ }
+
+ @Test
+ public void testDoesNotInvalidateGETRequest() throws HttpCacheOperationException {
+
+ requestLineIsRead();
+ requestMethodIs("GET");
+ requestContainsCacheControlHeader(null);
+ requestContainsPragmaHeader(null);
+ replayMocks();
+
+ impl.flushInvalidatedCacheEntries(host, mockRequest);
+
+ verifyMocks();
+ }
+
+ @Test
+ public void testDoesNotInvalidateHEADRequest() throws HttpCacheOperationException {
+
+ requestLineIsRead();
+ requestMethodIs("HEAD");
+ requestContainsCacheControlHeader(null);
+ requestContainsPragmaHeader(null);
+ replayMocks();
+
+ impl.flushInvalidatedCacheEntries(host, mockRequest);
+
+ verifyMocks();
+ }
+
+ @Test
+ public void testInvalidatesRequestsWithClientCacheControlHeaders() throws Exception {
+ final String theUri = "theUri";
+ extractorReturns(theUri);
+ cacheReturnsEntryForUri(theUri);
+ Set<String> variantURIs = new HashSet<String>();
+ cacheEntryHasVariantURIs(variantURIs);
+
+ requestLineIsRead();
+ requestMethodIs("GET");
+ requestContainsCacheControlHeader(mockHeaderArray);
+
+ org.easymock.EasyMock.expect(mockHeader.getElements()).andReturn(mockElementArray);
+ org.easymock.EasyMock.expect(mockElement.getName()).andReturn("no-cache").anyTimes();
+
+ entryIsRemoved(theUri);
+ replayMocks();
+
+ impl.flushInvalidatedCacheEntries(host, mockRequest);
+
+ verifyMocks();
+ }
+
+ @Test
+ public void testInvalidatesRequestsWithClientPragmaHeaders() throws Exception {
+ final String theUri = "theUri";
+ extractorReturns(theUri);
+ cacheReturnsEntryForUri(theUri);
+ Set<String> variantURIs = new HashSet<String>();
+ cacheEntryHasVariantURIs(variantURIs);
+
+ requestLineIsRead();
+ requestMethodIs("GET");
+ requestContainsCacheControlHeader(null);
+ requestContainsPragmaHeader(mockHeader);
+ entryIsRemoved(theUri);
+ replayMocks();
+
+ impl.flushInvalidatedCacheEntries(host, mockRequest);
+
+ verifyMocks();
+ }
+
+ @Test
+ public void testVariantURIsAreFlushedAlso() throws HttpCacheOperationException {
+ final String theUri = "theUri";
+ final String variantUri = "theVariantURI";
+
+ Set<String> listOfURIs = new HashSet<String>();
+ listOfURIs.add(variantUri);
+
+ extractorReturns(theUri);
+ cacheReturnsEntryForUri(theUri);
+ cacheEntryHasVariantURIs(listOfURIs);
+
+ entryIsRemoved(variantUri);
+ entryIsRemoved(theUri);
+
+ mockImplMethods("requestShouldNotBeCached");
+ org.easymock.EasyMock.expect(impl.requestShouldNotBeCached(mockRequest)).andReturn(true);
+
+ replayMocks();
+ impl.flushInvalidatedCacheEntries(host, mockRequest);
+ verifyMocks();
+ }
+
+ @Test
+ public void testCacheFlushException() throws Exception {
+ String theURI = "theURI";
+
+ mockImplMethods("requestShouldNotBeCached");
+ org.easymock.EasyMock.expect(impl.requestShouldNotBeCached(mockRequest)).andReturn(true);
+
+ extractorReturns(theURI);
+ cacheReturnsExceptionForUri(theURI);
+
+ replayMocks();
+ impl.flushInvalidatedCacheEntries(host, mockRequest);
+ verifyMocks();
+ }
+
+ // Expectations
+ private void requestContainsPragmaHeader(Header header) {
+ org.easymock.EasyMock.expect(mockRequest.getFirstHeader("Pragma")).andReturn(header);
+ }
+
+ private void requestMethodIs(String s) {
+ org.easymock.EasyMock.expect(mockRequestLine.getMethod()).andReturn(s);
+ }
+
+ private void cacheEntryHasVariantURIs(Set<String> variantURIs) {
+ org.easymock.EasyMock.expect(mockEntry.getVariantURIs()).andReturn(variantURIs);
+ }
+
+ private void cacheReturnsEntryForUri(String theUri) throws HttpCacheOperationException {
+ org.easymock.EasyMock.expect(mockCache.getEntry(theUri)).andReturn(mockEntry);
+ }
+
+ private void cacheReturnsExceptionForUri(String theUri) throws HttpCacheOperationException {
+ org.easymock.EasyMock.expect(mockCache.getEntry(theUri)).andThrow(
+ new HttpCacheOperationException("TOTAL FAIL"));
+ }
+
+ private void extractorReturns(String theUri) {
+ org.easymock.EasyMock.expect(mockExtractor.getURI(host, mockRequest)).andReturn(theUri);
+ }
+
+ private void entryIsRemoved(String theUri) throws HttpCacheOperationException {
+ mockCache.removeEntry(theUri);
+ }
+
+ private void requestLineIsRead() {
+ org.easymock.EasyMock.expect(mockRequest.getRequestLine()).andReturn(mockRequestLine);
+ }
+
+ private void requestContainsCacheControlHeader(Header[] header) {
+ org.easymock.EasyMock.expect(mockRequest.getHeaders("Cache-Control")).andReturn(header);
+ }
+}
\ No newline at end of file
Added: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheableRequestPolicy.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheableRequestPolicy.java?rev=939814&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheableRequestPolicy.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCacheableRequestPolicy.java Fri Apr 30 21:00:08 2010
@@ -0,0 +1,99 @@
+/*
+ * ====================================================================
+ * 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.http.client.cache.impl;
+
+import org.apache.http.client.cache.impl.CacheableRequestPolicy;
+import org.apache.http.message.BasicHttpRequest;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestCacheableRequestPolicy {
+
+ private CacheableRequestPolicy policy;
+
+ @Before
+ public void setUp() throws Exception {
+ policy = new CacheableRequestPolicy();
+ }
+
+ @Test
+ public void testIsGetServableFromCache() {
+ BasicHttpRequest request = new BasicHttpRequest("GET", "someUri");
+
+ Assert.assertTrue(policy.isServableFromCache(request));
+
+ }
+
+ @Test
+ public void testIsGetWithCacheControlServableFromCache() {
+ BasicHttpRequest request = new BasicHttpRequest("GET", "someUri");
+ request.addHeader("Cache-Control", "no-cache");
+
+ Assert.assertFalse(policy.isServableFromCache(request));
+
+ request = new BasicHttpRequest("GET", "someUri");
+ request.addHeader("Cache-Control", "no-store");
+ request.addHeader("Cache-Control", "max-age=20");
+
+ Assert.assertFalse(policy.isServableFromCache(request));
+
+ request = new BasicHttpRequest("GET", "someUri");
+ request.addHeader("Cache-Control", "public");
+ request.addHeader("Cache-Control", "no-store, max-age=20");
+
+ Assert.assertFalse(policy.isServableFromCache(request));
+ }
+
+ @Test
+ public void testIsGetWithPragmaServableFromCache() {
+ BasicHttpRequest request = new BasicHttpRequest("GET", "someUri");
+ request.addHeader("Pragma", "no-cache");
+
+ Assert.assertFalse(policy.isServableFromCache(request));
+
+ request = new BasicHttpRequest("GET", "someUri");
+ request.addHeader("Pragma", "value1");
+ request.addHeader("Pragma", "value2");
+
+ Assert.assertFalse(policy.isServableFromCache(request));
+ }
+
+ @Test
+ public void testIsArbitraryMethodServableFromCache() {
+
+ BasicHttpRequest request = new BasicHttpRequest("HEAD", "someUri");
+
+ Assert.assertFalse(policy.isServableFromCache(request));
+
+ request = new BasicHttpRequest("get", "someUri");
+
+ Assert.assertFalse(policy.isServableFromCache(request));
+
+ }
+
+}
Added: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCachedHttpResponseGenerator.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCachedHttpResponseGenerator.java?rev=939814&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCachedHttpResponseGenerator.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/client/cache/impl/TestCachedHttpResponseGenerator.java Fri Apr 30 21:00:08 2010
@@ -0,0 +1,192 @@
+/*
+ * ====================================================================
+ * 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.http.client.cache.impl;
+
+import java.util.Date;
+
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.client.cache.impl.CacheEntry;
+import org.apache.http.client.cache.impl.CachedHttpResponseGenerator;
+import org.apache.http.impl.cookie.DateUtils;
+import org.apache.http.message.BasicHeader;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestCachedHttpResponseGenerator {
+
+ @Test
+ public void testResponseHasContentLength() {
+
+ CacheEntry entry = new CacheEntry();
+ Header[] hdrs = new Header[] {};
+ byte[] buf = new byte[] { 1, 2, 3, 4, 5 };
+ entry.setResponseHeaders(hdrs);
+ entry.setProtocolVersion(new ProtocolVersion("HTTP", 1, 1));
+ entry.setBody(buf);
+ entry.setResponseDate(new Date());
+ entry.setRequestDate(new Date());
+
+ CachedHttpResponseGenerator gen = new CachedHttpResponseGenerator();
+ HttpResponse response = gen.generateResponse(entry);
+
+ Header length = response.getFirstHeader("Content-Length");
+ Assert.assertNotNull("Content-Length Header is missing", length);
+
+ Assert.assertEquals("Content-Length does not match buffer length", buf.length, Integer
+ .parseInt(length.getValue()));
+ }
+
+ @Test
+ public void testContentLengthIsNotAddedWhenTransferEncodingIsPresent() {
+ CacheEntry entry = new CacheEntry();
+ Header[] hdrs = new Header[] { new BasicHeader("Transfer-Encoding", "chunked") };
+ byte[] buf = new byte[] { 1, 2, 3, 4, 5 };
+ entry.setResponseHeaders(hdrs);
+ entry.setProtocolVersion(new ProtocolVersion("HTTP", 1, 1));
+ entry.setBody(buf);
+ entry.setResponseDate(new Date());
+ entry.setRequestDate(new Date());
+
+ CachedHttpResponseGenerator gen = new CachedHttpResponseGenerator();
+ HttpResponse response = gen.generateResponse(entry);
+
+ Header length = response.getFirstHeader("Content-Length");
+
+ Assert.assertNull(length);
+ }
+
+ @Test
+ public void testResponseMatchesCacheEntry() {
+ CacheEntry entry = new CacheEntry();
+ buildEntry(entry);
+
+ CachedHttpResponseGenerator gen = new CachedHttpResponseGenerator();
+ HttpResponse response = gen.generateResponse(entry);
+
+ Assert.assertTrue(response.containsHeader("Content-Length"));
+
+ Assert.assertSame("HTTP", response.getProtocolVersion().getProtocol());
+ Assert.assertSame(1, response.getProtocolVersion().getMajor());
+ Assert.assertSame(1, response.getProtocolVersion().getMinor());
+ }
+
+ @Test
+ public void testResponseStatusCodeMatchesCacheEntry() {
+ CacheEntry entry = new CacheEntry();
+ buildEntry(entry);
+
+ CachedHttpResponseGenerator gen = new CachedHttpResponseGenerator();
+ HttpResponse response = gen.generateResponse(entry);
+
+ Assert.assertEquals(entry.getStatusCode(), response.getStatusLine().getStatusCode());
+ }
+
+ @Test
+ public void testAgeHeaderIsPopulatedWithCurrentAgeOfCacheEntryIfNonZero() {
+ final long currAge = 10L;
+ CacheEntry entry = new CacheEntry() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public long getCurrentAgeSecs() {
+ return currAge;
+ }
+ };
+
+ buildEntry(entry);
+
+ CachedHttpResponseGenerator gen = new CachedHttpResponseGenerator();
+ HttpResponse response = gen.generateResponse(entry);
+
+ Header ageHdr = response.getFirstHeader("Age");
+ Assert.assertNotNull(ageHdr);
+ Assert.assertEquals(currAge, Long.parseLong(ageHdr.getValue()));
+ }
+
+ @Test
+ public void testAgeHeaderIsNotPopulatedIfCurrentAgeOfCacheEntryIsZero() {
+ final long currAge = 0L;
+ CacheEntry entry = new CacheEntry() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public long getCurrentAgeSecs() {
+ return currAge;
+ }
+ };
+ buildEntry(entry);
+
+ CachedHttpResponseGenerator gen = new CachedHttpResponseGenerator();
+ HttpResponse response = gen.generateResponse(entry);
+
+ Header ageHdr = response.getFirstHeader("Age");
+ Assert.assertNull(ageHdr);
+ }
+
+ @Test
+ public void testAgeHeaderIsPopulatedWithMaxAgeIfCurrentAgeTooBig() {
+ final long currAge = CacheEntry.MAX_AGE + 1L;
+ CacheEntry entry = new CacheEntry() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public long getCurrentAgeSecs() {
+ return currAge;
+ }
+ };
+ buildEntry(entry);
+
+ CachedHttpResponseGenerator gen = new CachedHttpResponseGenerator();
+ HttpResponse response = gen.generateResponse(entry);
+
+ Header ageHdr = response.getFirstHeader("Age");
+ Assert.assertNotNull(ageHdr);
+ Assert.assertEquals(CacheEntry.MAX_AGE, Long.parseLong(ageHdr.getValue()));
+ }
+
+ private CacheEntry buildEntry(CacheEntry entry) {
+ Date now = new Date();
+ Date sixSecondsAgo = new Date(now.getTime() - 6 * 1000L);
+ Date eightSecondsAgo = new Date(now.getTime() - 8 * 1000L);
+ Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
+ Date tenSecondsFromNow = new Date(now.getTime() + 10 * 1000L);
+ Header[] hdrs = { new BasicHeader("Date", DateUtils.formatDate(eightSecondsAgo)),
+ new BasicHeader("Expires", DateUtils.formatDate(tenSecondsFromNow)),
+ new BasicHeader("Content-Length", "150") };
+ entry.setRequestDate(tenSecondsAgo);
+ entry.setResponseDate(sixSecondsAgo);
+ entry.setBody(new byte[] {});
+ entry.setResponseHeaders(hdrs);
+
+ entry.setProtocolVersion(new ProtocolVersion("HTTP", 1, 1));
+
+ return entry;
+
+ }
+}