Skip to content

Commit

Permalink
Merge pull request #849 from zapier/pde-5239/scope-zcache-auth
Browse files Browse the repository at this point in the history
feat(core) - Add scopes as an option for zcache usage
  • Loading branch information
standielpls authored Aug 28, 2024
2 parents edf9a48 + 0fbf903 commit ec2dacd
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 20 deletions.
36 changes: 26 additions & 10 deletions packages/core/src/tools/create-cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ const ensureJSONEncodable = require('./ensure-json-encodable');

const createCache = (input) => {
const rpc = _.get(input, '_zapier.rpc');
const runValidationChecks = (rpc, key, value = null, ttl = null) => {
const runValidationChecks = (
rpc,
key,
value = null,
ttl = null,
scope = null
) => {
if (!rpc) {
throw new Error('rpc is not available');
}
Expand All @@ -20,25 +26,35 @@ const createCache = (input) => {
throw new TypeError('ttl must be an integer');
}

if (
scope !== null &&
(!Array.isArray(scope) ||
!scope.every((v) => v === 'user' || v === 'auth'))
) {
throw new TypeError(
'scope must be an array of strings with values "user" or "auth"'
);
}

ensureJSONEncodable(value);
};

return {
get: async (key) => {
runValidationChecks(rpc, key);
get: async (key, scope = null) => {
runValidationChecks(rpc, key, scope);

const result = await rpc('zcache_get', key);
const result = await rpc('zcache_get', key, scope);
return result ? JSON.parse(result) : null;
},
set: async (key, value, ttl = null) => {
runValidationChecks(rpc, key, value, ttl);
set: async (key, value, ttl = null, scope = null) => {
runValidationChecks(rpc, key, value, ttl, scope);

return await rpc('zcache_set', key, JSON.stringify(value), ttl);
return await rpc('zcache_set', key, JSON.stringify(value), ttl, scope);
},
delete: async (key) => {
runValidationChecks(rpc, key);
delete: async (key, scope = null) => {
runValidationChecks(rpc, key, scope);

return await rpc('zcache_delete', key);
return await rpc('zcache_delete', key, scope);
},
};
};
Expand Down
69 changes: 59 additions & 10 deletions packages/core/test/tools/create-cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe('zcache: get, set, delete', () => {
const cache = createCache({ _zapier: { rpc } });

it('zcache_get: should return the cache entry of an existing key', async () => {
const value = {entity:'Zapier', colors: ['Orange', 'black']};
const value = { entity: 'Zapier', colors: ['Orange', 'black'] };
mockRpcCall(JSON.stringify(value));

const result = await cache.get('existing-key');
Expand All @@ -28,10 +28,10 @@ describe('zcache: get, set, delete', () => {
await cache.get(12345).should.be.rejectedWith('key must be a string');
});

it('zcache_set: should set a cache entry based on the app\'s rate-limit', async () => {
const key1 = 'random-key1'
const key2 = 'random-key2'
const value = {entity:'Zapier', colors: ['Orange', 'black']};
it("zcache_set: should set a cache entry based on the app's rate-limit", async () => {
const key1 = 'random-key1';
const key2 = 'random-key2';
const value = { entity: 'Zapier', colors: ['Orange', 'black'] };
const valueLength = JSON.stringify(value).length;

// in bytes/minute
Expand All @@ -53,14 +53,24 @@ describe('zcache: get, set, delete', () => {
it('zcache_set: should throw error for values that are not JSON-encodable', async () => {
const key = 'random-key';
let value = console;
await cache.set(key, value).should.be.rejectedWith("Type 'object' is not JSON-encodable (path: '')");

value = () => { 'this is a function' };
await cache.set(key, value).should.be.rejectedWith("Type 'function' is not JSON-encodable (path: '')");
await cache
.set(key, value)
.should.be.rejectedWith("Type 'object' is not JSON-encodable (path: '')");

value = () => {
'this is a function';
};
await cache
.set(key, value)
.should.be.rejectedWith(
"Type 'function' is not JSON-encodable (path: '')"
);
});

it('zcache_set: should throw error for a non-integer ttl', async () => {
await cache.set('random-key', 'random-value', 'twenty').should.be.rejectedWith('ttl must be an integer');
await cache
.set('random-key', 'random-value', 'twenty')
.should.be.rejectedWith('ttl must be an integer');
});

it('zcache_delete: should delete the cache entry of an existing key', async () => {
Expand All @@ -76,4 +86,43 @@ describe('zcache: get, set, delete', () => {
const result = await cache.delete('non-existing-key');
should(result).eql(false);
});

it('zcache_set: no scope is ok', async () => {
mockRpcCall(true);
const res = await cache.set('key', 'ok');
should(res).eql(true);
});
it('zcache_set: empty array scope is ok', async () => {
mockRpcCall(true);

const res = await cache.set('key', 'ok', 1, []);
should(res).eql(true);
});
it('zcache_set: user and auth scope is ok', async () => {
mockRpcCall(true);

const res = await cache.set('key', 'ok', 1, ['user', 'auth']);
should(res).eql(true);
});
it('zcache_set: scope as string is not ok', async () => {
await cache
.set('key', 'ok', 1, 'bad')
.should.be.rejectedWith(
'scope must be an array of strings with values "user" or "auth"'
);
});
it('zcache_set: bad scope is not ok', async () => {
await cache
.set('key', 'ok', 1, ['bad', 'scope'])
.should.be.rejectedWith(
'scope must be an array of strings with values "user" or "auth"'
);
});
it('zcache_set: mix of good and bad is not ok', async () => {
await cache
.set('key', 'ok', 1, ['bad', 'auth'])
.should.be.rejectedWith(
'scope must be an array of strings with values "user" or "auth"'
);
});
});

0 comments on commit ec2dacd

Please sign in to comment.