Skip to content
This repository has been archived by the owner on Nov 30, 2023. It is now read-only.

feat: accept duration in seconds as option #1

Merged
merged 3 commits into from Mar 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/config.js
@@ -1,9 +1,12 @@
const sanitizePath = path =>
path ? path.replace(/^\/(.*)\/$/, '/$1') : ''

const defaultExpiration = Number(process.env.DEFAULT_EXPIRATION) || 60 * 60 * 24 * 7

module.exports = Object.freeze({
pathPrefix: sanitizePath(process.env.PATH_PREFIX || ''),
redisUrl: process.env.REDIS_URL || 'redis://127.0.0.1:6379',
isRedisCluster: process.env.REDIS_CLUSTER === 'true',
defaultExpiration: Number(process.env.DEFAULT_EXPIRATION) || 60 * 60 * 24 * 7
defaultExpiration,
maxDuration: Number(process.env.MAX_DURATION) || defaultExpiration
})
5 changes: 3 additions & 2 deletions src/options.js
@@ -1,12 +1,13 @@
const splitFlags = (flags, state) =>
flags && flags.split(',').reduce((all, flag) => ({ ...all, [flag]: state }), {})

const parseOptions = ({ enable, disable }) => {
const parseOptions = ({ enable, disable, duration }) => {
return {
flags: {
...splitFlags(enable, true),
...splitFlags(disable, false)
}
},
duration: parseInt(duration)
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/server.js
Expand Up @@ -3,15 +3,17 @@ const { SessionClient } = require('tog-node')

const { parseOptions } = require('./options')

function server ({ pathPrefix, redisUrl, isRedisCluster, defaultExpiration }, fastifyConfig = {}) {
function server ({ pathPrefix, redisUrl, isRedisCluster, defaultExpiration, maxDuration }, fastifyConfig = {}) {
const client = new SessionClient(redisUrl, { cluster: isRedisCluster })

return fastify(fastifyConfig)
.get(pathPrefix + '/:ns/:sid', (request, reply) => {
const options = parseOptions(request.query)
return client.session(request.params.ns, request.params.sid, {
flags: options.flags,
duration: defaultExpiration
duration: options.duration >= 1
? Math.min(options.duration, maxDuration)
: defaultExpiration
})
.then(session => reply.status(200).send(session))
})
Expand Down
47 changes: 45 additions & 2 deletions src/server.test.js
Expand Up @@ -8,6 +8,7 @@ jest.mock('tog-node', () => ({

const any = expect.anything()
const defaultExpiration = 60
const maxDuration = defaultExpiration
const mockSessionPayload = { id: 'abc123' }
const serializedPayload = JSON.stringify(mockSessionPayload)

Expand All @@ -18,7 +19,7 @@ beforeEach(() => {

describe('retrieve session', () => {
describe('with path prefix', () => {
const app = server({ pathPrefix: '/sessions', defaultExpiration })
const app = server({ pathPrefix: '/sessions', defaultExpiration, maxDuration })

afterAll(() => app.close())

Expand All @@ -34,7 +35,7 @@ describe('retrieve session', () => {
})

describe('with default configuration', () => {
const app = server({ pathPrefix: '', defaultExpiration })
const app = server({ pathPrefix: '', defaultExpiration, maxDuration })

afterAll(() => app.close())

Expand Down Expand Up @@ -65,5 +66,47 @@ describe('retrieve session', () => {
flags: { one: false, two: false }
}))
})

test('accepts custom valid duration', async () => {
await app.inject('/some-ns/abc123?disable=one&enable=two&duration=1')

expect(mockSession).toHaveBeenCalledWith(any, any,
expect.objectContaining({
flags: { one: false, two: true },
duration: 1
})
)
})

test.each([
{ duration: 'number', want: defaultExpiration },
{ duration: 5.678, want: 5 },
{ duration: -1, want: defaultExpiration }
])('resolves custom invalid duration', async ({ duration, want }) => {
await app.inject(`/some-ns/abc123?disable=one&enable=two&duration=${duration}`)

expect(mockSession).toHaveBeenCalledWith(any, any,
expect.objectContaining({
flags: { one: false, two: true },
duration: want
})
)
})
})

describe('with custom max duration', () => {
const app = server({ pathPrefix: '', defaultExpiration, maxDuration: 5 })

afterAll(() => app.close())

test('respects max duration', async () => {
const res = await app.inject('/some-ns/abc123?duration=6')

expect(res.statusCode).toBe(200)
expect(res.payload).toEqual(serializedPayload)

expect(mockSession).toHaveBeenCalledWith(
'some-ns', 'abc123', expect.objectContaining({ duration: 5, flags: {} }))
})
})
})