From f70a1c2ce1065e9caea04b20a4b36742b5161840 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 19 Feb 2021 17:42:04 -0800 Subject: [PATCH 1/4] Increase timeout for redis tests --- spec/RedisCacheAdapter.spec.js | 893 +++++++++++++++++---------------- 1 file changed, 447 insertions(+), 446 deletions(-) diff --git a/spec/RedisCacheAdapter.spec.js b/spec/RedisCacheAdapter.spec.js index 4991d2b937..00a69d3fe6 100644 --- a/spec/RedisCacheAdapter.spec.js +++ b/spec/RedisCacheAdapter.spec.js @@ -1,528 +1,529 @@ const RedisCacheAdapter = require('../lib/Adapters/Cache/RedisCacheAdapter').default; const Config = require('../lib/Config'); - -/* +for (let x = 0; x < 300; x++) { + /* To run this test part of the complete suite set PARSE_SERVER_TEST_CACHE='redis' and make sure a redis server is available on the default port */ -describe_only(() => { - return process.env.PARSE_SERVER_TEST_CACHE === 'redis'; -})('RedisCacheAdapter', function () { - const KEY = 'hello'; - const VALUE = 'world'; - - function wait(sleep) { - return new Promise(function (resolve) { - setTimeout(resolve, sleep); + describe_only(() => { + return process.env.PARSE_SERVER_TEST_CACHE === 'redis'; + })('RedisCacheAdapter', function () { + const KEY = 'hello'; + const VALUE = 'world'; + + function wait(sleep) { + return new Promise(function (resolve) { + setTimeout(resolve, sleep); + }); + } + + it('should get/set/clear', done => { + const cache = new RedisCacheAdapter({ + ttl: NaN, + }); + + cache + .put(KEY, VALUE) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(VALUE)) + .then(() => cache.clear()) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(null)) + .then(done); }); - } - it('should get/set/clear', done => { - const cache = new RedisCacheAdapter({ - ttl: NaN, + it('should expire after ttl', done => { + const cache = new RedisCacheAdapter(null, 50); + + cache + .put(KEY, VALUE) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(VALUE)) + .then(wait.bind(null, 52)) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(null)) + .then(done); }); - cache - .put(KEY, VALUE) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(VALUE)) - .then(() => cache.clear()) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(null)) - .then(done); - }); + it('should not store value for ttl=0', done => { + const cache = new RedisCacheAdapter(null, 50); - it('should expire after ttl', done => { - const cache = new RedisCacheAdapter(null, 50); - - cache - .put(KEY, VALUE) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(VALUE)) - .then(wait.bind(null, 52)) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(null)) - .then(done); - }); + cache + .put(KEY, VALUE, 0) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(null)) + .then(done); + }); - it('should not store value for ttl=0', done => { - const cache = new RedisCacheAdapter(null, 5); + it('should not expire when ttl=Infinity', done => { + const cache = new RedisCacheAdapter(null, 50); + + cache + .put(KEY, VALUE, Infinity) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(VALUE)) + .then(wait.bind(null, 52)) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(VALUE)) + .then(done); + }); - cache - .put(KEY, VALUE, 0) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(null)) - .then(done); - }); + it('should fallback to default ttl', done => { + const cache = new RedisCacheAdapter(null, 50); + let promise = Promise.resolve(); + + [-100, null, undefined, 'not number', true].forEach(ttl => { + promise = promise.then(() => + cache + .put(KEY, VALUE, ttl) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(VALUE)) + .then(wait.bind(null, 52)) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(null)) + ); + }); - it('should not expire when ttl=Infinity', done => { - const cache = new RedisCacheAdapter(null, 1); - - cache - .put(KEY, VALUE, Infinity) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(VALUE)) - .then(wait.bind(null, 5)) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(VALUE)) - .then(done); - }); + promise.then(done); + }); - it('should fallback to default ttl', done => { - const cache = new RedisCacheAdapter(null, 1); - let promise = Promise.resolve(); - - [-100, null, undefined, 'not number', true].forEach(ttl => { - promise = promise.then(() => - cache - .put(KEY, VALUE, ttl) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(VALUE)) - .then(wait.bind(null, 5)) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(null)) - ); + it('should find un-expired records', done => { + const cache = new RedisCacheAdapter(null, 50); + + cache + .put(KEY, VALUE) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(VALUE)) + .then(wait.bind(null, 1)) + .then(() => cache.get(KEY)) + .then(value => expect(value).not.toEqual(null)) + .then(done); }); - promise.then(done); - }); + it('handleShutdown, close connection', async () => { + const cache = new RedisCacheAdapter(null, 50); - it('should find un-expired records', done => { - const cache = new RedisCacheAdapter(null, 5); - - cache - .put(KEY, VALUE) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(VALUE)) - .then(wait.bind(null, 1)) - .then(() => cache.get(KEY)) - .then(value => expect(value).not.toEqual(null)) - .then(done); + await cache.handleShutdown(); + setTimeout(() => { + expect(cache.client.connected).toBe(false); + }, 0); + }); }); - it('handleShutdown, close connection', async () => { - const cache = new RedisCacheAdapter(null, 5); + describe_only(() => { + return process.env.PARSE_SERVER_TEST_CACHE === 'redis'; + })('RedisCacheAdapter/KeyPromiseQueue', function () { + const KEY1 = 'key1'; + const KEY2 = 'key2'; + const VALUE = 'hello'; - await cache.handleShutdown(); - setTimeout(() => { - expect(cache.client.connected).toBe(false); - }, 0); - }); -}); - -describe_only(() => { - return process.env.PARSE_SERVER_TEST_CACHE === 'redis'; -})('RedisCacheAdapter/KeyPromiseQueue', function () { - const KEY1 = 'key1'; - const KEY2 = 'key2'; - const VALUE = 'hello'; - - // number of chained ops on a single key - function getQueueCountForKey(cache, key) { - return cache.queue.queue[key][0]; - } - - // total number of queued keys - function getQueueCount(cache) { - return Object.keys(cache.queue.queue).length; - } - - it('it should clear completed operations from queue', done => { - const cache = new RedisCacheAdapter({ ttl: NaN }); - - // execute a bunch of operations in sequence - let promise = Promise.resolve(); - for (let index = 1; index < 100; index++) { - promise = promise.then(() => { - const key = `${index}`; - return cache - .put(key, VALUE) - .then(() => expect(getQueueCount(cache)).toEqual(0)) - .then(() => cache.get(key)) - .then(() => expect(getQueueCount(cache)).toEqual(0)) - .then(() => cache.clear()) - .then(() => expect(getQueueCount(cache)).toEqual(0)); - }); + // number of chained ops on a single key + function getQueueCountForKey(cache, key) { + return cache.queue.queue[key][0]; } - // at the end the queue should be empty - promise.then(() => expect(getQueueCount(cache)).toEqual(0)).then(done); - }); - - it('it should count per key chained operations correctly', done => { - const cache = new RedisCacheAdapter({ ttl: NaN }); - - let key1Promise = Promise.resolve(); - let key2Promise = Promise.resolve(); - for (let index = 1; index < 100; index++) { - key1Promise = cache.put(KEY1, VALUE); - key2Promise = cache.put(KEY2, VALUE); - // per key chain should be equal to index, which is the - // total number of operations on that key - expect(getQueueCountForKey(cache, KEY1)).toEqual(index); - expect(getQueueCountForKey(cache, KEY2)).toEqual(index); - // the total keys counts should be equal to the different keys - // we have currently being processed. - expect(getQueueCount(cache)).toEqual(2); + // total number of queued keys + function getQueueCount(cache) { + return Object.keys(cache.queue.queue).length; } - // at the end the queue should be empty - Promise.all([key1Promise, key2Promise]) - .then(() => expect(getQueueCount(cache)).toEqual(0)) - .then(done); - }); -}); - -describe_only(() => { - return process.env.PARSE_SERVER_TEST_CACHE === 'redis'; -})('Redis Performance', function () { - let cacheAdapter; - let getSpy; - let putSpy; - let delSpy; - - beforeEach(async () => { - cacheAdapter = new RedisCacheAdapter(); - await reconfigureServer({ - cacheAdapter, + it('it should clear completed operations from queue', done => { + const cache = new RedisCacheAdapter({ ttl: NaN }); + + // execute a bunch of operations in sequence + let promise = Promise.resolve(); + for (let index = 1; index < 100; index++) { + promise = promise.then(() => { + const key = `${index}`; + return cache + .put(key, VALUE) + .then(() => expect(getQueueCount(cache)).toEqual(0)) + .then(() => cache.get(key)) + .then(() => expect(getQueueCount(cache)).toEqual(0)) + .then(() => cache.clear()) + .then(() => expect(getQueueCount(cache)).toEqual(0)); + }); + } + + // at the end the queue should be empty + promise.then(() => expect(getQueueCount(cache)).toEqual(0)).then(done); }); - await cacheAdapter.clear(); - getSpy = spyOn(cacheAdapter, 'get').and.callThrough(); - putSpy = spyOn(cacheAdapter, 'put').and.callThrough(); - delSpy = spyOn(cacheAdapter, 'del').and.callThrough(); + it('it should count per key chained operations correctly', done => { + const cache = new RedisCacheAdapter({ ttl: NaN }); + + let key1Promise = Promise.resolve(); + let key2Promise = Promise.resolve(); + for (let index = 1; index < 100; index++) { + key1Promise = cache.put(KEY1, VALUE); + key2Promise = cache.put(KEY2, VALUE); + // per key chain should be equal to index, which is the + // total number of operations on that key + expect(getQueueCountForKey(cache, KEY1)).toEqual(index); + expect(getQueueCountForKey(cache, KEY2)).toEqual(index); + // the total keys counts should be equal to the different keys + // we have currently being processed. + expect(getQueueCount(cache)).toEqual(2); + } + + // at the end the queue should be empty + Promise.all([key1Promise, key2Promise]) + .then(() => expect(getQueueCount(cache)).toEqual(0)) + .then(done); + }); }); - it('test new object', async () => { - const object = new TestObject(); - object.set('foo', 'bar'); - await object.save(); - expect(getSpy.calls.count()).toBe(3); - expect(putSpy.calls.count()).toBe(3); - expect(delSpy.calls.count()).toBe(1); - - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + describe_only(() => { + return process.env.PARSE_SERVER_TEST_CACHE === 'redis'; + })('Redis Performance', function () { + let cacheAdapter; + let getSpy; + let putSpy; + let delSpy; + + beforeEach(async () => { + cacheAdapter = new RedisCacheAdapter(); + await reconfigureServer({ + cacheAdapter, + }); + await cacheAdapter.clear(); - it('test new object multiple fields', async () => { - const container = new Container({ - dateField: new Date(), - arrayField: [], - numberField: 1, - stringField: 'hello', - booleanField: true, + getSpy = spyOn(cacheAdapter, 'get').and.callThrough(); + putSpy = spyOn(cacheAdapter, 'put').and.callThrough(); + delSpy = spyOn(cacheAdapter, 'del').and.callThrough(); }); - await container.save(); - expect(getSpy.calls.count()).toBe(3); - expect(putSpy.calls.count()).toBe(3); - expect(delSpy.calls.count()).toBe(1); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + it('test new object', async () => { + const object = new TestObject(); + object.set('foo', 'bar'); + await object.save(); + expect(getSpy.calls.count()).toBe(3); + expect(putSpy.calls.count()).toBe(3); + expect(delSpy.calls.count()).toBe(1); + + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - it('test update existing fields', async () => { - const object = new TestObject(); - object.set('foo', 'bar'); - await object.save(); + it('test new object multiple fields', async () => { + const container = new Container({ + dateField: new Date(), + arrayField: [], + numberField: 1, + stringField: 'hello', + booleanField: true, + }); + await container.save(); + expect(getSpy.calls.count()).toBe(3); + expect(putSpy.calls.count()).toBe(3); + expect(delSpy.calls.count()).toBe(1); - getSpy.calls.reset(); - putSpy.calls.reset(); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - object.set('foo', 'barz'); - await object.save(); - expect(getSpy.calls.count()).toBe(3); - expect(putSpy.calls.count()).toBe(1); - expect(delSpy.calls.count()).toBe(2); + it('test update existing fields', async () => { + const object = new TestObject(); + object.set('foo', 'bar'); + await object.save(); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + getSpy.calls.reset(); + putSpy.calls.reset(); - it('test saveAll / destroyAll', async () => { - const object = new TestObject(); - await object.save(); + object.set('foo', 'barz'); + await object.save(); + expect(getSpy.calls.count()).toBe(3); + expect(putSpy.calls.count()).toBe(1); + expect(delSpy.calls.count()).toBe(2); - getSpy.calls.reset(); - putSpy.calls.reset(); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - const objects = []; - for (let i = 0; i < 10; i++) { + it('test saveAll / destroyAll', async () => { const object = new TestObject(); - object.set('number', i); - objects.push(object); - } - await Parse.Object.saveAll(objects); - expect(getSpy.calls.count()).toBe(21); - expect(putSpy.calls.count()).toBe(11); + await object.save(); + + getSpy.calls.reset(); + putSpy.calls.reset(); + + const objects = []; + for (let i = 0; i < 10; i++) { + const object = new TestObject(); + object.set('number', i); + objects.push(object); + } + await Parse.Object.saveAll(objects); + expect(getSpy.calls.count()).toBe(21); + expect(putSpy.calls.count()).toBe(11); + + getSpy.calls.reset(); + putSpy.calls.reset(); + + await Parse.Object.destroyAll(objects); + expect(getSpy.calls.count()).toBe(11); + expect(putSpy.calls.count()).toBe(1); + expect(delSpy.calls.count()).toBe(3); + + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - getSpy.calls.reset(); - putSpy.calls.reset(); + it('test saveAll / destroyAll batch', async () => { + const object = new TestObject(); + await object.save(); + + getSpy.calls.reset(); + putSpy.calls.reset(); + + const objects = []; + for (let i = 0; i < 10; i++) { + const object = new TestObject(); + object.set('number', i); + objects.push(object); + } + await Parse.Object.saveAll(objects, { batchSize: 5 }); + expect(getSpy.calls.count()).toBe(22); + expect(putSpy.calls.count()).toBe(7); + + getSpy.calls.reset(); + putSpy.calls.reset(); + + await Parse.Object.destroyAll(objects, { batchSize: 5 }); + expect(getSpy.calls.count()).toBe(12); + expect(putSpy.calls.count()).toBe(2); + expect(delSpy.calls.count()).toBe(5); + + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - await Parse.Object.destroyAll(objects); - expect(getSpy.calls.count()).toBe(11); - expect(putSpy.calls.count()).toBe(1); - expect(delSpy.calls.count()).toBe(3); + it('test add new field to existing object', async () => { + const object = new TestObject(); + object.set('foo', 'bar'); + await object.save(); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + getSpy.calls.reset(); + putSpy.calls.reset(); - it('test saveAll / destroyAll batch', async () => { - const object = new TestObject(); - await object.save(); + object.set('new', 'barz'); + await object.save(); + expect(getSpy.calls.count()).toBe(3); + expect(putSpy.calls.count()).toBe(2); + expect(delSpy.calls.count()).toBe(2); - getSpy.calls.reset(); - putSpy.calls.reset(); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - const objects = []; - for (let i = 0; i < 10; i++) { + it('test add multiple fields to existing object', async () => { const object = new TestObject(); - object.set('number', i); - objects.push(object); - } - await Parse.Object.saveAll(objects, { batchSize: 5 }); - expect(getSpy.calls.count()).toBe(22); - expect(putSpy.calls.count()).toBe(7); + object.set('foo', 'bar'); + await object.save(); + + getSpy.calls.reset(); + putSpy.calls.reset(); + + object.set({ + dateField: new Date(), + arrayField: [], + numberField: 1, + stringField: 'hello', + booleanField: true, + }); + await object.save(); + expect(getSpy.calls.count()).toBe(3); + expect(putSpy.calls.count()).toBe(2); + expect(delSpy.calls.count()).toBe(2); - getSpy.calls.reset(); - putSpy.calls.reset(); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - await Parse.Object.destroyAll(objects, { batchSize: 5 }); - expect(getSpy.calls.count()).toBe(12); - expect(putSpy.calls.count()).toBe(2); - expect(delSpy.calls.count()).toBe(5); + it('test user', async () => { + const user = new Parse.User(); + user.setUsername('testing'); + user.setPassword('testing'); + await user.signUp(); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + expect(getSpy.calls.count()).toBe(8); + expect(putSpy.calls.count()).toBe(2); + expect(delSpy.calls.count()).toBe(1); - it('test add new field to existing object', async () => { - const object = new TestObject(); - object.set('foo', 'bar'); - await object.save(); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - getSpy.calls.reset(); - putSpy.calls.reset(); + it('test allowClientCreation false', async () => { + const object = new TestObject(); + await object.save(); + await reconfigureServer({ + cacheAdapter, + allowClientClassCreation: false, + }); + await cacheAdapter.clear(); - object.set('new', 'barz'); - await object.save(); - expect(getSpy.calls.count()).toBe(3); - expect(putSpy.calls.count()).toBe(2); - expect(delSpy.calls.count()).toBe(2); + getSpy.calls.reset(); + putSpy.calls.reset(); + delSpy.calls.reset(); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + object.set('foo', 'bar'); + await object.save(); + expect(getSpy.calls.count()).toBe(4); + expect(putSpy.calls.count()).toBe(2); - it('test add multiple fields to existing object', async () => { - const object = new TestObject(); - object.set('foo', 'bar'); - await object.save(); + getSpy.calls.reset(); + putSpy.calls.reset(); - getSpy.calls.reset(); - putSpy.calls.reset(); + const query = new Parse.Query(TestObject); + await query.get(object.id); + expect(getSpy.calls.count()).toBe(3); + expect(putSpy.calls.count()).toBe(1); + expect(delSpy.calls.count()).toBe(2); - object.set({ - dateField: new Date(), - arrayField: [], - numberField: 1, - stringField: 'hello', - booleanField: true, + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); }); - await object.save(); - expect(getSpy.calls.count()).toBe(3); - expect(putSpy.calls.count()).toBe(2); - expect(delSpy.calls.count()).toBe(2); - - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); - it('test user', async () => { - const user = new Parse.User(); - user.setUsername('testing'); - user.setPassword('testing'); - await user.signUp(); + it('test query', async () => { + const object = new TestObject(); + object.set('foo', 'bar'); + await object.save(); - expect(getSpy.calls.count()).toBe(8); - expect(putSpy.calls.count()).toBe(2); - expect(delSpy.calls.count()).toBe(1); + getSpy.calls.reset(); + putSpy.calls.reset(); + delSpy.calls.reset(); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + const query = new Parse.Query(TestObject); + await query.get(object.id); + expect(getSpy.calls.count()).toBe(2); + expect(putSpy.calls.count()).toBe(1); + expect(delSpy.calls.count()).toBe(1); - it('test allowClientCreation false', async () => { - const object = new TestObject(); - await object.save(); - await reconfigureServer({ - cacheAdapter, - allowClientClassCreation: false, + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); }); - await cacheAdapter.clear(); - - getSpy.calls.reset(); - putSpy.calls.reset(); - delSpy.calls.reset(); - - object.set('foo', 'bar'); - await object.save(); - expect(getSpy.calls.count()).toBe(4); - expect(putSpy.calls.count()).toBe(2); - getSpy.calls.reset(); - putSpy.calls.reset(); + it('test query include', async () => { + const child = new TestObject(); + await child.save(); - const query = new Parse.Query(TestObject); - await query.get(object.id); - expect(getSpy.calls.count()).toBe(3); - expect(putSpy.calls.count()).toBe(1); - expect(delSpy.calls.count()).toBe(2); - - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); - - it('test query', async () => { - const object = new TestObject(); - object.set('foo', 'bar'); - await object.save(); - - getSpy.calls.reset(); - putSpy.calls.reset(); - delSpy.calls.reset(); - - const query = new Parse.Query(TestObject); - await query.get(object.id); - expect(getSpy.calls.count()).toBe(2); - expect(putSpy.calls.count()).toBe(1); - expect(delSpy.calls.count()).toBe(1); - - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); - - it('test query include', async () => { - const child = new TestObject(); - await child.save(); + const object = new TestObject(); + object.set('child', child); + await object.save(); - const object = new TestObject(); - object.set('child', child); - await object.save(); + getSpy.calls.reset(); + putSpy.calls.reset(); - getSpy.calls.reset(); - putSpy.calls.reset(); + const query = new Parse.Query(TestObject); + query.include('child'); + await query.get(object.id); - const query = new Parse.Query(TestObject); - query.include('child'); - await query.get(object.id); + expect(getSpy.calls.count()).toBe(4); + expect(putSpy.calls.count()).toBe(1); + expect(delSpy.calls.count()).toBe(3); - expect(getSpy.calls.count()).toBe(4); - expect(putSpy.calls.count()).toBe(1); - expect(delSpy.calls.count()).toBe(3); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + it('query relation without schema', async () => { + const child = new Parse.Object('ChildObject'); + await child.save(); - it('query relation without schema', async () => { - const child = new Parse.Object('ChildObject'); - await child.save(); + const parent = new Parse.Object('ParentObject'); + const relation = parent.relation('child'); + relation.add(child); + await parent.save(); - const parent = new Parse.Object('ParentObject'); - const relation = parent.relation('child'); - relation.add(child); - await parent.save(); + getSpy.calls.reset(); + putSpy.calls.reset(); - getSpy.calls.reset(); - putSpy.calls.reset(); + const objects = await relation.query().find(); + expect(objects.length).toBe(1); + expect(objects[0].id).toBe(child.id); - const objects = await relation.query().find(); - expect(objects.length).toBe(1); - expect(objects[0].id).toBe(child.id); + expect(getSpy.calls.count()).toBe(2); + expect(putSpy.calls.count()).toBe(1); + expect(delSpy.calls.count()).toBe(3); - expect(getSpy.calls.count()).toBe(2); - expect(putSpy.calls.count()).toBe(1); - expect(delSpy.calls.count()).toBe(3); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + it('test delete object', async () => { + const object = new TestObject(); + object.set('foo', 'bar'); + await object.save(); - it('test delete object', async () => { - const object = new TestObject(); - object.set('foo', 'bar'); - await object.save(); + getSpy.calls.reset(); + putSpy.calls.reset(); + delSpy.calls.reset(); - getSpy.calls.reset(); - putSpy.calls.reset(); - delSpy.calls.reset(); + await object.destroy(); + expect(getSpy.calls.count()).toBe(2); + expect(putSpy.calls.count()).toBe(1); + expect(delSpy.calls.count()).toBe(1); - await object.destroy(); - expect(getSpy.calls.count()).toBe(2); - expect(putSpy.calls.count()).toBe(1); - expect(delSpy.calls.count()).toBe(1); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + it('test schema update class', async () => { + const container = new Container(); + await container.save(); + + getSpy.calls.reset(); + putSpy.calls.reset(); + delSpy.calls.reset(); + + const config = Config.get('test'); + const schema = await config.database.loadSchema(); + await schema.reloadData(); + + const levelPermissions = { + find: { '*': true }, + get: { '*': true }, + create: { '*': true }, + update: { '*': true }, + delete: { '*': true }, + addField: { '*': true }, + protectedFields: { '*': [] }, + }; + + await schema.updateClass( + 'Container', + { + fooOne: { type: 'Number' }, + fooTwo: { type: 'Array' }, + fooThree: { type: 'Date' }, + fooFour: { type: 'Object' }, + fooFive: { type: 'Relation', targetClass: '_User' }, + fooSix: { type: 'String' }, + fooSeven: { type: 'Object' }, + fooEight: { type: 'String' }, + fooNine: { type: 'String' }, + fooTeen: { type: 'Number' }, + fooEleven: { type: 'String' }, + fooTwelve: { type: 'String' }, + fooThirteen: { type: 'String' }, + fooFourteen: { type: 'String' }, + fooFifteen: { type: 'String' }, + fooSixteen: { type: 'String' }, + fooEighteen: { type: 'String' }, + fooNineteen: { type: 'String' }, + }, + levelPermissions, + {}, + config.database + ); + expect(getSpy.calls.count()).toBe(3); + expect(putSpy.calls.count()).toBe(3); + expect(delSpy.calls.count()).toBe(0); - it('test schema update class', async () => { - const container = new Container(); - await container.save(); - - getSpy.calls.reset(); - putSpy.calls.reset(); - delSpy.calls.reset(); - - const config = Config.get('test'); - const schema = await config.database.loadSchema(); - await schema.reloadData(); - - const levelPermissions = { - find: { '*': true }, - get: { '*': true }, - create: { '*': true }, - update: { '*': true }, - delete: { '*': true }, - addField: { '*': true }, - protectedFields: { '*': [] }, - }; - - await schema.updateClass( - 'Container', - { - fooOne: { type: 'Number' }, - fooTwo: { type: 'Array' }, - fooThree: { type: 'Date' }, - fooFour: { type: 'Object' }, - fooFive: { type: 'Relation', targetClass: '_User' }, - fooSix: { type: 'String' }, - fooSeven: { type: 'Object' }, - fooEight: { type: 'String' }, - fooNine: { type: 'String' }, - fooTeen: { type: 'Number' }, - fooEleven: { type: 'String' }, - fooTwelve: { type: 'String' }, - fooThirteen: { type: 'String' }, - fooFourteen: { type: 'String' }, - fooFifteen: { type: 'String' }, - fooSixteen: { type: 'String' }, - fooEighteen: { type: 'String' }, - fooNineteen: { type: 'String' }, - }, - levelPermissions, - {}, - config.database - ); - expect(getSpy.calls.count()).toBe(3); - expect(putSpy.calls.count()).toBe(3); - expect(delSpy.calls.count()).toBe(0); - - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(1); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(1); + }); }); -}); +} From 650651083c43674ad05402774d4fb3eccdb8ad4b Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 19 Feb 2021 17:50:41 -0800 Subject: [PATCH 2/4] Remove for --- spec/RedisCacheAdapter.spec.js | 893 ++++++++++++++++----------------- 1 file changed, 446 insertions(+), 447 deletions(-) diff --git a/spec/RedisCacheAdapter.spec.js b/spec/RedisCacheAdapter.spec.js index 00a69d3fe6..7c88387a48 100644 --- a/spec/RedisCacheAdapter.spec.js +++ b/spec/RedisCacheAdapter.spec.js @@ -1,529 +1,528 @@ const RedisCacheAdapter = require('../lib/Adapters/Cache/RedisCacheAdapter').default; const Config = require('../lib/Config'); -for (let x = 0; x < 300; x++) { - /* + +/* To run this test part of the complete suite set PARSE_SERVER_TEST_CACHE='redis' and make sure a redis server is available on the default port */ - describe_only(() => { - return process.env.PARSE_SERVER_TEST_CACHE === 'redis'; - })('RedisCacheAdapter', function () { - const KEY = 'hello'; - const VALUE = 'world'; - - function wait(sleep) { - return new Promise(function (resolve) { - setTimeout(resolve, sleep); - }); - } - - it('should get/set/clear', done => { - const cache = new RedisCacheAdapter({ - ttl: NaN, - }); - - cache - .put(KEY, VALUE) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(VALUE)) - .then(() => cache.clear()) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(null)) - .then(done); +describe_only(() => { + return process.env.PARSE_SERVER_TEST_CACHE === 'redis'; +})('RedisCacheAdapter', function () { + const KEY = 'hello'; + const VALUE = 'world'; + + function wait(sleep) { + return new Promise(function (resolve) { + setTimeout(resolve, sleep); }); + } - it('should expire after ttl', done => { - const cache = new RedisCacheAdapter(null, 50); - - cache - .put(KEY, VALUE) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(VALUE)) - .then(wait.bind(null, 52)) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(null)) - .then(done); + it('should get/set/clear', done => { + const cache = new RedisCacheAdapter({ + ttl: NaN, }); - it('should not store value for ttl=0', done => { - const cache = new RedisCacheAdapter(null, 50); + cache + .put(KEY, VALUE) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(VALUE)) + .then(() => cache.clear()) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(null)) + .then(done); + }); - cache - .put(KEY, VALUE, 0) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(null)) - .then(done); - }); + it('should expire after ttl', done => { + const cache = new RedisCacheAdapter(null, 50); + + cache + .put(KEY, VALUE) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(VALUE)) + .then(wait.bind(null, 52)) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(null)) + .then(done); + }); - it('should not expire when ttl=Infinity', done => { - const cache = new RedisCacheAdapter(null, 50); - - cache - .put(KEY, VALUE, Infinity) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(VALUE)) - .then(wait.bind(null, 52)) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(VALUE)) - .then(done); - }); + it('should not store value for ttl=0', done => { + const cache = new RedisCacheAdapter(null, 50); - it('should fallback to default ttl', done => { - const cache = new RedisCacheAdapter(null, 50); - let promise = Promise.resolve(); - - [-100, null, undefined, 'not number', true].forEach(ttl => { - promise = promise.then(() => - cache - .put(KEY, VALUE, ttl) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(VALUE)) - .then(wait.bind(null, 52)) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(null)) - ); - }); + cache + .put(KEY, VALUE, 0) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(null)) + .then(done); + }); - promise.then(done); - }); + it('should not expire when ttl=Infinity', done => { + const cache = new RedisCacheAdapter(null, 50); + + cache + .put(KEY, VALUE, Infinity) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(VALUE)) + .then(wait.bind(null, 52)) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(VALUE)) + .then(done); + }); - it('should find un-expired records', done => { - const cache = new RedisCacheAdapter(null, 50); - - cache - .put(KEY, VALUE) - .then(() => cache.get(KEY)) - .then(value => expect(value).toEqual(VALUE)) - .then(wait.bind(null, 1)) - .then(() => cache.get(KEY)) - .then(value => expect(value).not.toEqual(null)) - .then(done); + it('should fallback to default ttl', done => { + const cache = new RedisCacheAdapter(null, 50); + let promise = Promise.resolve(); + + [-100, null, undefined, 'not number', true].forEach(ttl => { + promise = promise.then(() => + cache + .put(KEY, VALUE, ttl) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(VALUE)) + .then(wait.bind(null, 52)) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(null)) + ); }); - it('handleShutdown, close connection', async () => { - const cache = new RedisCacheAdapter(null, 50); + promise.then(done); + }); - await cache.handleShutdown(); - setTimeout(() => { - expect(cache.client.connected).toBe(false); - }, 0); - }); + it('should find un-expired records', done => { + const cache = new RedisCacheAdapter(null, 50); + + cache + .put(KEY, VALUE) + .then(() => cache.get(KEY)) + .then(value => expect(value).toEqual(VALUE)) + .then(wait.bind(null, 1)) + .then(() => cache.get(KEY)) + .then(value => expect(value).not.toEqual(null)) + .then(done); }); - describe_only(() => { - return process.env.PARSE_SERVER_TEST_CACHE === 'redis'; - })('RedisCacheAdapter/KeyPromiseQueue', function () { - const KEY1 = 'key1'; - const KEY2 = 'key2'; - const VALUE = 'hello'; + it('handleShutdown, close connection', async () => { + const cache = new RedisCacheAdapter(null, 50); - // number of chained ops on a single key - function getQueueCountForKey(cache, key) { - return cache.queue.queue[key][0]; + await cache.handleShutdown(); + setTimeout(() => { + expect(cache.client.connected).toBe(false); + }, 0); + }); +}); + +describe_only(() => { + return process.env.PARSE_SERVER_TEST_CACHE === 'redis'; +})('RedisCacheAdapter/KeyPromiseQueue', function () { + const KEY1 = 'key1'; + const KEY2 = 'key2'; + const VALUE = 'hello'; + + // number of chained ops on a single key + function getQueueCountForKey(cache, key) { + return cache.queue.queue[key][0]; + } + + // total number of queued keys + function getQueueCount(cache) { + return Object.keys(cache.queue.queue).length; + } + + it('it should clear completed operations from queue', done => { + const cache = new RedisCacheAdapter({ ttl: NaN }); + + // execute a bunch of operations in sequence + let promise = Promise.resolve(); + for (let index = 1; index < 100; index++) { + promise = promise.then(() => { + const key = `${index}`; + return cache + .put(key, VALUE) + .then(() => expect(getQueueCount(cache)).toEqual(0)) + .then(() => cache.get(key)) + .then(() => expect(getQueueCount(cache)).toEqual(0)) + .then(() => cache.clear()) + .then(() => expect(getQueueCount(cache)).toEqual(0)); + }); } - // total number of queued keys - function getQueueCount(cache) { - return Object.keys(cache.queue.queue).length; + // at the end the queue should be empty + promise.then(() => expect(getQueueCount(cache)).toEqual(0)).then(done); + }); + + it('it should count per key chained operations correctly', done => { + const cache = new RedisCacheAdapter({ ttl: NaN }); + + let key1Promise = Promise.resolve(); + let key2Promise = Promise.resolve(); + for (let index = 1; index < 100; index++) { + key1Promise = cache.put(KEY1, VALUE); + key2Promise = cache.put(KEY2, VALUE); + // per key chain should be equal to index, which is the + // total number of operations on that key + expect(getQueueCountForKey(cache, KEY1)).toEqual(index); + expect(getQueueCountForKey(cache, KEY2)).toEqual(index); + // the total keys counts should be equal to the different keys + // we have currently being processed. + expect(getQueueCount(cache)).toEqual(2); } - it('it should clear completed operations from queue', done => { - const cache = new RedisCacheAdapter({ ttl: NaN }); - - // execute a bunch of operations in sequence - let promise = Promise.resolve(); - for (let index = 1; index < 100; index++) { - promise = promise.then(() => { - const key = `${index}`; - return cache - .put(key, VALUE) - .then(() => expect(getQueueCount(cache)).toEqual(0)) - .then(() => cache.get(key)) - .then(() => expect(getQueueCount(cache)).toEqual(0)) - .then(() => cache.clear()) - .then(() => expect(getQueueCount(cache)).toEqual(0)); - }); - } - - // at the end the queue should be empty - promise.then(() => expect(getQueueCount(cache)).toEqual(0)).then(done); + // at the end the queue should be empty + Promise.all([key1Promise, key2Promise]) + .then(() => expect(getQueueCount(cache)).toEqual(0)) + .then(done); + }); +}); + +describe_only(() => { + return process.env.PARSE_SERVER_TEST_CACHE === 'redis'; +})('Redis Performance', function () { + let cacheAdapter; + let getSpy; + let putSpy; + let delSpy; + + beforeEach(async () => { + cacheAdapter = new RedisCacheAdapter(); + await reconfigureServer({ + cacheAdapter, }); + await cacheAdapter.clear(); - it('it should count per key chained operations correctly', done => { - const cache = new RedisCacheAdapter({ ttl: NaN }); - - let key1Promise = Promise.resolve(); - let key2Promise = Promise.resolve(); - for (let index = 1; index < 100; index++) { - key1Promise = cache.put(KEY1, VALUE); - key2Promise = cache.put(KEY2, VALUE); - // per key chain should be equal to index, which is the - // total number of operations on that key - expect(getQueueCountForKey(cache, KEY1)).toEqual(index); - expect(getQueueCountForKey(cache, KEY2)).toEqual(index); - // the total keys counts should be equal to the different keys - // we have currently being processed. - expect(getQueueCount(cache)).toEqual(2); - } - - // at the end the queue should be empty - Promise.all([key1Promise, key2Promise]) - .then(() => expect(getQueueCount(cache)).toEqual(0)) - .then(done); - }); + getSpy = spyOn(cacheAdapter, 'get').and.callThrough(); + putSpy = spyOn(cacheAdapter, 'put').and.callThrough(); + delSpy = spyOn(cacheAdapter, 'del').and.callThrough(); }); - describe_only(() => { - return process.env.PARSE_SERVER_TEST_CACHE === 'redis'; - })('Redis Performance', function () { - let cacheAdapter; - let getSpy; - let putSpy; - let delSpy; - - beforeEach(async () => { - cacheAdapter = new RedisCacheAdapter(); - await reconfigureServer({ - cacheAdapter, - }); - await cacheAdapter.clear(); + it('test new object', async () => { + const object = new TestObject(); + object.set('foo', 'bar'); + await object.save(); + expect(getSpy.calls.count()).toBe(3); + expect(putSpy.calls.count()).toBe(3); + expect(delSpy.calls.count()).toBe(1); - getSpy = spyOn(cacheAdapter, 'get').and.callThrough(); - putSpy = spyOn(cacheAdapter, 'put').and.callThrough(); - delSpy = spyOn(cacheAdapter, 'del').and.callThrough(); - }); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - it('test new object', async () => { - const object = new TestObject(); - object.set('foo', 'bar'); - await object.save(); - expect(getSpy.calls.count()).toBe(3); - expect(putSpy.calls.count()).toBe(3); - expect(delSpy.calls.count()).toBe(1); - - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); + it('test new object multiple fields', async () => { + const container = new Container({ + dateField: new Date(), + arrayField: [], + numberField: 1, + stringField: 'hello', + booleanField: true, }); + await container.save(); + expect(getSpy.calls.count()).toBe(3); + expect(putSpy.calls.count()).toBe(3); + expect(delSpy.calls.count()).toBe(1); - it('test new object multiple fields', async () => { - const container = new Container({ - dateField: new Date(), - arrayField: [], - numberField: 1, - stringField: 'hello', - booleanField: true, - }); - await container.save(); - expect(getSpy.calls.count()).toBe(3); - expect(putSpy.calls.count()).toBe(3); - expect(delSpy.calls.count()).toBe(1); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + it('test update existing fields', async () => { + const object = new TestObject(); + object.set('foo', 'bar'); + await object.save(); - it('test update existing fields', async () => { - const object = new TestObject(); - object.set('foo', 'bar'); - await object.save(); + getSpy.calls.reset(); + putSpy.calls.reset(); - getSpy.calls.reset(); - putSpy.calls.reset(); + object.set('foo', 'barz'); + await object.save(); + expect(getSpy.calls.count()).toBe(3); + expect(putSpy.calls.count()).toBe(1); + expect(delSpy.calls.count()).toBe(2); - object.set('foo', 'barz'); - await object.save(); - expect(getSpy.calls.count()).toBe(3); - expect(putSpy.calls.count()).toBe(1); - expect(delSpy.calls.count()).toBe(2); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + it('test saveAll / destroyAll', async () => { + const object = new TestObject(); + await object.save(); - it('test saveAll / destroyAll', async () => { - const object = new TestObject(); - await object.save(); - - getSpy.calls.reset(); - putSpy.calls.reset(); - - const objects = []; - for (let i = 0; i < 10; i++) { - const object = new TestObject(); - object.set('number', i); - objects.push(object); - } - await Parse.Object.saveAll(objects); - expect(getSpy.calls.count()).toBe(21); - expect(putSpy.calls.count()).toBe(11); - - getSpy.calls.reset(); - putSpy.calls.reset(); - - await Parse.Object.destroyAll(objects); - expect(getSpy.calls.count()).toBe(11); - expect(putSpy.calls.count()).toBe(1); - expect(delSpy.calls.count()).toBe(3); - - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + getSpy.calls.reset(); + putSpy.calls.reset(); - it('test saveAll / destroyAll batch', async () => { + const objects = []; + for (let i = 0; i < 10; i++) { const object = new TestObject(); - await object.save(); - - getSpy.calls.reset(); - putSpy.calls.reset(); - - const objects = []; - for (let i = 0; i < 10; i++) { - const object = new TestObject(); - object.set('number', i); - objects.push(object); - } - await Parse.Object.saveAll(objects, { batchSize: 5 }); - expect(getSpy.calls.count()).toBe(22); - expect(putSpy.calls.count()).toBe(7); - - getSpy.calls.reset(); - putSpy.calls.reset(); - - await Parse.Object.destroyAll(objects, { batchSize: 5 }); - expect(getSpy.calls.count()).toBe(12); - expect(putSpy.calls.count()).toBe(2); - expect(delSpy.calls.count()).toBe(5); - - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + object.set('number', i); + objects.push(object); + } + await Parse.Object.saveAll(objects); + expect(getSpy.calls.count()).toBe(21); + expect(putSpy.calls.count()).toBe(11); - it('test add new field to existing object', async () => { - const object = new TestObject(); - object.set('foo', 'bar'); - await object.save(); + getSpy.calls.reset(); + putSpy.calls.reset(); - getSpy.calls.reset(); - putSpy.calls.reset(); + await Parse.Object.destroyAll(objects); + expect(getSpy.calls.count()).toBe(11); + expect(putSpy.calls.count()).toBe(1); + expect(delSpy.calls.count()).toBe(3); - object.set('new', 'barz'); - await object.save(); - expect(getSpy.calls.count()).toBe(3); - expect(putSpy.calls.count()).toBe(2); - expect(delSpy.calls.count()).toBe(2); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + it('test saveAll / destroyAll batch', async () => { + const object = new TestObject(); + await object.save(); - it('test add multiple fields to existing object', async () => { + getSpy.calls.reset(); + putSpy.calls.reset(); + + const objects = []; + for (let i = 0; i < 10; i++) { const object = new TestObject(); - object.set('foo', 'bar'); - await object.save(); - - getSpy.calls.reset(); - putSpy.calls.reset(); - - object.set({ - dateField: new Date(), - arrayField: [], - numberField: 1, - stringField: 'hello', - booleanField: true, - }); - await object.save(); - expect(getSpy.calls.count()).toBe(3); - expect(putSpy.calls.count()).toBe(2); - expect(delSpy.calls.count()).toBe(2); + object.set('number', i); + objects.push(object); + } + await Parse.Object.saveAll(objects, { batchSize: 5 }); + expect(getSpy.calls.count()).toBe(22); + expect(putSpy.calls.count()).toBe(7); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + getSpy.calls.reset(); + putSpy.calls.reset(); - it('test user', async () => { - const user = new Parse.User(); - user.setUsername('testing'); - user.setPassword('testing'); - await user.signUp(); + await Parse.Object.destroyAll(objects, { batchSize: 5 }); + expect(getSpy.calls.count()).toBe(12); + expect(putSpy.calls.count()).toBe(2); + expect(delSpy.calls.count()).toBe(5); - expect(getSpy.calls.count()).toBe(8); - expect(putSpy.calls.count()).toBe(2); - expect(delSpy.calls.count()).toBe(1); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + it('test add new field to existing object', async () => { + const object = new TestObject(); + object.set('foo', 'bar'); + await object.save(); - it('test allowClientCreation false', async () => { - const object = new TestObject(); - await object.save(); - await reconfigureServer({ - cacheAdapter, - allowClientClassCreation: false, - }); - await cacheAdapter.clear(); + getSpy.calls.reset(); + putSpy.calls.reset(); - getSpy.calls.reset(); - putSpy.calls.reset(); - delSpy.calls.reset(); + object.set('new', 'barz'); + await object.save(); + expect(getSpy.calls.count()).toBe(3); + expect(putSpy.calls.count()).toBe(2); + expect(delSpy.calls.count()).toBe(2); - object.set('foo', 'bar'); - await object.save(); - expect(getSpy.calls.count()).toBe(4); - expect(putSpy.calls.count()).toBe(2); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - getSpy.calls.reset(); - putSpy.calls.reset(); + it('test add multiple fields to existing object', async () => { + const object = new TestObject(); + object.set('foo', 'bar'); + await object.save(); - const query = new Parse.Query(TestObject); - await query.get(object.id); - expect(getSpy.calls.count()).toBe(3); - expect(putSpy.calls.count()).toBe(1); - expect(delSpy.calls.count()).toBe(2); + getSpy.calls.reset(); + putSpy.calls.reset(); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); + object.set({ + dateField: new Date(), + arrayField: [], + numberField: 1, + stringField: 'hello', + booleanField: true, }); + await object.save(); + expect(getSpy.calls.count()).toBe(3); + expect(putSpy.calls.count()).toBe(2); + expect(delSpy.calls.count()).toBe(2); - it('test query', async () => { - const object = new TestObject(); - object.set('foo', 'bar'); - await object.save(); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - getSpy.calls.reset(); - putSpy.calls.reset(); - delSpy.calls.reset(); + it('test user', async () => { + const user = new Parse.User(); + user.setUsername('testing'); + user.setPassword('testing'); + await user.signUp(); - const query = new Parse.Query(TestObject); - await query.get(object.id); - expect(getSpy.calls.count()).toBe(2); - expect(putSpy.calls.count()).toBe(1); - expect(delSpy.calls.count()).toBe(1); + expect(getSpy.calls.count()).toBe(8); + expect(putSpy.calls.count()).toBe(2); + expect(delSpy.calls.count()).toBe(1); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); + + it('test allowClientCreation false', async () => { + const object = new TestObject(); + await object.save(); + await reconfigureServer({ + cacheAdapter, + allowClientClassCreation: false, }); + await cacheAdapter.clear(); - it('test query include', async () => { - const child = new TestObject(); - await child.save(); + getSpy.calls.reset(); + putSpy.calls.reset(); + delSpy.calls.reset(); - const object = new TestObject(); - object.set('child', child); - await object.save(); + object.set('foo', 'bar'); + await object.save(); + expect(getSpy.calls.count()).toBe(4); + expect(putSpy.calls.count()).toBe(2); + + getSpy.calls.reset(); + putSpy.calls.reset(); - getSpy.calls.reset(); - putSpy.calls.reset(); + const query = new Parse.Query(TestObject); + await query.get(object.id); + expect(getSpy.calls.count()).toBe(3); + expect(putSpy.calls.count()).toBe(1); + expect(delSpy.calls.count()).toBe(2); - const query = new Parse.Query(TestObject); - query.include('child'); - await query.get(object.id); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - expect(getSpy.calls.count()).toBe(4); - expect(putSpy.calls.count()).toBe(1); - expect(delSpy.calls.count()).toBe(3); + it('test query', async () => { + const object = new TestObject(); + object.set('foo', 'bar'); + await object.save(); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + getSpy.calls.reset(); + putSpy.calls.reset(); + delSpy.calls.reset(); - it('query relation without schema', async () => { - const child = new Parse.Object('ChildObject'); - await child.save(); + const query = new Parse.Query(TestObject); + await query.get(object.id); + expect(getSpy.calls.count()).toBe(2); + expect(putSpy.calls.count()).toBe(1); + expect(delSpy.calls.count()).toBe(1); - const parent = new Parse.Object('ParentObject'); - const relation = parent.relation('child'); - relation.add(child); - await parent.save(); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - getSpy.calls.reset(); - putSpy.calls.reset(); + it('test query include', async () => { + const child = new TestObject(); + await child.save(); - const objects = await relation.query().find(); - expect(objects.length).toBe(1); - expect(objects[0].id).toBe(child.id); + const object = new TestObject(); + object.set('child', child); + await object.save(); - expect(getSpy.calls.count()).toBe(2); - expect(putSpy.calls.count()).toBe(1); - expect(delSpy.calls.count()).toBe(3); + getSpy.calls.reset(); + putSpy.calls.reset(); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + const query = new Parse.Query(TestObject); + query.include('child'); + await query.get(object.id); - it('test delete object', async () => { - const object = new TestObject(); - object.set('foo', 'bar'); - await object.save(); + expect(getSpy.calls.count()).toBe(4); + expect(putSpy.calls.count()).toBe(1); + expect(delSpy.calls.count()).toBe(3); - getSpy.calls.reset(); - putSpy.calls.reset(); - delSpy.calls.reset(); + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); - await object.destroy(); - expect(getSpy.calls.count()).toBe(2); - expect(putSpy.calls.count()).toBe(1); - expect(delSpy.calls.count()).toBe(1); + it('query relation without schema', async () => { + const child = new Parse.Object('ChildObject'); + await child.save(); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(0); - }); + const parent = new Parse.Object('ParentObject'); + const relation = parent.relation('child'); + relation.add(child); + await parent.save(); - it('test schema update class', async () => { - const container = new Container(); - await container.save(); - - getSpy.calls.reset(); - putSpy.calls.reset(); - delSpy.calls.reset(); - - const config = Config.get('test'); - const schema = await config.database.loadSchema(); - await schema.reloadData(); - - const levelPermissions = { - find: { '*': true }, - get: { '*': true }, - create: { '*': true }, - update: { '*': true }, - delete: { '*': true }, - addField: { '*': true }, - protectedFields: { '*': [] }, - }; - - await schema.updateClass( - 'Container', - { - fooOne: { type: 'Number' }, - fooTwo: { type: 'Array' }, - fooThree: { type: 'Date' }, - fooFour: { type: 'Object' }, - fooFive: { type: 'Relation', targetClass: '_User' }, - fooSix: { type: 'String' }, - fooSeven: { type: 'Object' }, - fooEight: { type: 'String' }, - fooNine: { type: 'String' }, - fooTeen: { type: 'Number' }, - fooEleven: { type: 'String' }, - fooTwelve: { type: 'String' }, - fooThirteen: { type: 'String' }, - fooFourteen: { type: 'String' }, - fooFifteen: { type: 'String' }, - fooSixteen: { type: 'String' }, - fooEighteen: { type: 'String' }, - fooNineteen: { type: 'String' }, - }, - levelPermissions, - {}, - config.database - ); - expect(getSpy.calls.count()).toBe(3); - expect(putSpy.calls.count()).toBe(3); - expect(delSpy.calls.count()).toBe(0); + getSpy.calls.reset(); + putSpy.calls.reset(); - const keys = await cacheAdapter.getAllKeys(); - expect(keys.length).toBe(1); - }); + const objects = await relation.query().find(); + expect(objects.length).toBe(1); + expect(objects[0].id).toBe(child.id); + + expect(getSpy.calls.count()).toBe(2); + expect(putSpy.calls.count()).toBe(1); + expect(delSpy.calls.count()).toBe(3); + + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); + + it('test delete object', async () => { + const object = new TestObject(); + object.set('foo', 'bar'); + await object.save(); + + getSpy.calls.reset(); + putSpy.calls.reset(); + delSpy.calls.reset(); + + await object.destroy(); + expect(getSpy.calls.count()).toBe(2); + expect(putSpy.calls.count()).toBe(1); + expect(delSpy.calls.count()).toBe(1); + + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(0); + }); + + it('test schema update class', async () => { + const container = new Container(); + await container.save(); + + getSpy.calls.reset(); + putSpy.calls.reset(); + delSpy.calls.reset(); + + const config = Config.get('test'); + const schema = await config.database.loadSchema(); + await schema.reloadData(); + + const levelPermissions = { + find: { '*': true }, + get: { '*': true }, + create: { '*': true }, + update: { '*': true }, + delete: { '*': true }, + addField: { '*': true }, + protectedFields: { '*': [] }, + }; + + await schema.updateClass( + 'Container', + { + fooOne: { type: 'Number' }, + fooTwo: { type: 'Array' }, + fooThree: { type: 'Date' }, + fooFour: { type: 'Object' }, + fooFive: { type: 'Relation', targetClass: '_User' }, + fooSix: { type: 'String' }, + fooSeven: { type: 'Object' }, + fooEight: { type: 'String' }, + fooNine: { type: 'String' }, + fooTeen: { type: 'Number' }, + fooEleven: { type: 'String' }, + fooTwelve: { type: 'String' }, + fooThirteen: { type: 'String' }, + fooFourteen: { type: 'String' }, + fooFifteen: { type: 'String' }, + fooSixteen: { type: 'String' }, + fooEighteen: { type: 'String' }, + fooNineteen: { type: 'String' }, + }, + levelPermissions, + {}, + config.database + ); + expect(getSpy.calls.count()).toBe(3); + expect(putSpy.calls.count()).toBe(3); + expect(delSpy.calls.count()).toBe(0); + + const keys = await cacheAdapter.getAllKeys(); + expect(keys.length).toBe(1); }); -} +}); From bb337d1a99d486d1641b784d5043fd7f6e581e5c Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 19 Feb 2021 18:02:01 -0800 Subject: [PATCH 3/4] Increase little bit more one of the tests since it requires two calls to be done in time-fahsion way --- spec/RedisCacheAdapter.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/RedisCacheAdapter.spec.js b/spec/RedisCacheAdapter.spec.js index 7c88387a48..387262b3f8 100644 --- a/spec/RedisCacheAdapter.spec.js +++ b/spec/RedisCacheAdapter.spec.js @@ -89,7 +89,7 @@ describe_only(() => { }); it('should find un-expired records', done => { - const cache = new RedisCacheAdapter(null, 50); + const cache = new RedisCacheAdapter(null, 100); cache .put(KEY, VALUE) From f5df018fc2ef7108773e202d42557d25811bfdcb Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Fri, 19 Feb 2021 18:32:58 -0800 Subject: [PATCH 4/4] increase default ttl a bit more --- spec/RedisCacheAdapter.spec.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/RedisCacheAdapter.spec.js b/spec/RedisCacheAdapter.spec.js index 387262b3f8..ac5c209c82 100644 --- a/spec/RedisCacheAdapter.spec.js +++ b/spec/RedisCacheAdapter.spec.js @@ -34,20 +34,20 @@ describe_only(() => { }); it('should expire after ttl', done => { - const cache = new RedisCacheAdapter(null, 50); + const cache = new RedisCacheAdapter(null, 100); cache .put(KEY, VALUE) .then(() => cache.get(KEY)) .then(value => expect(value).toEqual(VALUE)) - .then(wait.bind(null, 52)) + .then(wait.bind(null, 102)) .then(() => cache.get(KEY)) .then(value => expect(value).toEqual(null)) .then(done); }); it('should not store value for ttl=0', done => { - const cache = new RedisCacheAdapter(null, 50); + const cache = new RedisCacheAdapter(null, 100); cache .put(KEY, VALUE, 0) @@ -57,20 +57,20 @@ describe_only(() => { }); it('should not expire when ttl=Infinity', done => { - const cache = new RedisCacheAdapter(null, 50); + const cache = new RedisCacheAdapter(null, 100); cache .put(KEY, VALUE, Infinity) .then(() => cache.get(KEY)) .then(value => expect(value).toEqual(VALUE)) - .then(wait.bind(null, 52)) + .then(wait.bind(null, 102)) .then(() => cache.get(KEY)) .then(value => expect(value).toEqual(VALUE)) .then(done); }); it('should fallback to default ttl', done => { - const cache = new RedisCacheAdapter(null, 50); + const cache = new RedisCacheAdapter(null, 100); let promise = Promise.resolve(); [-100, null, undefined, 'not number', true].forEach(ttl => { @@ -79,7 +79,7 @@ describe_only(() => { .put(KEY, VALUE, ttl) .then(() => cache.get(KEY)) .then(value => expect(value).toEqual(VALUE)) - .then(wait.bind(null, 52)) + .then(wait.bind(null, 102)) .then(() => cache.get(KEY)) .then(value => expect(value).toEqual(null)) ); @@ -102,7 +102,7 @@ describe_only(() => { }); it('handleShutdown, close connection', async () => { - const cache = new RedisCacheAdapter(null, 50); + const cache = new RedisCacheAdapter(null, 100); await cache.handleShutdown(); setTimeout(() => {