Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: add metadata cases
Browse files Browse the repository at this point in the history
Kikobeats committed Apr 7, 2024
1 parent 8fe1718 commit 5a2249d
Showing 2 changed files with 113 additions and 6 deletions.
7 changes: 4 additions & 3 deletions src/plans.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 PLAN_PREFIX = 'plan_'
const PLAN_QUOTA_PERIODS = ['day', 'week', 'month']
@@ -22,7 +22,7 @@ module.exports = ({ serialize, deserialize, redis } = {}) => {
* @param {number} [options.throttle.rateLimit] - The rate limit of the plan.
* @param {Object} [options.metadata] - Any extra information can be attached here.
*
* @returns {Object|null} The plan object, null if it doesn't exist.
* @returns {Object} The plan object.
*/
const create = async (opts = {}) => {
assert(typeof opts.name === 'string' && opts.name.length > 0, 'The argument `name` is required.')
@@ -31,6 +31,7 @@ module.exports = ({ serialize, deserialize, redis } = {}) => {
`The argument \`quota.period\` must be ${PLAN_QUOTA_PERIODS.map(period => `\`${period}\``).join(' or ')}.`
)
assert(opts.quota.limit > 0, 'The argument `quota.limit` must be a positive number.')
opts.metadata = assertMetadata(opts.metadata)
const plan = pick(opts, PLAN_FIELDS.concat(PLAN_FIELDS_OBJECT))
plan.id = await uid({ redis, prefix: PLAN_PREFIX, size: 5 })
plan.createdAt = plan.updatedAt = Date.now()
@@ -88,7 +89,7 @@ module.exports = ({ serialize, deserialize, redis } = {}) => {
const update = async (planId, opts) => {
const currentPlan = await retrieve(planId, { throwError: true })
const quota = Object.assign(currentPlan.quota, opts.quota)
const metadata = Object.assign({}, currentPlan.metadata, opts.metadata)
const metadata = Object.assign({}, currentPlan.metadata, opts.assertMetadata(opts.metadata))
const plan = Object.assign(currentPlan, pick(opts, PLAN_FIELDS), {
quota,
updatedAt: Date.now()
112 changes: 109 additions & 3 deletions test/plans.js
Original file line number Diff line number Diff line change
@@ -50,6 +50,51 @@ test('.create # `quota` is required', async t => {
}
})

test('.create # `metadata` must be a flat object', async t => {
{
const error = await t.throwsAsync(
plans.create({
name: 'free tier',
quota: { period: 'week', limit: 1000 },
metadata: { tier: { type: 'new' } }
})
)
t.is(error.message, "The metadata field 'tier' can't be an object.")
t.is(error.name, 'TypeError')
}
{
const error = await t.throwsAsync(
plans.create({
name: 'free tier',
quota: { period: 'week', limit: 1000 },
metadata: 'foo'
})
)
t.is(error.message, 'The metadata must be a flat object.')
t.is(error.name, 'TypeError')
}
})

test('.create # `metadata` as undefined is omitted', async t => {
{
const plan = await plans.create({
name: 'free tier',
quota: { period: 'week', limit: 1000 },
metadata: { tier: undefined }
})
t.is(plan.metadata, undefined)
}
{
const plan = await plans.create({
name: 'free tier',
quota: { period: 'week', limit: 1000 },
metadata: { tier: 'free', version: undefined }
})

t.deepEqual(Object.keys(plan.metadata), ['tier'])
}
})

test('.create', async t => {
const plan = await plans.create({
name: 'free tier',
@@ -68,7 +113,11 @@ test('.create', async t => {
t.deepEqual(plan.throttle, { burstLimit: 1000, rateLimit: 10 })
})

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

test('.retrieve # a plan previosuly declared', async t => {
const { id } = await plans.create({
name: 'free tier',
quota: { limit: 3000, period: 'day' }
@@ -108,13 +157,59 @@ test('.update', async t => {
})

test('.update # add metadata', async t => {
{
const { id } = await plans.create({
name: 'free tier',
quota: { limit: 3000, period: 'day' }
})

const plan = await plans.update(id, { metadata: { tier: 'free' } })
t.is(plan.metadata.tier, 'free')
}
{
const { id } = await plans.create({
name: 'free tier',
quota: { limit: 3000, period: 'day' }
})

await plans.update(id, { metadata: { tier: 'free' } })
const plan = await plans.update(id, { metadata: { tier: 'free', version: 2 } })
t.is(plan.metadata.tier, 'free')
t.is(plan.metadata.version, 2)
}
})

test('.update # metadata must be a flat object', async t => {
const { id } = await plans.create({
name: 'free tier',
quota: { limit: 3000, period: 'day' }
})

const plan = await plans.update(id, { metadata: { tier: 'free' } })
t.is(plan.metadata.tier, 'free')
const error = await t.throwsAsync(plans.update(id, { metadata: { tier: { type: 'new' } } }))
t.is(error.message, "The metadata field 'tier' can't be an object.")
t.is(error.name, 'TypeError')
})

test('.update # metadata as undefined is omitted', async t => {
{
const { id } = await plans.create({
name: 'free tier',
quota: { limit: 3000, period: 'day' }
})

const plan = await plans.update(id, { metadata: { tier: undefined } })
t.is(plan.metadata, undefined)
}

{
const { id } = await plans.create({
name: 'free tier',
quota: { limit: 3000, period: 'day' }
})

const plan = await plans.update(id, { metadata: { tier: 'free', version: undefined } })
t.deepEqual(Object.keys(plan.metadata), ['tier'])
}
})

test('.update # prevent to add random data', async t => {
@@ -126,6 +221,17 @@ test('.update # prevent to add random data', async t => {
t.is(plan.foo, undefined)
})

test('.update # prevent to modify the plan id', async t => {
const { id } = await plans.create({
name: 'free tier',
quota: { limit: 3000, period: 'day' }
})

const plan = await plans.update(id, { id: 'foo' })

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

test('.update # error if plan does not exist', async t => {
{
const error = await t.throwsAsync(plans.update('id', { foo: 'bar' }))

0 comments on commit 5a2249d

Please sign in to comment.