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.http.impl.client.cache.ehcache;
28  
29  import static org.mockito.Matchers.isA;
30  import static org.mockito.Matchers.same;
31  import static org.mockito.Mockito.mock;
32  import static org.mockito.Mockito.times;
33  import static org.mockito.Mockito.verify;
34  import static org.mockito.Mockito.when;
35  
36  import java.io.IOException;
37  import java.io.InputStream;
38  import java.io.OutputStream;
39  
40  import junit.framework.TestCase;
41  import net.sf.ehcache.Ehcache;
42  import net.sf.ehcache.Element;
43  
44  import org.apache.http.client.cache.HttpCacheEntry;
45  import org.apache.http.client.cache.HttpCacheEntrySerializer;
46  import org.apache.http.client.cache.HttpCacheUpdateCallback;
47  import org.apache.http.client.cache.HttpCacheUpdateException;
48  import org.apache.http.impl.client.cache.CacheConfig;
49  import org.apache.http.impl.client.cache.HttpTestUtils;
50  import org.junit.Test;
51  
52  @SuppressWarnings("boxing") // test code
53  public class TestEhcacheHttpCacheStorage extends TestCase {
54  
55      private Ehcache mockCache;
56      private EhcacheHttpCacheStorage impl;
57      private HttpCacheEntrySerializer mockSerializer;
58  
59      @Override
60      public void setUp() {
61          mockCache = mock(Ehcache.class);
62          final CacheConfig config = CacheConfig.custom().setMaxUpdateRetries(1).build();
63          mockSerializer = mock(HttpCacheEntrySerializer.class);
64          impl = new EhcacheHttpCacheStorage(mockCache, config, mockSerializer);
65      }
66  
67      @Test
68      public void testCachePut() throws IOException {
69          final String key = "foo";
70          final HttpCacheEntry value = HttpTestUtils.makeCacheEntry();
71  
72          final Element e = new Element(key, new byte[]{});
73  
74          impl.putEntry(key, value);
75  
76          verify(mockSerializer).writeTo(same(value), isA(OutputStream.class));
77          verify(mockCache).put(e);;
78      }
79  
80      @Test
81      public void testCacheGetNullEntry() throws IOException {
82          final String key = "foo";
83  
84          when(mockCache.get(key)).thenReturn(null);
85  
86          final HttpCacheEntry resultingEntry = impl.getEntry(key);
87  
88          verify(mockCache).get(key);
89  
90          assertNull(resultingEntry);
91      }
92  
93      @Test
94      public void testCacheGet() throws IOException {
95          final String key = "foo";
96          final HttpCacheEntry cachedValue = HttpTestUtils.makeCacheEntry();
97  
98          final Element element = new Element(key, new byte[]{});
99  
100         when(mockCache.get(key))
101                 .thenReturn(element);
102         when(mockSerializer.readFrom(isA(InputStream.class)))
103                 .thenReturn(cachedValue);
104 
105         final HttpCacheEntry resultingEntry = impl.getEntry(key);
106 
107         verify(mockCache).get(key);
108         verify(mockSerializer).readFrom(isA(InputStream.class));
109 
110         assertSame(cachedValue, resultingEntry);
111     }
112 
113     @Test
114     public void testCacheRemove() {
115         final String key = "foo";
116 
117         when(mockCache.remove(key)).thenReturn(true);
118 
119         impl.removeEntry(key);
120         verify(mockCache).remove(key);
121     }
122 
123     @Test
124     public void testCacheUpdateNullEntry() throws IOException, HttpCacheUpdateException {
125         final String key = "foo";
126         final HttpCacheEntry updatedValue = HttpTestUtils.makeCacheEntry();
127 
128         final Element element = new Element(key, new byte[]{});
129 
130         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback(){
131             @Override
132             public HttpCacheEntry update(final HttpCacheEntry old){
133                 assertNull(old);
134                 return updatedValue;
135             }
136         };
137 
138         // get empty old entry
139         when(mockCache.get(key)).thenReturn(null);
140 
141         // put new entry
142         mockSerializer.writeTo(same(updatedValue), isA(OutputStream.class));
143 
144         impl.updateEntry(key, callback);
145 
146         verify(mockCache).get(key);
147         verify(mockSerializer).writeTo(same(updatedValue), isA(OutputStream.class));
148         verify(mockCache).put(element);
149     }
150 
151     @Test
152     public void testCacheUpdate() throws IOException, HttpCacheUpdateException {
153         final String key = "foo";
154         final HttpCacheEntry existingValue = HttpTestUtils.makeCacheEntry();
155         final HttpCacheEntry updatedValue = HttpTestUtils.makeCacheEntry();
156 
157         final Element existingElement = new Element(key, new byte[]{});
158 
159         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback(){
160             @Override
161             public HttpCacheEntry update(final HttpCacheEntry old){
162                 assertEquals(existingValue, old);
163                 return updatedValue;
164             }
165         };
166 
167         // get existing old entry
168         when(mockCache.get(key)).thenReturn(existingElement);
169         when(mockSerializer.readFrom(isA(InputStream.class))).thenReturn(existingValue);
170 
171         // update
172         mockSerializer.writeTo(same(updatedValue), isA(OutputStream.class));
173         when(mockCache.replace(same(existingElement), isA(Element.class))).thenReturn(true);
174 
175         impl.updateEntry(key, callback);
176 
177         verify(mockCache).get(key);
178         verify(mockSerializer).readFrom(isA(InputStream.class));
179         verify(mockSerializer).writeTo(same(updatedValue), isA(OutputStream.class));
180         verify(mockCache).replace(same(existingElement), isA(Element.class));
181     }
182 
183     @Test
184     public void testSingleCacheUpdateRetry() throws IOException, HttpCacheUpdateException {
185         final String key = "foo";
186         final HttpCacheEntry existingValue = HttpTestUtils.makeCacheEntry();
187         final HttpCacheEntry updatedValue = HttpTestUtils.makeCacheEntry();
188 
189         final Element existingElement = new Element(key, new byte[]{});
190 
191         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback(){
192             @Override
193             public HttpCacheEntry update(final HttpCacheEntry old){
194                 assertEquals(existingValue, old);
195                 return updatedValue;
196             }
197         };
198 
199         // get existing old entry, will happen twice
200         when(mockCache.get(key)).thenReturn(existingElement);
201         when(mockSerializer.readFrom(isA(InputStream.class))).thenReturn(existingValue);
202 
203         // Fail first and then succeed
204         when(mockCache.replace(same(existingElement), isA(Element.class))).thenReturn(false).thenReturn(true);
205 
206         impl.updateEntry(key, callback);
207 
208         verify(mockCache, times(2)).get(key);
209         verify(mockSerializer, times(2)).readFrom(isA(InputStream.class));
210         verify(mockSerializer, times(2)).writeTo(same(updatedValue), isA(OutputStream.class));
211         verify(mockCache, times(2)).replace(same(existingElement), isA(Element.class));
212     }
213 
214     @Test
215     public void testCacheUpdateFail() throws IOException {
216         final String key = "foo";
217         final HttpCacheEntry existingValue = HttpTestUtils.makeCacheEntry();
218         final HttpCacheEntry updatedValue = HttpTestUtils.makeCacheEntry();
219 
220         final Element existingElement = new Element(key, new byte[]{});
221 
222         final HttpCacheUpdateCallback callback = new HttpCacheUpdateCallback(){
223             @Override
224             public HttpCacheEntry update(final HttpCacheEntry old){
225                 assertEquals(existingValue, old);
226                 return updatedValue;
227             }
228         };
229 
230         // get existing old entry
231         when(mockCache.get(key)).thenReturn(existingElement);
232         when(mockSerializer.readFrom(isA(InputStream.class))).thenReturn(existingValue);
233 
234         // update but fail
235         when(mockCache.replace(same(existingElement), isA(Element.class))).thenReturn(false);
236 
237         try{
238             impl.updateEntry(key, callback);
239             fail("Expected HttpCacheUpdateException");
240         } catch (final HttpCacheUpdateException e) { }
241 
242         verify(mockCache, times(2)).get(key);
243         verify(mockSerializer, times(2)).readFrom(isA(InputStream.class));
244         verify(mockSerializer, times(2)).writeTo(same(updatedValue), isA(OutputStream.class));
245         verify(mockCache, times(2)).replace(same(existingElement), isA(Element.class));
246     }
247 }