Skip to content

Commit

Permalink
modifying restify PR to work with Buffers
Browse files Browse the repository at this point in the history
  • Loading branch information
Kevin Whitley committed Jan 11, 2017
1 parent aaaf37d commit 902a154
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 79 deletions.
44 changes: 31 additions & 13 deletions src/apicache.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ function ApiCache() {
}

function cacheResponse(key, value, duration) {
console.log('caching response', key, value)
var redis = globalOptions.redisClient
if (redis) {
redis.hset(key, "response", JSON.stringify(value))
Expand All @@ -102,28 +103,40 @@ function ApiCache() {

function accumulateContent(res, content) {
if (content) {
if (typeof(content) == "string") {
res._apicache.content=(res._apicache.content || "") + content;
}
else {
res._apicache.cacheable=false;
if (typeof(content) == 'string') {
res._apicache.content = (res._apicache.content || '') + content;
} else {
res._apicache.content = content
// res._apicache.cacheable = false;
}
}
}

function makeResponseCacheable(req, res, next, key, duration, strDuration) {
// monkeypatch res.end to create cache object
res._apicache={write:res.write,end:res.end,cacheable:true}
res._apicache = {
write: res.write,
end: res.end,
cacheable: true,
content: undefined
}

res.header('cache-control','max-age=' + (duration / 1000).toFixed(0))
// add cache control headers
res.header('cache-control', 'max-age=' + (duration / 1000).toFixed(0))

// patch res.write
res.write = function(content) {
accumulateContent(res,content);
return res._apicache.write.apply(this,arguments);
// console.log('patched write', content)
accumulateContent(res, content);
return res._apicache.write.apply(this, arguments);
}
res.end = function(content,encoding) {

// patch res.end
res.end = function(content, encoding) {
// console.log('patched end', content, encoding)
if (shouldCacheResponse(res)) {

accumulateContent(res,content);
accumulateContent(res, content);

if (res._apicache.cacheable && res._apicache.content) {
addIndexEntries(key, req)
Expand All @@ -136,7 +149,7 @@ function ApiCache() {
}
}

return res._apicache.end.apply(this,arguments);
return res._apicache.end.apply(this, arguments);
}

next()
Expand All @@ -149,6 +162,8 @@ function ApiCache() {
'apicache-version': pkg.version
})

console.log('building response from', cacheObject)

// unstringify buffers
var data = cacheObject.data
if (data && data.type === 'Buffer') {
Expand Down Expand Up @@ -286,12 +301,15 @@ function ApiCache() {

// if not forced bypass of cache from client request, attempt cache hit
if (!req.headers['x-apicache-force-fetch']) {
console.log('attempting key hits for', key)
// console.log('current cache:', memCache.cache)
// attempt cache hit
var redis = globalOptions.redisClient
var cached = !redis ? memCache.getValue(key) : null

// send if cache hit from memory-cache
if (cached) {
console.log('cache hit in memory for', key)
// console log
var elapsed = new Date() - req.apicacheTimer
debug('sending cached (memory-cache) version of', key, logDuration(elapsed))
Expand All @@ -313,7 +331,7 @@ function ApiCache() {
}
})
} else {
makeResponseCacheable(req, res, next, key, duration, strDuration)
return makeResponseCacheable(req, res, next, key, duration, strDuration)
}
}
}
Expand Down
154 changes: 88 additions & 66 deletions test/apicache_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,72 +114,6 @@ describe('.resetIndex() {SETTER}', function() {

})

describe('.clear(key?) {SETTER}', function() {
var apicache = require('../src/apicache.js')

it('is a function', function() {
expect(typeof apicache.clear).to.equal('function')
})

it('works when called with group key', function(done) {
var mockAPI = require('./mock_api')('10 seconds')

request(mockAPI)
.get('/api/testcachegroup')
.end(function(err, res) {
expect(mockAPI.requestsProcessed).to.equal(1)
expect(mockAPI.apicache.getIndex().all.length).to.equal(1)
expect(mockAPI.apicache.getIndex().groups.cachegroup.length).to.equal(1)
expect(Object.keys(mockAPI.apicache.clear('cachegroup').groups).length).to.equal(0)
expect(mockAPI.apicache.getIndex().all.length).to.equal(0)
done()
})
})

it('works when called with specific endpoint (non-group) key', function(done) {
var mockAPI = require('./mock_api')('10 seconds')

request(mockAPI)
.get('/api/movies')
.end(function(err, res) {
expect(mockAPI.requestsProcessed).to.equal(1)
expect(mockAPI.apicache.getIndex().all.length).to.equal(1)
expect(mockAPI.apicache.clear('/api/movies').all.length).to.equal(0)
done()
})
})

it('clears empty group after removing last specific endpoint', function(done) {
var mockAPI = require('./mock_api')('10 seconds')

request(mockAPI)
.get('/api/testcachegroup')
.end(function(err, res) {
expect(mockAPI.requestsProcessed).to.equal(1)
expect(mockAPI.apicache.getIndex().all.length).to.equal(1)
expect(mockAPI.apicache.getIndex().groups.cachegroup.length).to.equal(1)
expect(Object.keys(mockAPI.apicache.clear('/api/testcachegroup').groups).length).to.equal(0)
expect(mockAPI.apicache.getIndex().all.length).to.equal(0)
done()
})
})

it('works when called with no key', function(done) {
var mockAPI = require('./mock_api')('10 seconds')

expect(mockAPI.apicache.getIndex().all.length).to.equal(0)
expect(mockAPI.apicache.clear().all.length).to.equal(0)
request(mockAPI)
.get('/api/movies')
.end(function(err, res) {
expect(mockAPI.requestsProcessed).to.equal(1)
expect(mockAPI.apicache.getIndex().all.length).to.equal(1)
expect(mockAPI.apicache.clear().all.length).to.equal(0)
done()
})
})
})

describe('.middleware {MIDDLEWARE}', function() {
var apicache = require('../src/apicache.js')

Expand Down Expand Up @@ -236,6 +170,28 @@ describe('.middleware {MIDDLEWARE}', function() {
})
})

it('returns cached response from write+end', function(done) {
var mockAPI = require('./mock_api')('10 seconds')

request(mockAPI)
.get('/api/writeandend')
.end(function(err, res1, body) {
expect(res1.status).to.equal(200)
expect(res1.text).to.equal('abc')
expect(mockAPI.requestsProcessed).to.equal(1)

request(mockAPI)
.get('/api/writeandend')
.end(function(err, res2) {
expect(res2.status).to.equal(200)
expect(res2.text).to.equal('abc')

expect(mockAPI.requestsProcessed).to.equal(1)
done()
})
})
})

it('embeds store type and apicache version in cached responses', function(done) {
var mockAPI = require('./mock_api')('10 seconds')

Expand Down Expand Up @@ -453,3 +409,69 @@ describe('Redis support', function() {
})
})
})

describe('.clear(key?) {SETTER}', function() {
var apicache = require('../src/apicache.js')

it('is a function', function() {
expect(typeof apicache.clear).to.equal('function')
})

it('works when called with group key', function(done) {
var mockAPI = require('./mock_api')('10 seconds')

request(mockAPI)
.get('/api/testcachegroup')
.end(function(err, res) {
expect(mockAPI.requestsProcessed).to.equal(1)
expect(mockAPI.apicache.getIndex().all.length).to.equal(1)
expect(mockAPI.apicache.getIndex().groups.cachegroup.length).to.equal(1)
expect(Object.keys(mockAPI.apicache.clear('cachegroup').groups).length).to.equal(0)
expect(mockAPI.apicache.getIndex().all.length).to.equal(0)
done()
})
})

it('works when called with specific endpoint (non-group) key', function(done) {
var mockAPI = require('./mock_api')('10 seconds')

request(mockAPI)
.get('/api/movies')
.end(function(err, res) {
expect(mockAPI.requestsProcessed).to.equal(1)
expect(mockAPI.apicache.getIndex().all.length).to.equal(1)
expect(mockAPI.apicache.clear('/api/movies').all.length).to.equal(0)
done()
})
})

it('clears empty group after removing last specific endpoint', function(done) {
var mockAPI = require('./mock_api')('10 seconds')

request(mockAPI)
.get('/api/testcachegroup')
.end(function(err, res) {
expect(mockAPI.requestsProcessed).to.equal(1)
expect(mockAPI.apicache.getIndex().all.length).to.equal(1)
expect(mockAPI.apicache.getIndex().groups.cachegroup.length).to.equal(1)
expect(Object.keys(mockAPI.apicache.clear('/api/testcachegroup').groups).length).to.equal(0)
expect(mockAPI.apicache.getIndex().all.length).to.equal(0)
done()
})
})

it('works when called with no key', function(done) {
var mockAPI = require('./mock_api')('10 seconds')

expect(mockAPI.apicache.getIndex().all.length).to.equal(0)
expect(mockAPI.apicache.clear().all.length).to.equal(0)
request(mockAPI)
.get('/api/movies')
.end(function(err, res) {
expect(mockAPI.requestsProcessed).to.equal(1)
expect(mockAPI.apicache.getIndex().all.length).to.equal(1)
expect(mockAPI.apicache.clear().all.length).to.equal(0)
done()
})
})
})
10 changes: 10 additions & 0 deletions test/mock_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ function MockAPI(expiration, options) {
res.json(movies)
})

app.get('/api/writeandend', function(req, res) {
app.requestsProcessed++

res.write('a')
res.write('b')
res.write('c')

res.end()
})

app.get('/api/testcachegroup', function(req, res) {
app.requestsProcessed++
req.apicacheGroup = 'cachegroup'
Expand Down

0 comments on commit 902a154

Please sign in to comment.