From 188ae56a2150dfb791f03979829de22787029382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Tue, 5 Mar 2024 14:53:29 +0100 Subject: [PATCH 1/3] add test scenarios for collection operations data persistence --- packages/minimongo/local_collection.js | 12 +++ packages/mongo/mongo_livedata_tests.js | 110 +++++++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/packages/minimongo/local_collection.js b/packages/minimongo/local_collection.js index 43877fb87e..9f0f4a9193 100644 --- a/packages/minimongo/local_collection.js +++ b/packages/minimongo/local_collection.js @@ -160,6 +160,10 @@ export default class LocalCollection { return id; } + insertAsync(doc, callback) { + return new Promise(resolve => resolve(this.insert(doc, callback))); + } + // Pause the observers. No callbacks from observers will fire until // 'resumeObservers' is called. pauseObservers() { @@ -273,6 +277,10 @@ export default class LocalCollection { return result; } + removeAsync(selector, callback) { + return new Promise(resolve => resolve(this.remove(selector, callback))); + } + // Resume the observers. Observers immediately receive change // notifications to bring them to the current state of the // database. Note that this is not just replaying all the changes that @@ -482,6 +490,10 @@ export default class LocalCollection { return result; } + updateAsync(selector, mod, options, callback) { + return new Promise(resolve => resolve(this.update(selector, mod, options, callback))); + } + // A convenience wrapper on update. LocalCollection.upsert(sel, mod) is // equivalent to LocalCollection.update(sel, mod, {upsert: true, // _returnObject: true}). diff --git a/packages/mongo/mongo_livedata_tests.js b/packages/mongo/mongo_livedata_tests.js index c6a2484728..02f23e9453 100644 --- a/packages/mongo/mongo_livedata_tests.js +++ b/packages/mongo/mongo_livedata_tests.js @@ -3496,3 +3496,113 @@ if (Meteor.isServer) { }); }); } + +testAsyncMulti('mongo-livedata - collection operations data persistence', [ + async function (test) { // Using remote collection + const Collection = new Mongo.Collection( + `remoteop_persistence${test.runId()}`, + ); + + await Collection.insertAsync({ _id: 'a' }); + await Collection.updateAsync({ _id: 'a' }, { $set: { num: 1 } }); + const insertedId = await Collection.insertAsync({ num: 2 }); + + let items = await Collection.find().fetchAsync(); + let itemIds = items.map(_item => _item._id); + test.equal(itemIds, ['a', insertedId]); // temporary data accessible + + const aItem = items[0]; + const insertedItem = items[1]; + test.equal(aItem?.num, 1); + test.equal(insertedItem?.num, 2); + + await Collection.removeAsync({ _id: insertedId }); + + items = await Collection.find().fetchAsync(); + itemIds = items.map(_item => _item._id); + + test.equal(itemIds, ['a']); // temporary data accessible + + if (Meteor.isClient) { + return new Promise(resolve => { + Meteor.setTimeout(async () => { + items = await Collection.find().fetchAsync(); + itemIds = items.map(_item => _item._id); + test.equal(itemIds, []); // data IS NOT persisted + resolve(); + }, 100); + }); + } + + return Promise.resolve(); + }, + async function (test) { // Using local collection + const Collection = new Mongo.Collection( + `localop_persistence${test.runId()}`, + ); + + await Collection._collection.insertAsync({ _id: 'a' }); + await Collection._collection.updateAsync({ _id: 'a' }, { $set: { num: 1 } }); + const insertedId = await Collection._collection.insertAsync({ num: 2 }); + + let items = await Collection.find().fetchAsync(); + let itemIds = items.map(_item => _item._id); + test.equal(itemIds, ['a', insertedId]); // temporary data accessible + + const aItem = items[0]; + const insertedItem = items[1]; + test.equal(aItem?.num, 1); + test.equal(insertedItem?.num, 2); + + await Collection._collection.removeAsync({ _id: insertedId }); + + items = await Collection.find().fetchAsync(); + itemIds = items.map(_item => _item._id); + + test.equal(itemIds, ['a']); // temporary data accessible + + if (Meteor.isClient) { + return new Promise(resolve => { + Meteor.setTimeout(async () => { + items = await Collection.find().fetchAsync(); + itemIds = items.map(_item => _item._id); + test.equal(itemIds, ['a']); // data is persisted + resolve(); + }, 100); + }); + } + + return Promise.resolve(); + }, + async function (test) { // Using methods + const Collection = new Mongo.Collection( + `methodop_persistence${test.runId()}`, + ); + + Meteor.methods({ + [`insertMethodPersistence${test.runId()}`]: async () => { + await Collection.insertAsync({ _id: 'a' }); + }, + }); + + Meteor.callAsync(`insertMethodPersistence${test.runId()}`); + + let items = await Collection.find().fetchAsync(); + let itemIds = items.map(_item => _item._id); + + test.equal(itemIds, ['a']); // temporary data accessible + + if (Meteor.isClient) { + return new Promise(resolve => { + Meteor.setTimeout(async () => { + items = await Collection.find().fetchAsync(); + itemIds = items.map(_item => _item._id); + test.equal(itemIds, []); // data IS NOT persisted + resolve(); + }, 100); + }); + } + + return Promise.resolve(); + }, +]); From 7348b6861ce73b6b85994a098fc2242704c2ed4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Tue, 5 Mar 2024 14:59:27 +0100 Subject: [PATCH 2/3] better name --- packages/mongo/mongo_livedata_tests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mongo/mongo_livedata_tests.js b/packages/mongo/mongo_livedata_tests.js index 02f23e9453..2c1b074872 100644 --- a/packages/mongo/mongo_livedata_tests.js +++ b/packages/mongo/mongo_livedata_tests.js @@ -3497,7 +3497,7 @@ if (Meteor.isServer) { }); } -testAsyncMulti('mongo-livedata - collection operations data persistence', [ +testAsyncMulti('mongo-livedata - collection async operations data persistence', [ async function (test) { // Using remote collection const Collection = new Mongo.Collection( `remoteop_persistence${test.runId()}`, From 0f39e55883cfbb84772dc02986943a95c9ad671f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Wed, 6 Mar 2024 16:21:33 +0100 Subject: [PATCH 3/3] add sync version --- packages/mongo/mongo_livedata_tests.js | 126 +++++++++++++++++++++++-- 1 file changed, 118 insertions(+), 8 deletions(-) diff --git a/packages/mongo/mongo_livedata_tests.js b/packages/mongo/mongo_livedata_tests.js index 2c1b074872..38ec93a36a 100644 --- a/packages/mongo/mongo_livedata_tests.js +++ b/packages/mongo/mongo_livedata_tests.js @@ -3497,6 +3497,116 @@ if (Meteor.isServer) { }); } +testAsyncMulti('mongo-livedata - collection sync operations data persistence', [ + function (test) { // Using remote collection + const Collection = new Mongo.Collection( + `remotesyncop_persistence${test.runId()}`, + ); + + Collection.insert({ _id: 'a' }); + Collection.update({ _id: 'a' }, { $set: { num: 1 } }); + const insertedId = Collection.insert({ num: 2 }); + + let items = Collection.find().fetch(); + let itemIds = items.map(_item => _item._id); + test.equal(itemIds, ['a', insertedId]); // temporary data accessible (optimistic-ui) + + const aItem = items[0]; + const insertedItem = items[1]; + test.equal(aItem?.num, 1); + test.equal(insertedItem?.num, 2); + + Collection.remove({ _id: insertedId }); + + items = Collection.find().fetch(); + itemIds = items.map(_item => _item._id); + + test.equal(itemIds, ['a']); // temporary data accessible (optimistic-ui) + + if (Meteor.isClient) { + return new Promise(resolve => { + Meteor.setTimeout(async () => { + items = Collection.find().fetch(); + itemIds = items.map(_item => _item._id); + test.equal(itemIds, []); // data IS NOT persisted + resolve(); + }, 10); + }); + } + + return Promise.resolve(); + }, + async function (test) { // Using local collection + const Collection = new Mongo.Collection( + `localsyncop_persistence${test.runId()}`, + ); + + Collection._collection.insert({ _id: 'a' }); + Collection._collection.update({ _id: 'a' }, { $set: { num: 1 } }); + const insertedId = Collection._collection.insert({ num: 2 }); + + let items = Collection.find().fetch(); + let itemIds = items.map(_item => _item._id); + test.equal(itemIds, ['a', insertedId]); // temporary data accessible (optimistic-ui) + + const aItem = items[0]; + const insertedItem = items[1]; + test.equal(aItem?.num, 1); + test.equal(insertedItem?.num, 2); + + Collection._collection.remove({ _id: insertedId }); + + items = Collection.find().fetch(); + itemIds = items.map(_item => _item._id); + + test.equal(itemIds, ['a']); // temporary data accessible (optimistic-ui) + + if (Meteor.isClient) { + return new Promise(resolve => { + Meteor.setTimeout(() => { + items = Collection.find().fetch(); + itemIds = items.map(_item => _item._id); + test.equal(itemIds, ['a']); // data is persisted + resolve(); + }, 10); + }); + } + + return Promise.resolve(); + }, + function (test) { // Using methods + const Collection = new Mongo.Collection( + `methodsyncop_persistence${test.runId()}`, + ); + + Meteor.methods({ + [`insertSyncMethodPersistence${test.runId()}`]: async () => { + Collection.insert({ _id: 'a' }); + }, + }); + + Meteor.call(`insertSyncMethodPersistence${test.runId()}`); + + let items = Collection.find().fetch(); + let itemIds = items.map(_item => _item._id); + + test.equal(itemIds, ['a']); // temporary data accessible (optimistic-ui) + + if (Meteor.isClient) { + return new Promise(resolve => { + Meteor.setTimeout(() => { + items = Collection.find().fetch(); + itemIds = items.map(_item => _item._id); + test.equal(itemIds, []); // data IS NOT persisted + resolve(); + }, 10); + }); + } + + return Promise.resolve(); + }, +]); + testAsyncMulti('mongo-livedata - collection async operations data persistence', [ async function (test) { // Using remote collection const Collection = new Mongo.Collection( @@ -3509,7 +3619,7 @@ testAsyncMulti('mongo-livedata - collection async operations data persistence', let items = await Collection.find().fetchAsync(); let itemIds = items.map(_item => _item._id); - test.equal(itemIds, ['a', insertedId]); // temporary data accessible + test.equal(itemIds, ['a', insertedId]); // temporary data accessible (optimistic-ui) const aItem = items[0]; const insertedItem = items[1]; @@ -3521,7 +3631,7 @@ testAsyncMulti('mongo-livedata - collection async operations data persistence', items = await Collection.find().fetchAsync(); itemIds = items.map(_item => _item._id); - test.equal(itemIds, ['a']); // temporary data accessible + test.equal(itemIds, ['a']); // temporary data accessible (optimistic-ui) if (Meteor.isClient) { return new Promise(resolve => { @@ -3530,7 +3640,7 @@ testAsyncMulti('mongo-livedata - collection async operations data persistence', itemIds = items.map(_item => _item._id); test.equal(itemIds, []); // data IS NOT persisted resolve(); - }, 100); + }, 10); }); } @@ -3547,7 +3657,7 @@ testAsyncMulti('mongo-livedata - collection async operations data persistence', let items = await Collection.find().fetchAsync(); let itemIds = items.map(_item => _item._id); - test.equal(itemIds, ['a', insertedId]); // temporary data accessible + test.equal(itemIds, ['a', insertedId]); // temporary data accessible (optimistic-ui) const aItem = items[0]; const insertedItem = items[1]; @@ -3559,7 +3669,7 @@ testAsyncMulti('mongo-livedata - collection async operations data persistence', items = await Collection.find().fetchAsync(); itemIds = items.map(_item => _item._id); - test.equal(itemIds, ['a']); // temporary data accessible + test.equal(itemIds, ['a']); // temporary data accessible (optimistic-ui) if (Meteor.isClient) { return new Promise(resolve => { @@ -3568,7 +3678,7 @@ testAsyncMulti('mongo-livedata - collection async operations data persistence', itemIds = items.map(_item => _item._id); test.equal(itemIds, ['a']); // data is persisted resolve(); - }, 100); + }, 10); }); } @@ -3590,7 +3700,7 @@ testAsyncMulti('mongo-livedata - collection async operations data persistence', let items = await Collection.find().fetchAsync(); let itemIds = items.map(_item => _item._id); - test.equal(itemIds, ['a']); // temporary data accessible + test.equal(itemIds, ['a']); // temporary data accessible (optimistic-ui) if (Meteor.isClient) { return new Promise(resolve => { @@ -3599,7 +3709,7 @@ testAsyncMulti('mongo-livedata - collection async operations data persistence', itemIds = items.map(_item => _item._id); test.equal(itemIds, []); // data IS NOT persisted resolve(); - }, 100); + }, 10); }); }