Skip to content

Commit

Permalink
test(keys): add metadata cases
Browse files Browse the repository at this point in the history
  • Loading branch information
Kikobeats committed Apr 8, 2024
1 parent d504221 commit 527dca3
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 54 deletions.
5 changes: 3 additions & 2 deletions src/keys.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

const { pick, uid, validateKey, assert } = require('./util')
const { pick, uid, validateKey, assert, assertMetadata } = require('./util')

const KEY_PREFIX = 'key_'
const KEY_FIELDS = ['name', 'description', 'enabled', 'value', 'plan']
Expand All @@ -22,6 +22,7 @@ module.exports = ({ serialize, deserialize, plans, redis } = {}) => {
*/
const create = async (opts = {}) => {
assert(typeof opts.name === 'string' && opts.name.length > 0, 'The argument `name` is required.')
opts.metadata = assertMetadata(opts.metadata)
const key = pick(opts, KEY_FIELDS.concat(KEY_FIELDS_OBJECT))
key.id = await uid({ redis, prefix: KEY_PREFIX, size: 5 })
key.createdAt = key.updatedAt = Date.now()
Expand Down Expand Up @@ -84,7 +85,7 @@ module.exports = ({ serialize, deserialize, plans, redis } = {}) => {
*/
const update = async (keyId, opts) => {
const currentKey = await retrieve(keyId, { throwError: true })
const metadata = Object.assign({}, currentKey.metadata, opts.metadata)
const metadata = Object.assign({}, currentKey.metadata, assertMetadata(opts.metadata))
const key = Object.assign(currentKey, pick(opts, KEY_FIELDS), {
updatedAt: Date.now()
})
Expand Down
117 changes: 77 additions & 40 deletions test/keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ test('.create # `name` is required', async t => {
t.is(error.name, 'TypeError')
})

test('.create # `metadata` must be a flat object', async t => {
const error = await t.throwsAsync(keys.create({ name: '[email protected]', metadata: { tier: { type: 'new' } } }))

t.is(error.message, "The metadata field 'tier' can't be an object.")
t.is(error.name, 'TypeError')
})

test('.create # `metadata` as undefined is omitted', async t => {
const key = keys.create({ name: '[email protected]', metadata: { cc: undefined } })

t.is(key.metadata, undefined)
})

test('.create # error if plan is invalid', async t => {
const error = await t.throwsAsync(keys.create({ name: '[email protected]', plan: 123 }))

Expand All @@ -48,7 +61,22 @@ test('.create', async t => {
t.true(key.enabled)
})

test('.retrieve', async t => {
test('.create # associate a plan', async t => {
const plan = await plans.create({
name: 'free tier',
quota: { limit: 3000, period: 'day' }
})

const key = await keys.create({ name: '[email protected]', plan: plan.id })

t.true(key.id.startsWith('key_'))
t.truthy(key.createdAt)
t.is(key.createdAt, key.updatedAt)
t.is(key.value.length, 16)
t.true(key.enabled)
})

test('.retrieve # a key previously created', async t => {
const { id, value } = await keys.create({ name: '[email protected]' })

const { createdAt, updatedAt, ...key } = await keys.retrieve(id)
Expand All @@ -61,6 +89,10 @@ test('.retrieve', async t => {
})
})

test('.retrieve # a key not previously created', async t => {
t.is(await keys.retrieve('key_1'), null)
})

test('.update', async t => {
const { id, value, createdAt } = await keys.create({
name: '[email protected]'
Expand All @@ -86,47 +118,16 @@ test('.update', async t => {
t.deepEqual(await keys.retrieve(id), { ...key, updatedAt })
})

test('.update # error if plan is invalid', async t => {
const { id } = await keys.create({ name: '[email protected]' })

const error = await t.throwsAsync(
keys.update(id, {
description: 'new description',
enabled: false,
plan: 123
})
)

t.is(error.message, 'The id `123` must to start with `plan_`.')
t.is(error.name, 'TypeError')
})

test('.update # error if plan does not exist', async t => {
const { id } = await keys.create({ name: '[email protected]' })

const error = await t.throwsAsync(
keys.update(id, {
description: 'new description',
enabled: false,
plan: 'plan_123'
})
)

t.is(error.message, 'The plan `plan_123` does not exist.')
test('.update # error if key is invalid', async t => {
const error = await t.throwsAsync(keys.update('id', { foo: 'bar' }))
t.is(error.message, 'The id `id` must to start with `key_`.')
t.is(error.name, 'TypeError')
})

test('.update # error if key does not exist', async t => {
{
const error = await t.throwsAsync(keys.update('id', { foo: 'bar' }))
t.is(error.message, 'The id `id` must to start with `key_`.')
t.is(error.name, 'TypeError')
}
{
const error = await t.throwsAsync(keys.update('key_id', { foo: 'bar' }))
t.is(error.message, 'The key `key_id` does not exist.')
t.is(error.name, 'TypeError')
}
const error = await t.throwsAsync(keys.update('key_id'))
t.is(error.message, 'The key `key_id` does not exist.')
t.is(error.name, 'TypeError')
})

test('.update # add a plan', async t => {
Expand All @@ -142,10 +143,39 @@ test('.update # add a plan', async t => {
})

test('.update # add metadata', async t => {
{
const { id } = await keys.create({ name: '[email protected]' })
const key = await keys.update(id, { metadata: { cc: '[email protected]' } })
t.is(key.metadata.cc, '[email protected]')
}
{
const { id } = await keys.create({ name: '[email protected]' })
await keys.update(id, { metadata: { cc: '[email protected]' } })
const key = await keys.update(id, { metadata: { cc: '[email protected]', version: 2 } })

t.is(key.metadata.cc, '[email protected]')
t.is(key.metadata.version, 2)
}
})

test('.update # metadata must be a flat object', async t => {
const { id } = await keys.create({ name: '[email protected]' })
const key = await keys.update(id, { metadata: { cc: '[email protected]' } })
const error = await t.throwsAsync(keys.update(id, { metadata: { email: { cc: '[email protected]' } } }))
t.is(error.message, "The metadata field 'email' can't be an object.")
t.is(error.name, 'TypeError')
})

t.is(key.metadata.cc, '[email protected]')
test('.update # metadata as undefined is omitted', async t => {
{
const { id } = await keys.create({ name: '[email protected]' })
const key = await keys.update(id, { metadata: { email: undefined } })
t.is(key.metadata, undefined)
}
{
const { id } = await keys.create({ name: '[email protected]' })
const key = await keys.update(id, { metadata: { cc: '[email protected]', bcc: undefined } })
t.deepEqual(Object.keys(key.metadata), ['cc'])
}
})

test('.update # prevent to add random data', async t => {
Expand All @@ -155,6 +185,13 @@ test('.update # prevent to add random data', async t => {
t.is(key.foo, undefined)
})

test('.update # prevent to modify the key id', async t => {
const { id } = await keys.create({ name: '[email protected]' })
const key = await keys.update(id, { id: 'foo' })

t.is(key.id, id)
})

test.serial('.list', async t => {
const { id: id1 } = await keys.create({ name: '[email protected]' })
const { id: id2 } = await keys.create({ name: '[email protected]' })
Expand Down
23 changes: 11 additions & 12 deletions test/plans.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,11 @@ test('.create', async t => {
t.deepEqual(plan.throttle, { burstLimit: 1000, rateLimit: 10 })
})

test('.retrieve # a plan not previosuly declared', async t => {
test('.retrieve # a plan not previosuly created', async t => {
t.is(await plans.retrieve('plan_1'), null)
})

test('.retrieve # a plan previosuly declared', async t => {
test('.retrieve # a plan previosuly created', async t => {
const { id } = await plans.create({
name: 'free tier',
quota: { limit: 3000, period: 'day' }
Expand Down Expand Up @@ -232,17 +232,16 @@ test('.update # prevent to modify the plan id', async t => {
t.is(plan.id, id)
})

test('.update # error if plan is invalid', async t => {
const error = await t.throwsAsync(plans.update('id', { foo: 'bar' }))
t.is(error.message, 'The id `id` must to start with `plan_`.')
t.is(error.name, 'TypeError')
})

test('.update # error if plan does not exist', async t => {
{
const error = await t.throwsAsync(plans.update('id', { foo: 'bar' }))
t.is(error.message, 'The id `id` must to start with `plan_`.')
t.is(error.name, 'TypeError')
}
{
const error = await t.throwsAsync(plans.update('plan_id', { foo: 'bar' }))
t.is(error.message, 'The plan `plan_id` does not exist.')
t.is(error.name, 'TypeError')
}
const error = await t.throwsAsync(plans.update('plan_id', { foo: 'bar' }))
t.is(error.message, 'The plan `plan_id` does not exist.')
t.is(error.name, 'TypeError')
})

test.serial('.list', async t => {
Expand Down

0 comments on commit 527dca3

Please sign in to comment.