View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.hc.client5.http.impl.cache;
28  
29  import static org.mockito.ArgumentMatchers.isA;
30  import static org.mockito.ArgumentMatchers.same;
31  import static org.mockito.Mockito.mock;
32  import static org.mockito.Mockito.verify;
33  import static org.mockito.Mockito.when;
34  
35  import java.time.Instant;
36  import java.util.HashMap;
37  
38  import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
39  import org.apache.hc.client5.http.cache.HttpCacheEntry;
40  import org.apache.hc.core5.http.ClassicHttpRequest;
41  import org.apache.hc.core5.http.Header;
42  import org.apache.hc.core5.http.message.BasicHeader;
43  import org.apache.hc.core5.util.TimeValue;
44  import org.junit.jupiter.api.Assertions;
45  import org.junit.jupiter.api.BeforeEach;
46  import org.junit.jupiter.api.Test;
47  
48  @SuppressWarnings({"boxing","static-access"}) // test code
49  public class TestCachedHttpResponseGenerator {
50  
51      private HttpCacheEntry entry;
52      private ClassicHttpRequest request;
53      private CacheValidityPolicy mockValidityPolicy;
54      private CachedHttpResponseGenerator impl;
55  
56      @BeforeEach
57      public void setUp() {
58          entry = HttpTestUtils.makeCacheEntry(new HashMap<>());
59          request = HttpTestUtils.makeDefaultRequest();
60          mockValidityPolicy = mock(CacheValidityPolicy.class);
61          impl = new CachedHttpResponseGenerator(mockValidityPolicy);
62      }
63  
64      @Test
65      public void testResponseHasContentLength() throws Exception {
66          final byte[] buf = new byte[] { 1, 2, 3, 4, 5 };
67          final HttpCacheEntry entry1 = HttpTestUtils.makeCacheEntry(buf);
68  
69          final SimpleHttpResponse response = impl.generateResponse(request, entry1);
70  
71          final Header length = response.getFirstHeader("Content-Length");
72          Assertions.assertNotNull(length, "Content-Length Header is missing");
73  
74          Assertions.assertEquals(buf.length, Integer.parseInt(length.getValue()), "Content-Length does not match buffer length");
75      }
76  
77      @Test
78      public void testContentLengthIsNotAddedWhenTransferEncodingIsPresent() throws Exception {
79  
80          final Header[] hdrs = new Header[] { new BasicHeader("Transfer-Encoding", "chunked") };
81          final byte[] buf = new byte[] { 1, 2, 3, 4, 5 };
82          final HttpCacheEntry entry1 = HttpTestUtils.makeCacheEntry(hdrs, buf);
83  
84          final SimpleHttpResponse response = impl.generateResponse(request, entry1);
85  
86          final Header length = response.getFirstHeader("Content-Length");
87  
88          Assertions.assertNull(length);
89      }
90  
91      @Test
92      public void testResponseMatchesCacheEntry() throws Exception {
93          final SimpleHttpResponse response = impl.generateResponse(request, entry);
94  
95          Assertions.assertTrue(response.containsHeader("Content-Length"));
96  
97          Assertions.assertSame("HTTP", response.getVersion().getProtocol());
98          Assertions.assertEquals(1, response.getVersion().getMajor());
99          Assertions.assertEquals(1, response.getVersion().getMinor());
100     }
101 
102     @Test
103     public void testResponseStatusCodeMatchesCacheEntry() throws Exception {
104         final SimpleHttpResponse response = impl.generateResponse(request, entry);
105 
106         Assertions.assertEquals(entry.getStatus(), response.getCode());
107     }
108 
109     @Test
110     public void testAgeHeaderIsPopulatedWithCurrentAgeOfCacheEntryIfNonZero() throws Exception {
111         currentAge(TimeValue.ofSeconds(10L));
112 
113         final SimpleHttpResponse response = impl.generateResponse(request, entry);
114 
115         verify(mockValidityPolicy).getCurrentAge(same(entry), isA(Instant.class));
116 
117         final Header ageHdr = response.getFirstHeader("Age");
118         Assertions.assertNotNull(ageHdr);
119         Assertions.assertEquals(10L, Long.parseLong(ageHdr.getValue()));
120     }
121 
122     @Test
123     public void testAgeHeaderIsNotPopulatedIfCurrentAgeOfCacheEntryIsZero() throws Exception {
124         currentAge(TimeValue.ofSeconds(0L));
125 
126         final SimpleHttpResponse response = impl.generateResponse(request, entry);
127 
128         verify(mockValidityPolicy).getCurrentAge(same(entry), isA(Instant.class));
129 
130         final Header ageHdr = response.getFirstHeader("Age");
131         Assertions.assertNull(ageHdr);
132     }
133 
134     @Test
135     public void testAgeHeaderIsPopulatedWithMaxAgeIfCurrentAgeTooBig() throws Exception {
136         currentAge(TimeValue.ofSeconds(CacheValidityPolicy.MAX_AGE.toSeconds() + 1L));
137 
138         final SimpleHttpResponse response = impl.generateResponse(request, entry);
139 
140         verify(mockValidityPolicy).getCurrentAge(same(entry), isA(Instant.class));
141 
142         final Header ageHdr = response.getFirstHeader("Age");
143         Assertions.assertNotNull(ageHdr);
144         Assertions.assertEquals(CacheValidityPolicy.MAX_AGE.toSeconds(), Long.parseLong(ageHdr.getValue()));
145     }
146 
147     private void currentAge(final TimeValue age) {
148         when(
149                 mockValidityPolicy.getCurrentAge(same(entry),
150                         isA(Instant.class))).thenReturn(age);
151     }
152 
153     @Test
154     public void testResponseContainsEntityToServeGETRequestIfEntryContainsResource() throws Exception {
155         final SimpleHttpResponse response = impl.generateResponse(request, entry);
156 
157         Assertions.assertNotNull(response.getBody());
158     }
159 
160     @Test
161     public void testResponseDoesNotContainEntityToServeHEADRequestIfEntryContainsResource() throws Exception {
162         final ClassicHttpRequest headRequest = HttpTestUtils.makeDefaultHEADRequest();
163         final SimpleHttpResponse response = impl.generateResponse(headRequest, entry);
164 
165         Assertions.assertNull(response.getBody());
166     }
167 
168 }