-
-
Notifications
You must be signed in to change notification settings - Fork 934
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add cache
option
#284
Add cache
option
#284
Changes from 48 commits
43023d5
49b6f00
2811293
0f6f944
0d6180a
011ea0e
5ec945f
817de11
b3201ea
b65128e
b0490ca
903fbfa
b8b3411
39811aa
e4ae2c6
f64dcc7
a31c966
4e98913
f2026dc
b3f23ea
7d4365e
70d57d7
838821d
dbb7f20
d4cf24c
159c399
23d76e3
bd99d4d
be4c431
58ffa2b
6212f16
75a9995
f6f915b
8ee8a4a
4e3a3dc
b6b3401
f56c508
07a403c
b63a641
459cbbf
a67f157
1843cba
c2c920f
e328719
0ef2c4f
81e5b98
8f4b02b
7148409
6814128
dbf96c6
b0c6fa8
4355e59
cf95ab9
d45ac92
8bf25ab
f00749a
be12b61
2616d53
13a9e1b
ad9403a
44a51c9
eef529e
a36ab21
56bf35f
f6541ed
ac48967
b7fc611
2b7176a
f182b5c
b0d5704
dfd072b
8893e2c
fe116bc
7f63136
a3dd216
ff7c57d
4d9ab59
0a75785
f249038
c27f7f5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
import test from 'ava'; | ||
import getStream from 'get-stream'; | ||
import got from '../'; | ||
import {createServer} from './helpers/server'; | ||
|
||
let s; | ||
|
||
test.before('setup', async () => { | ||
s = await createServer(); | ||
|
||
let noStoreIndex = 0; | ||
s.on('/no-store', (req, res) => { | ||
noStoreIndex++; | ||
res.setHeader('Cache-Control', 'public, no-cache, no-store'); | ||
res.end(noStoreIndex.toString()); | ||
}); | ||
|
||
let cacheIndex = 0; | ||
s.on('/cache', (req, res) => { | ||
cacheIndex++; | ||
res.setHeader('Cache-Control', 'public, max-age=60'); | ||
res.end(cacheIndex.toString()); | ||
}); | ||
|
||
s.on('/last-modified', (req, res) => { | ||
res.setHeader('Cache-Control', 'public, max-age=0'); | ||
res.setHeader('Last-Modified', 'Wed, 21 Oct 2015 07:28:00 GMT'); | ||
let responseBody = 'last-modified'; | ||
|
||
if (req.headers['if-modified-since'] === 'Wed, 21 Oct 2015 07:28:00 GMT') { | ||
res.statusCode = 304; | ||
responseBody = null; | ||
} | ||
|
||
res.end(responseBody); | ||
}); | ||
|
||
s.on('/etag', (req, res) => { | ||
res.setHeader('Cache-Control', 'public, max-age=0'); | ||
res.setHeader('ETag', '33a64df551425fcc55e4d42a148795d9f25f89d4'); | ||
let responseBody = 'etag'; | ||
|
||
if (req.headers['if-none-match'] === '33a64df551425fcc55e4d42a148795d9f25f89d4') { | ||
res.statusCode = 304; | ||
responseBody = null; | ||
} | ||
|
||
res.end(responseBody); | ||
}); | ||
|
||
let cacheThenNoStoreIndex = 0; | ||
s.on('/cache-then-no-store-on-revalidate', (req, res) => { | ||
const cc = cacheThenNoStoreIndex === 0 ? 'public, max-age=0' : 'public, no-cache, no-store'; | ||
cacheThenNoStoreIndex++; | ||
res.setHeader('Cache-Control', cc); | ||
res.end('cache-then-no-store-on-revalidate'); | ||
}); | ||
|
||
await s.listen(s.port); | ||
}); | ||
|
||
test('Non cacheable responses are not cached', async t => { | ||
const endpoint = '/no-store'; | ||
const cache = new Map(); | ||
|
||
const firstResponseInt = parseInt((await got(s.url + endpoint, {cache})).body, 10); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think xo had a rule favoring |
||
const secondResponseInt = parseInt((await got(s.url + endpoint, {cache})).body, 10); | ||
|
||
t.is(cache.size, 0); | ||
t.true(firstResponseInt < secondResponseInt); | ||
}); | ||
|
||
test('Cacheable responses are cached', async t => { | ||
const endpoint = '/cache'; | ||
const cache = new Map(); | ||
|
||
const firstResponse = await got(s.url + endpoint, {cache}); | ||
const secondResponse = await got(s.url + endpoint, {cache}); | ||
|
||
t.is(cache.size, 1); | ||
t.is(firstResponse.body, secondResponse.body); | ||
}); | ||
|
||
test('Stream responses are cached', async t => { | ||
const endpoint = '/cache'; | ||
const cache = new Map(); | ||
|
||
const firstResponseBody = await getStream(got.stream(s.url + endpoint, {cache})); | ||
const secondResponseBody = await getStream(got.stream(s.url + endpoint, {cache})); | ||
|
||
t.is(cache.size, 1); | ||
t.is(firstResponseBody, secondResponseBody); | ||
}); | ||
|
||
test('Binary responses are cached', async t => { | ||
const endpoint = '/cache'; | ||
const cache = new Map(); | ||
const encoding = null; | ||
|
||
const firstResponse = await got(s.url + endpoint, {cache, encoding}); | ||
const secondResponse = await got(s.url + endpoint, {cache, encoding}); | ||
|
||
t.is(cache.size, 1); | ||
t.true(firstResponse.body instanceof Buffer); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. => |
||
t.is(firstResponse.body.toString(), secondResponse.body.toString()); | ||
}); | ||
|
||
test('TTL is passed to cache', async t => { | ||
const endpoint = '/cache'; | ||
const store = new Map(); | ||
const cache = { | ||
get: store.get.bind(store), | ||
set: (key, val, ttl) => { | ||
t.true(typeof ttl === 'number'); | ||
t.true(ttl > 0); | ||
return store.set(key, val, ttl); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since const cache = {
get: () => {},
delete: () => {},
set: (key, val, ttl) => {
// your set() code
}
}; |
||
}, | ||
delete: store.delete.bind(store) | ||
}; | ||
|
||
t.plan(2); | ||
|
||
await got(s.url + endpoint, {cache}); | ||
}); | ||
|
||
test('Cached response is re-encoded to current encoding option', async t => { | ||
const endpoint = '/cache'; | ||
const cache = new Map(); | ||
const firstEncoding = 'base64'; | ||
const secondEncoding = 'hex'; | ||
|
||
const firstResponse = await got(s.url + endpoint, {cache, encoding: firstEncoding}); | ||
const secondResponse = await got(s.url + endpoint, {cache, encoding: secondEncoding}); | ||
|
||
const expectedSecondResponseBody = Buffer.from(firstResponse.body, firstEncoding).toString(secondEncoding); | ||
|
||
t.is(cache.size, 1); | ||
t.is(secondResponse.body, expectedSecondResponseBody); | ||
}); | ||
|
||
test('Stale cache entries with Last-Modified headers are revalidated', async t => { | ||
const endpoint = '/last-modified'; | ||
const cache = new Map(); | ||
|
||
const firstResponse = await got(s.url + endpoint, {cache}); | ||
const secondResponse = await got(s.url + endpoint, {cache}); | ||
|
||
t.is(cache.size, 1); | ||
t.is(firstResponse.statusCode, 200); | ||
t.is(secondResponse.statusCode, 304); | ||
t.is(firstResponse.body, 'last-modified'); | ||
t.is(firstResponse.body, secondResponse.body); | ||
}); | ||
|
||
test('Stale cache entries with ETag headers are revalidated', async t => { | ||
const endpoint = '/etag'; | ||
const cache = new Map(); | ||
|
||
const firstResponse = await got(s.url + endpoint, {cache}); | ||
const secondResponse = await got(s.url + endpoint, {cache}); | ||
|
||
t.is(cache.size, 1); | ||
t.is(firstResponse.statusCode, 200); | ||
t.is(secondResponse.statusCode, 304); | ||
t.is(firstResponse.body, 'etag'); | ||
t.is(firstResponse.body, secondResponse.body); | ||
}); | ||
|
||
test('Stale cache entries that can\'t be revalidate are deleted from cache', async t => { | ||
const endpoint = '/cache-then-no-store-on-revalidate'; | ||
const cache = new Map(); | ||
|
||
const firstResponse = await got(s.url + endpoint, {cache}); | ||
t.is(cache.size, 1); | ||
const secondResponse = await got(s.url + endpoint, {cache, log: true}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add a newline above too? |
||
|
||
t.is(cache.size, 0); | ||
t.is(firstResponse.statusCode, 200); | ||
t.is(secondResponse.statusCode, 200); | ||
t.is(firstResponse.body, 'cache-then-no-store-on-revalidate'); | ||
t.is(firstResponse.body, secondResponse.body); | ||
}); | ||
|
||
test('Response objects have fromCache property set correctly', async t => { | ||
const endpoint = '/cache'; | ||
const cache = new Map(); | ||
|
||
const response = await got(s.url + endpoint, {cache}); | ||
const cachedResponse = await got(s.url + endpoint, {cache}); | ||
|
||
t.false(response.fromCache); | ||
t.true(cachedResponse.fromCache); | ||
}); | ||
|
||
test.after('cleanup', async () => { | ||
await s.close(); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rename this to
cacheControl
.