From 622039ce25203104c56e54a278a75b4519d5e33e Mon Sep 17 00:00:00 2001 From: Andrew Bulat Date: Fri, 31 Jan 2025 05:09:57 +0000 Subject: [PATCH] Run LiveObjects tests on all transports and protocols (MsgPack and JSON) Only the tests that interact with the realtime server are marked to run using `SharedHelper.testOnAllTransportsAndProtocols` function. Tests that rely on private `channel.processMessage` calls to inject forged state messages are not included. Resolves DTP-1096 --- test/realtime/live_objects.test.js | 426 +++++++++++++++++------------ 1 file changed, 250 insertions(+), 176 deletions(-) diff --git a/test/realtime/live_objects.test.js b/test/realtime/live_objects.test.js index 9cfa0ea88..13f320e83 100644 --- a/test/realtime/live_objects.test.js +++ b/test/realtime/live_objects.test.js @@ -34,14 +34,29 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], expect(object.constructor.name).to.match(new RegExp(`_?${className}`), msg); } - function forScenarios(scenarios, testFn) { + function forScenarios(thisInDescribe, scenarios, testFn) { for (const scenario of scenarios) { - const itFn = scenario.skip ? it.skip : scenario.only ? it.only : it; + if (scenario.allTransportsAndProtocols) { + Helper.testOnAllTransportsAndProtocols( + thisInDescribe, + scenario.description, + function (options, channelName) { + return async function () { + const helper = this.test.helper; + await testFn(helper, scenario, options, channelName); + }; + }, + scenario.skip, + scenario.only, + ); + } else { + const itFn = scenario.skip ? it.skip : scenario.only ? it.only : it; - itFn(scenario.description, async function () { - const helper = this.test.helper; - await testFn(helper, scenario); - }); + itFn(scenario.description, async function () { + const helper = this.test.helper; + await testFn(helper, scenario, {}, scenario.description); + }); + } } } @@ -135,7 +150,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], await Promise.all(expectedKeys.map((key) => (root.get(key) ? undefined : waitForMapKeyUpdate(root, key)))); } - describe('realtime/live_objects', function () { + describe.only('realtime/live_objects', function () { this.timeout(60 * 1000); before(function (done) { @@ -404,175 +419,209 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }); /** @nospec */ - it('builds state object tree from STATE_SYNC sequence on channel attachment', async function () { - const helper = this.test.helper; - const client = RealtimeWithLiveObjects(helper); - - await helper.monitorConnectionThenCloseAndFinish(async () => { - await waitFixtureChannelIsReady(client); - - const channel = client.channels.get(liveObjectsFixturesChannel, channelOptionsWithLiveObjects()); - const liveObjects = channel.liveObjects; - - await channel.attach(); - const root = await liveObjects.getRoot(); - - const counterKeys = ['emptyCounter', 'initialValueCounter', 'referencedCounter']; - const mapKeys = ['emptyMap', 'referencedMap', 'valuesMap']; - const rootKeysCount = counterKeys.length + mapKeys.length; - - expect(root, 'Check getRoot() is resolved when STATE_SYNC sequence ends').to.exist; - expect(root.size()).to.equal(rootKeysCount, 'Check root has correct number of keys'); - - counterKeys.forEach((key) => { - const counter = root.get(key); - expect(counter, `Check counter at key="${key}" in root exists`).to.exist; - expectInstanceOf(counter, 'LiveCounter', `Check counter at key="${key}" in root is of type LiveCounter`); - }); + Helper.testOnAllTransportsAndProtocols( + this, + 'builds state object tree from STATE_SYNC sequence on channel attachment', + function (options, channelName) { + return async function () { + const helper = this.test.helper; + const client = RealtimeWithLiveObjects(helper, options); + + await helper.monitorConnectionThenCloseAndFinish(async () => { + await waitFixtureChannelIsReady(client); + + const channel = client.channels.get(liveObjectsFixturesChannel, channelOptionsWithLiveObjects()); + const liveObjects = channel.liveObjects; + + await channel.attach(); + const root = await liveObjects.getRoot(); + + const counterKeys = ['emptyCounter', 'initialValueCounter', 'referencedCounter']; + const mapKeys = ['emptyMap', 'referencedMap', 'valuesMap']; + const rootKeysCount = counterKeys.length + mapKeys.length; + + expect(root, 'Check getRoot() is resolved when STATE_SYNC sequence ends').to.exist; + expect(root.size()).to.equal(rootKeysCount, 'Check root has correct number of keys'); + + counterKeys.forEach((key) => { + const counter = root.get(key); + expect(counter, `Check counter at key="${key}" in root exists`).to.exist; + expectInstanceOf( + counter, + 'LiveCounter', + `Check counter at key="${key}" in root is of type LiveCounter`, + ); + }); - mapKeys.forEach((key) => { - const map = root.get(key); - expect(map, `Check map at key="${key}" in root exists`).to.exist; - expectInstanceOf(map, 'LiveMap', `Check map at key="${key}" in root is of type LiveMap`); - }); + mapKeys.forEach((key) => { + const map = root.get(key); + expect(map, `Check map at key="${key}" in root exists`).to.exist; + expectInstanceOf(map, 'LiveMap', `Check map at key="${key}" in root is of type LiveMap`); + }); - const valuesMap = root.get('valuesMap'); - const valueMapKeys = [ - 'stringKey', - 'emptyStringKey', - 'bytesKey', - 'emptyBytesKey', - 'numberKey', - 'zeroKey', - 'trueKey', - 'falseKey', - 'mapKey', - ]; - expect(valuesMap.size()).to.equal(valueMapKeys.length, 'Check nested map has correct number of keys'); - valueMapKeys.forEach((key) => { - const value = valuesMap.get(key); - expect(value, `Check value at key="${key}" in nested map exists`).to.exist; - }); - }, client); - }); + const valuesMap = root.get('valuesMap'); + const valueMapKeys = [ + 'stringKey', + 'emptyStringKey', + 'bytesKey', + 'emptyBytesKey', + 'numberKey', + 'zeroKey', + 'trueKey', + 'falseKey', + 'mapKey', + ]; + expect(valuesMap.size()).to.equal(valueMapKeys.length, 'Check nested map has correct number of keys'); + valueMapKeys.forEach((key) => { + const value = valuesMap.get(key); + expect(value, `Check value at key="${key}" in nested map exists`).to.exist; + }); + }, client); + }; + }, + ); /** @nospec */ - it('LiveCounter is initialized with initial value from STATE_SYNC sequence', async function () { - const helper = this.test.helper; - const client = RealtimeWithLiveObjects(helper); - - await helper.monitorConnectionThenCloseAndFinish(async () => { - await waitFixtureChannelIsReady(client); - - const channel = client.channels.get(liveObjectsFixturesChannel, channelOptionsWithLiveObjects()); - const liveObjects = channel.liveObjects; - - await channel.attach(); - const root = await liveObjects.getRoot(); - - const counters = [ - { key: 'emptyCounter', value: 0 }, - { key: 'initialValueCounter', value: 10 }, - { key: 'referencedCounter', value: 20 }, - ]; - - counters.forEach((x) => { - const counter = root.get(x.key); - expect(counter.value()).to.equal(x.value, `Check counter at key="${x.key}" in root has correct value`); - }); - }, client); - }); + Helper.testOnAllTransportsAndProtocols( + this, + 'LiveCounter is initialized with initial value from STATE_SYNC sequence', + function (options, channelName) { + return async function () { + const helper = this.test.helper; + const client = RealtimeWithLiveObjects(helper, options); + + await helper.monitorConnectionThenCloseAndFinish(async () => { + await waitFixtureChannelIsReady(client); + + const channel = client.channels.get(liveObjectsFixturesChannel, channelOptionsWithLiveObjects()); + const liveObjects = channel.liveObjects; + + await channel.attach(); + const root = await liveObjects.getRoot(); + + const counters = [ + { key: 'emptyCounter', value: 0 }, + { key: 'initialValueCounter', value: 10 }, + { key: 'referencedCounter', value: 20 }, + ]; + + counters.forEach((x) => { + const counter = root.get(x.key); + expect(counter.value()).to.equal(x.value, `Check counter at key="${x.key}" in root has correct value`); + }); + }, client); + }; + }, + ); /** @nospec */ - it('LiveMap is initialized with initial value from STATE_SYNC sequence', async function () { - const helper = this.test.helper; - const client = RealtimeWithLiveObjects(helper); + Helper.testOnAllTransportsAndProtocols( + this, + 'LiveMap is initialized with initial value from STATE_SYNC sequence', + function (options, channelName) { + return async function () { + const helper = this.test.helper; + const client = RealtimeWithLiveObjects(helper, options); - await helper.monitorConnectionThenCloseAndFinish(async () => { - await waitFixtureChannelIsReady(client); + await helper.monitorConnectionThenCloseAndFinish(async () => { + await waitFixtureChannelIsReady(client); - const channel = client.channels.get(liveObjectsFixturesChannel, channelOptionsWithLiveObjects()); - const liveObjects = channel.liveObjects; + const channel = client.channels.get(liveObjectsFixturesChannel, channelOptionsWithLiveObjects()); + const liveObjects = channel.liveObjects; - await channel.attach(); - const root = await liveObjects.getRoot(); + await channel.attach(); + const root = await liveObjects.getRoot(); - const emptyMap = root.get('emptyMap'); - expect(emptyMap.size()).to.equal(0, 'Check empty map in root has no keys'); + const emptyMap = root.get('emptyMap'); + expect(emptyMap.size()).to.equal(0, 'Check empty map in root has no keys'); - const referencedMap = root.get('referencedMap'); - expect(referencedMap.size()).to.equal(1, 'Check referenced map in root has correct number of keys'); + const referencedMap = root.get('referencedMap'); + expect(referencedMap.size()).to.equal(1, 'Check referenced map in root has correct number of keys'); - const counterFromReferencedMap = referencedMap.get('counterKey'); - expect(counterFromReferencedMap.value()).to.equal(20, 'Check nested counter has correct value'); + const counterFromReferencedMap = referencedMap.get('counterKey'); + expect(counterFromReferencedMap.value()).to.equal(20, 'Check nested counter has correct value'); - const valuesMap = root.get('valuesMap'); - expect(valuesMap.size()).to.equal(9, 'Check values map in root has correct number of keys'); + const valuesMap = root.get('valuesMap'); + expect(valuesMap.size()).to.equal(9, 'Check values map in root has correct number of keys'); - expect(valuesMap.get('stringKey')).to.equal('stringValue', 'Check values map has correct string value key'); - expect(valuesMap.get('emptyStringKey')).to.equal('', 'Check values map has correct empty string value key'); - helper.recordPrivateApi('call.BufferUtils.base64Decode'); - helper.recordPrivateApi('call.BufferUtils.areBuffersEqual'); - expect( - BufferUtils.areBuffersEqual( - valuesMap.get('bytesKey'), - BufferUtils.base64Decode('eyJwcm9kdWN0SWQiOiAiMDAxIiwgInByb2R1Y3ROYW1lIjogImNhciJ9'), - ), - 'Check values map has correct bytes value key', - ).to.be.true; - helper.recordPrivateApi('call.BufferUtils.base64Decode'); - helper.recordPrivateApi('call.BufferUtils.areBuffersEqual'); - expect( - BufferUtils.areBuffersEqual(valuesMap.get('emptyBytesKey'), BufferUtils.base64Decode('')), - 'Check values map has correct empty bytes value key', - ).to.be.true; - expect(valuesMap.get('numberKey')).to.equal(1, 'Check values map has correct number value key'); - expect(valuesMap.get('zeroKey')).to.equal(0, 'Check values map has correct zero number value key'); - expect(valuesMap.get('trueKey')).to.equal(true, `Check values map has correct 'true' value key`); - expect(valuesMap.get('falseKey')).to.equal(false, `Check values map has correct 'false' value key`); - - const mapFromValuesMap = valuesMap.get('mapKey'); - expect(mapFromValuesMap.size()).to.equal(1, 'Check nested map has correct number of keys'); - }, client); - }); + expect(valuesMap.get('stringKey')).to.equal( + 'stringValue', + 'Check values map has correct string value key', + ); + expect(valuesMap.get('emptyStringKey')).to.equal( + '', + 'Check values map has correct empty string value key', + ); + helper.recordPrivateApi('call.BufferUtils.base64Decode'); + helper.recordPrivateApi('call.BufferUtils.areBuffersEqual'); + expect( + BufferUtils.areBuffersEqual( + valuesMap.get('bytesKey'), + BufferUtils.base64Decode('eyJwcm9kdWN0SWQiOiAiMDAxIiwgInByb2R1Y3ROYW1lIjogImNhciJ9'), + ), + 'Check values map has correct bytes value key', + ).to.be.true; + helper.recordPrivateApi('call.BufferUtils.base64Decode'); + helper.recordPrivateApi('call.BufferUtils.areBuffersEqual'); + expect( + BufferUtils.areBuffersEqual(valuesMap.get('emptyBytesKey'), BufferUtils.base64Decode('')), + 'Check values map has correct empty bytes value key', + ).to.be.true; + expect(valuesMap.get('numberKey')).to.equal(1, 'Check values map has correct number value key'); + expect(valuesMap.get('zeroKey')).to.equal(0, 'Check values map has correct zero number value key'); + expect(valuesMap.get('trueKey')).to.equal(true, `Check values map has correct 'true' value key`); + expect(valuesMap.get('falseKey')).to.equal(false, `Check values map has correct 'false' value key`); + + const mapFromValuesMap = valuesMap.get('mapKey'); + expect(mapFromValuesMap.size()).to.equal(1, 'Check nested map has correct number of keys'); + }, client); + }; + }, + ); /** @nospec */ - it('LiveMaps can reference the same object in their keys', async function () { - const helper = this.test.helper; - const client = RealtimeWithLiveObjects(helper); - - await helper.monitorConnectionThenCloseAndFinish(async () => { - await waitFixtureChannelIsReady(client); - - const channel = client.channels.get(liveObjectsFixturesChannel, channelOptionsWithLiveObjects()); - const liveObjects = channel.liveObjects; - - await channel.attach(); - const root = await liveObjects.getRoot(); - - const referencedCounter = root.get('referencedCounter'); - const referencedMap = root.get('referencedMap'); - const valuesMap = root.get('valuesMap'); - - const counterFromReferencedMap = referencedMap.get('counterKey'); - expect(counterFromReferencedMap, 'Check nested counter exists at a key in a map').to.exist; - expectInstanceOf(counterFromReferencedMap, 'LiveCounter', 'Check nested counter is of type LiveCounter'); - expect(counterFromReferencedMap).to.equal( - referencedCounter, - 'Check nested counter is the same object instance as counter on the root', - ); - expect(counterFromReferencedMap.value()).to.equal(20, 'Check nested counter has correct value'); - - const mapFromValuesMap = valuesMap.get('mapKey'); - expect(mapFromValuesMap, 'Check nested map exists at a key in a map').to.exist; - expectInstanceOf(mapFromValuesMap, 'LiveMap', 'Check nested map is of type LiveMap'); - expect(mapFromValuesMap.size()).to.equal(1, 'Check nested map has correct number of keys'); - expect(mapFromValuesMap).to.equal( - referencedMap, - 'Check nested map is the same object instance as map on the root', - ); - }, client); - }); + Helper.testOnAllTransportsAndProtocols( + this, + 'LiveMap can reference the same object in their keys', + function (options, channelName) { + return async function () { + const helper = this.test.helper; + const client = RealtimeWithLiveObjects(helper, options); + + await helper.monitorConnectionThenCloseAndFinish(async () => { + await waitFixtureChannelIsReady(client); + + const channel = client.channels.get(liveObjectsFixturesChannel, channelOptionsWithLiveObjects()); + const liveObjects = channel.liveObjects; + + await channel.attach(); + const root = await liveObjects.getRoot(); + + const referencedCounter = root.get('referencedCounter'); + const referencedMap = root.get('referencedMap'); + const valuesMap = root.get('valuesMap'); + + const counterFromReferencedMap = referencedMap.get('counterKey'); + expect(counterFromReferencedMap, 'Check nested counter exists at a key in a map').to.exist; + expectInstanceOf(counterFromReferencedMap, 'LiveCounter', 'Check nested counter is of type LiveCounter'); + expect(counterFromReferencedMap).to.equal( + referencedCounter, + 'Check nested counter is the same object instance as counter on the root', + ); + expect(counterFromReferencedMap.value()).to.equal(20, 'Check nested counter has correct value'); + + const mapFromValuesMap = valuesMap.get('mapKey'); + expect(mapFromValuesMap, 'Check nested map exists at a key in a map').to.exist; + expectInstanceOf(mapFromValuesMap, 'LiveMap', 'Check nested map is of type LiveMap'); + expect(mapFromValuesMap.size()).to.equal(1, 'Check nested map has correct number of keys'); + expect(mapFromValuesMap).to.equal( + referencedMap, + 'Check nested map is the same object instance as map on the root', + ); + }, client); + }; + }, + ); const primitiveKeyData = [ { key: 'stringKey', data: { value: 'stringValue' } }, @@ -663,6 +712,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'STATE_SYNC sequence with state object "tombstone" property deletes existing object', action: async (ctx) => { const { root, liveObjectsHelper, channelName, channel } = ctx; @@ -712,6 +762,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'STATE_SYNC sequence with state object "tombstone" property triggers subscription callback for existing object', action: async (ctx) => { @@ -769,6 +820,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], const applyOperationsScenarios = [ { + allTransportsAndProtocols: true, description: 'can apply MAP_CREATE with primitives state operation messages', action: async (ctx) => { const { root, liveObjectsHelper, channelName, helper } = ctx; @@ -832,6 +884,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'can apply MAP_CREATE with object ids state operation messages', action: async (ctx) => { const { root, liveObjectsHelper, channelName } = ctx; @@ -989,6 +1042,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'can apply MAP_SET with primitives state operation messages', action: async (ctx) => { const { root, liveObjectsHelper, channelName, helper } = ctx; @@ -1037,6 +1091,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'can apply MAP_SET with object ids state operation messages', action: async (ctx) => { const { root, liveObjectsHelper, channelName } = ctx; @@ -1163,6 +1218,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'can apply MAP_REMOVE state operation messages', action: async (ctx) => { const { root, liveObjectsHelper, channelName } = ctx; @@ -1297,6 +1353,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'can apply COUNTER_CREATE state operation messages', action: async (ctx) => { const { root, liveObjectsHelper, channelName } = ctx; @@ -1419,6 +1476,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'can apply COUNTER_INC state operation messages', action: async (ctx) => { const { root, liveObjectsHelper, channelName } = ctx; @@ -2217,6 +2275,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], const writeApiScenarios = [ { + allTransportsAndProtocols: true, description: 'LiveCounter.increment sends COUNTER_INC operation', action: async (ctx) => { const { root, liveObjectsHelper, channelName } = ctx; @@ -2326,6 +2385,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'LiveCounter.decrement sends COUNTER_INC operation', action: async (ctx) => { const { root, liveObjectsHelper, channelName } = ctx; @@ -2435,6 +2495,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'LiveMap.set sends MAP_SET operation with primitive values', action: async (ctx) => { const { root, helper } = ctx; @@ -2469,6 +2530,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'LiveMap.set sends MAP_SET operation with reference to another LiveObject', action: async (ctx) => { const { root, liveObjectsHelper, channelName } = ctx; @@ -2546,6 +2608,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'LiveMap.remove sends MAP_REMOVE operation', action: async (ctx) => { const { root, liveObjectsHelper, channelName } = ctx; @@ -2608,6 +2671,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'LiveObjects.createCounter sends COUNTER_CREATE operation', action: async (ctx) => { const { liveObjects } = ctx; @@ -2629,6 +2693,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'LiveCounter created with LiveObjects.createCounter can be assigned to the state tree', action: async (ctx) => { const { root, liveObjects } = ctx; @@ -2671,6 +2736,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'LiveObjects.createCounter can return LiveCounter with initial value from applied CREATE operation', action: async (ctx) => { @@ -2702,7 +2768,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], { description: - 'Initial value is not double counted for LiveCounter from LiveObjects.createCounter when CREATE op is received', + 'initial value is not double counted for LiveCounter from LiveObjects.createCounter when CREATE op is received', action: async (ctx) => { const { liveObjects, liveObjectsHelper, helper, channel } = ctx; @@ -2783,6 +2849,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'LiveObjects.createMap sends MAP_CREATE operation with primitive values', action: async (ctx) => { const { liveObjects, helper } = ctx; @@ -2836,6 +2903,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'LiveObjects.createMap sends MAP_CREATE operation with reference to another LiveObject', action: async (ctx) => { const { root, liveObjectsHelper, channelName, liveObjects } = ctx; @@ -2876,6 +2944,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'LiveMap created with LiveObjects.createMap can be assigned to the state tree', action: async (ctx) => { const { root, liveObjects } = ctx; @@ -2919,6 +2988,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'LiveObjects.createMap can return LiveMap with initial value from applied CREATE operation', action: async (ctx) => { const { liveObjects, liveObjectsHelper, helper, channel } = ctx; @@ -2955,7 +3025,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], { description: - 'Initial value is not double counted for LiveMap from LiveObjects.createMap when CREATE op is received', + 'initial value is not double counted for LiveMap from LiveObjects.createMap when CREATE op is received', action: async (ctx) => { const { liveObjects, liveObjectsHelper, helper, channel } = ctx; @@ -3181,6 +3251,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'batch API scheduled operations are applied when batch callback is finished', action: async (ctx) => { const { root, liveObjects } = ctx; @@ -3361,18 +3432,18 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], /** @nospec */ forScenarios( + this, [ ...stateSyncSequenceScenarios, ...applyOperationsScenarios, ...applyOperationsDuringSyncScenarios, ...writeApiScenarios, ], - async function (helper, scenario) { + async function (helper, scenario, clientOptions, channelName) { const liveObjectsHelper = new LiveObjectsHelper(helper); - const client = RealtimeWithLiveObjects(helper); + const client = RealtimeWithLiveObjects(helper, clientOptions); await helper.monitorConnectionThenCloseAndFinish(async () => { - const channelName = scenario.description; const channel = client.channels.get(channelName, channelOptionsWithLiveObjects()); const liveObjects = channel.liveObjects; @@ -3386,6 +3457,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], const subscriptionCallbacksScenarios = [ { + allTransportsAndProtocols: true, description: 'can subscribe to the incoming COUNTER_INC operation on a LiveCounter', action: async (ctx) => { const { root, liveObjectsHelper, channelName, sampleCounterKey, sampleCounterObjectId } = ctx; @@ -3418,6 +3490,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'can subscribe to multiple incoming operations on a LiveCounter', action: async (ctx) => { const { root, liveObjectsHelper, channelName, sampleCounterKey, sampleCounterObjectId } = ctx; @@ -3461,6 +3534,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'can subscribe to the incoming MAP_SET operation on a LiveMap', action: async (ctx) => { const { root, liveObjectsHelper, channelName, sampleMapKey, sampleMapObjectId } = ctx; @@ -3494,6 +3568,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'can subscribe to the incoming MAP_REMOVE operation on a LiveMap', action: async (ctx) => { const { root, liveObjectsHelper, channelName, sampleMapKey, sampleMapObjectId } = ctx; @@ -3526,6 +3601,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'can subscribe to multiple incoming operations on a LiveMap', action: async (ctx) => { const { root, liveObjectsHelper, channelName, sampleMapKey, sampleMapObjectId } = ctx; @@ -3864,12 +3940,11 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], ]; /** @nospec */ - forScenarios(subscriptionCallbacksScenarios, async function (helper, scenario) { + forScenarios(this, subscriptionCallbacksScenarios, async function (helper, scenario, clientOptions, channelName) { const liveObjectsHelper = new LiveObjectsHelper(helper); - const client = RealtimeWithLiveObjects(helper); + const client = RealtimeWithLiveObjects(helper, clientOptions); await helper.monitorConnectionThenCloseAndFinish(async () => { - const channelName = scenario.description; const channel = client.channels.get(channelName, channelOptionsWithLiveObjects()); const liveObjects = channel.liveObjects; @@ -3965,6 +4040,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], }, { + allTransportsAndProtocols: true, description: 'tombstoned map entry is removed from the LiveMap after the GC grace period', action: async (ctx) => { const { root, liveObjectsHelper, channelName, helper, waitForGCCycles } = ctx; @@ -4014,7 +4090,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], ]; /** @nospec */ - forScenarios(tombstonesGCScenarios, async function (helper, scenario) { + forScenarios(this, tombstonesGCScenarios, async function (helper, scenario, clientOptions, channelName) { try { helper.recordPrivateApi('write.LiveObjects._DEFAULTS.gcInterval'); LiveObjectsPlugin.LiveObjects._DEFAULTS.gcInterval = 500; @@ -4022,10 +4098,9 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], LiveObjectsPlugin.LiveObjects._DEFAULTS.gcGracePeriod = 250; const liveObjectsHelper = new LiveObjectsHelper(helper); - const client = RealtimeWithLiveObjects(helper); + const client = RealtimeWithLiveObjects(helper, clientOptions); await helper.monitorConnectionThenCloseAndFinish(async () => { - const channelName = scenario.description; const channel = client.channels.get(channelName, channelOptionsWithLiveObjects()); const liveObjects = channel.liveObjects; @@ -4179,12 +4254,11 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], ]; /** @nospec */ - forScenarios(missingChannelModesScenarios, async function (helper, scenario) { + forScenarios(this, missingChannelModesScenarios, async function (helper, scenario, clientOptions, channelName) { const liveObjectsHelper = new LiveObjectsHelper(helper); - const client = RealtimeWithLiveObjects(helper); + const client = RealtimeWithLiveObjects(helper, clientOptions); await helper.monitorConnectionThenCloseAndFinish(async () => { - const channelName = scenario.description; // attach with correct channel modes so we can create liveobjects on the root for testing. // each scenario will modify the underlying modes array to test specific behavior const channel = client.channels.get(channelName, channelOptionsWithLiveObjects()); @@ -4211,7 +4285,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], * @spec TO3l8 * @spec RSL1i */ - it('state message publish respects connectionDetails.maxMessageSize', async function () { + it.only('state message publish respects connectionDetails.maxMessageSize', async function () { const helper = this.test.helper; const client = RealtimeWithLiveObjects(helper, { clientId: 'test' }); @@ -4467,7 +4541,7 @@ define(['ably', 'shared_helper', 'chai', 'live_objects', 'live_objects_helper'], ]; /** @nospec */ - forScenarios(stateMessageSizeScenarios, function (helper, scenario) { + forScenarios(this, stateMessageSizeScenarios, function (helper, scenario) { helper.recordPrivateApi('call.StateMessage.encode'); LiveObjectsPlugin.StateMessage.encode(scenario.message); helper.recordPrivateApi('call.BufferUtils.utf8Encode'); // was called by a scenario to create buffers