Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
18084 manas 1
/*
2
 * Copyright (C) 2011 The Android Open Source Project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
 
17
package com.android.volley.toolbox;
18
 
19
import com.android.volley.Cache;
20
import com.android.volley.NetworkResponse;
21
 
22
import org.apache.http.Header;
23
import org.apache.http.message.BasicHeader;
24
import org.junit.Before;
25
import org.junit.Test;
26
import org.junit.runner.RunWith;
27
import org.robolectric.RobolectricTestRunner;
28
 
29
import java.text.DateFormat;
30
import java.text.SimpleDateFormat;
31
import java.util.Date;
32
import java.util.HashMap;
33
import java.util.Locale;
34
import java.util.Map;
35
 
36
import static org.junit.Assert.*;
37
 
38
@RunWith(RobolectricTestRunner.class)
39
public class HttpHeaderParserTest {
40
 
41
    private static long ONE_MINUTE_MILLIS = 1000L * 60;
42
    private static long ONE_HOUR_MILLIS = 1000L * 60 * 60;
43
    private static long ONE_DAY_MILLIS = ONE_HOUR_MILLIS * 24;
44
    private static long ONE_WEEK_MILLIS = ONE_DAY_MILLIS * 7;
45
 
46
    private NetworkResponse response;
47
    private Map<String, String> headers;
48
 
49
    @Before public void setUp() throws Exception {
50
        headers = new HashMap<String, String>();
51
        response = new NetworkResponse(0, null, headers, false);
52
    }
53
 
54
    @Test public void parseCacheHeaders_noHeaders() {
55
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
56
 
57
        assertNotNull(entry);
58
        assertNull(entry.etag);
59
        assertEquals(0, entry.serverDate);
60
        assertEquals(0, entry.lastModified);
61
        assertEquals(0, entry.ttl);
62
        assertEquals(0, entry.softTtl);
63
    }
64
 
65
    @Test public void parseCacheHeaders_headersSet() {
66
        headers.put("MyCustomHeader", "42");
67
 
68
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
69
 
70
        assertNotNull(entry);
71
        assertNotNull(entry.responseHeaders);
72
        assertEquals(1, entry.responseHeaders.size());
73
        assertEquals("42", entry.responseHeaders.get("MyCustomHeader"));
74
    }
75
 
76
    @Test public void parseCacheHeaders_etag() {
77
        headers.put("ETag", "Yow!");
78
 
79
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
80
 
81
        assertNotNull(entry);
82
        assertEquals("Yow!", entry.etag);
83
    }
84
 
85
    @Test public void parseCacheHeaders_normalExpire() {
86
        long now = System.currentTimeMillis();
87
        headers.put("Date", rfc1123Date(now));
88
        headers.put("Last-Modified", rfc1123Date(now - ONE_DAY_MILLIS));
89
        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
90
 
91
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
92
 
93
        assertNotNull(entry);
94
        assertNull(entry.etag);
95
        assertEqualsWithin(entry.serverDate, now, ONE_MINUTE_MILLIS);
96
        assertEqualsWithin(entry.lastModified, (now - ONE_DAY_MILLIS), ONE_MINUTE_MILLIS);
97
        assertTrue(entry.softTtl >= (now + ONE_HOUR_MILLIS));
98
        assertTrue(entry.ttl == entry.softTtl);
99
    }
100
 
101
    @Test public void parseCacheHeaders_expiresInPast() {
102
        long now = System.currentTimeMillis();
103
        headers.put("Date", rfc1123Date(now));
104
        headers.put("Expires", rfc1123Date(now - ONE_HOUR_MILLIS));
105
 
106
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
107
 
108
        assertNotNull(entry);
109
        assertNull(entry.etag);
110
        assertEqualsWithin(entry.serverDate, now, ONE_MINUTE_MILLIS);
111
        assertEquals(0, entry.ttl);
112
        assertEquals(0, entry.softTtl);
113
    }
114
 
115
    @Test public void parseCacheHeaders_serverRelative() {
116
 
117
        long now = System.currentTimeMillis();
118
        // Set "current" date as one hour in the future
119
        headers.put("Date", rfc1123Date(now + ONE_HOUR_MILLIS));
120
        // TTL four hours in the future, so should be three hours from now
121
        headers.put("Expires", rfc1123Date(now + 4 * ONE_HOUR_MILLIS));
122
 
123
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
124
 
125
        assertEqualsWithin(now + 3 * ONE_HOUR_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
126
        assertEquals(entry.softTtl, entry.ttl);
127
    }
128
 
129
    @Test public void parseCacheHeaders_cacheControlOverridesExpires() {
130
        long now = System.currentTimeMillis();
131
        headers.put("Date", rfc1123Date(now));
132
        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
133
        headers.put("Cache-Control", "public, max-age=86400");
134
 
135
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
136
 
137
        assertNotNull(entry);
138
        assertNull(entry.etag);
139
        assertEqualsWithin(now + ONE_DAY_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
140
        assertEquals(entry.softTtl, entry.ttl);
141
    }
142
 
143
    @Test public void testParseCacheHeaders_staleWhileRevalidate() {
144
        long now = System.currentTimeMillis();
145
        headers.put("Date", rfc1123Date(now));
146
        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
147
 
148
        // - max-age (entry.softTtl) indicates that the asset is fresh for 1 day
149
        // - stale-while-revalidate (entry.ttl) indicates that the asset may
150
        // continue to be served stale for up to additional 7 days
151
        headers.put("Cache-Control", "max-age=86400, stale-while-revalidate=604800");
152
 
153
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
154
 
155
        assertNotNull(entry);
156
        assertNull(entry.etag);
157
        assertEqualsWithin(now + ONE_DAY_MILLIS, entry.softTtl, ONE_MINUTE_MILLIS);
158
        assertEqualsWithin(now + ONE_DAY_MILLIS + ONE_WEEK_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
159
    }
160
 
161
    @Test public void parseCacheHeaders_cacheControlNoCache() {
162
        long now = System.currentTimeMillis();
163
        headers.put("Date", rfc1123Date(now));
164
        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
165
        headers.put("Cache-Control", "no-cache");
166
 
167
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
168
 
169
        assertNull(entry);
170
    }
171
 
172
    @Test public void parseCacheHeaders_cacheControlMustRevalidateNoMaxAge() {
173
        long now = System.currentTimeMillis();
174
        headers.put("Date", rfc1123Date(now));
175
        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
176
        headers.put("Cache-Control", "must-revalidate");
177
 
178
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
179
        assertNotNull(entry);
180
        assertNull(entry.etag);
181
        assertEqualsWithin(now, entry.ttl, ONE_MINUTE_MILLIS);
182
        assertEquals(entry.softTtl, entry.ttl);
183
    }
184
 
185
    @Test public void parseCacheHeaders_cacheControlMustRevalidateWithMaxAge() {
186
        long now = System.currentTimeMillis();
187
        headers.put("Date", rfc1123Date(now));
188
        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
189
        headers.put("Cache-Control", "must-revalidate, max-age=3600");
190
 
191
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
192
        assertNotNull(entry);
193
        assertNull(entry.etag);
194
        assertEqualsWithin(now + ONE_HOUR_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
195
        assertEquals(entry.softTtl, entry.ttl);
196
    }
197
 
198
    @Test public void parseCacheHeaders_cacheControlMustRevalidateWithMaxAgeAndStale() {
199
        long now = System.currentTimeMillis();
200
        headers.put("Date", rfc1123Date(now));
201
        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
202
 
203
        // - max-age (entry.softTtl) indicates that the asset is fresh for 1 day
204
        // - stale-while-revalidate (entry.ttl) indicates that the asset may
205
        // continue to be served stale for up to additional 7 days, but this is
206
        // ignored in this case because of the must-revalidate header.
207
        headers.put("Cache-Control",
208
                "must-revalidate, max-age=86400, stale-while-revalidate=604800");
209
 
210
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
211
        assertNotNull(entry);
212
        assertNull(entry.etag);
213
        assertEqualsWithin(now + ONE_DAY_MILLIS, entry.softTtl, ONE_MINUTE_MILLIS);
214
        assertEquals(entry.softTtl, entry.ttl);
215
    }
216
 
217
    private void assertEqualsWithin(long expected, long value, long fudgeFactor) {
218
        long diff = Math.abs(expected - value);
219
        assertTrue(diff < fudgeFactor);
220
    }
221
 
222
    private static String rfc1123Date(long millis) {
223
        DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH);
224
        return df.format(new Date(millis));
225
    }
226
 
227
    // --------------------------
228
 
229
    @Test public void parseCharset() {
230
        // Like the ones we usually see
231
        headers.put("Content-Type", "text/plain; charset=utf-8");
232
        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers));
233
 
234
        // Charset specified, ignore default charset
235
        headers.put("Content-Type", "text/plain; charset=utf-8");
236
        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers, "ISO-8859-1"));
237
 
238
        // Extra whitespace
239
        headers.put("Content-Type", "text/plain;    charset=utf-8 ");
240
        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers));
241
 
242
        // Extra parameters
243
        headers.put("Content-Type", "text/plain; charset=utf-8; frozzle=bar");
244
        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers));
245
 
246
        // No Content-Type header
247
        headers.clear();
248
        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
249
 
250
        // No Content-Type header, use default charset
251
        headers.clear();
252
        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers, "utf-8"));
253
 
254
        // Empty value
255
        headers.put("Content-Type", "text/plain; charset=");
256
        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
257
 
258
        // None specified
259
        headers.put("Content-Type", "text/plain");
260
        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
261
 
262
        // None charset specified, use default charset
263
        headers.put("Content-Type", "application/json");
264
        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers, "utf-8"));
265
 
266
        // None specified, extra semicolon
267
        headers.put("Content-Type", "text/plain;");
268
        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
269
    }
270
 
271
    @Test public void parseCaseInsensitive() {
272
 
273
        long now = System.currentTimeMillis();
274
 
275
        Header[] headersArray = new Header[5];
276
        headersArray[0] = new BasicHeader("eTAG", "Yow!");
277
        headersArray[1] = new BasicHeader("DATE", rfc1123Date(now));
278
        headersArray[2] = new BasicHeader("expires", rfc1123Date(now + ONE_HOUR_MILLIS));
279
        headersArray[3] = new BasicHeader("cache-control", "public, max-age=86400");
280
        headersArray[4] = new BasicHeader("content-type", "text/plain");
281
 
282
        Map<String, String> headers = BasicNetwork.convertHeaders(headersArray);
283
        NetworkResponse response = new NetworkResponse(0, null, headers, false);
284
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
285
 
286
        assertNotNull(entry);
287
        assertEquals("Yow!", entry.etag);
288
        assertEqualsWithin(now + ONE_DAY_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
289
        assertEquals(entry.softTtl, entry.ttl);
290
        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
291
    }
292
}