From 95c3c8a78dd524a4bc054d5e7deff5e23169d564 Mon Sep 17 00:00:00 2001 From: Lawrence Forooghian Date: Wed, 5 Jun 2024 14:16:25 -0300 Subject: [PATCH] further --- docs/internal/private-api-usage.md | 8 +++ test/common/modules/private_api_recorder.js | 17 +++++++ test/realtime/message.test.js | 5 +- test/realtime/resume.test.js | 55 ++++++++++++++++----- test/realtime/utils.test.js | 5 +- 5 files changed, 77 insertions(+), 13 deletions(-) diff --git a/docs/internal/private-api-usage.md b/docs/internal/private-api-usage.md index 5eb95cf41e..5bbcf04b39 100644 --- a/docs/internal/private-api-usage.md +++ b/docs/internal/private-api-usage.md @@ -113,6 +113,8 @@ Marked in code. ### `test/realtime/transports.test.js` +Skipped marking in code. + Transports are a JS-specific concept so might not be worth worrying too much about the contents of this file - `const Defaults = Ably.Rest.Platform.Defaults;` @@ -129,12 +131,18 @@ Transports are a JS-specific concept so might not be worth worrying too much abo ### `test/realtime/utils.test.js` +Marked in code. + Ah, I just realised that some of the properties on `shared_helper` actually refer to properties of the library, e.g. `helper.Utils` is actually `Ably.Realtime.Utils`. So perhaps I missed some usages of internal APIs in earlier files. But can figure that out later. +(I’ve addressed this in the context of marking the code; utils stuff is properly marked.) + - this entire file is a test of the internal `utils.getRetryTime(…)` method ### `test/realtime/resume.test.js` +Marked in code. + - `connectionManager.once('transport.active',` and inside the callback it makes an assertion on `transport.params.mode` - sets a channel’s state: `suspendedChannel.state = 'suspended';` - sabotages a resume by setting `connection.connectionManager`’s `conectionKey` and `connectionId` to garbage diff --git a/test/common/modules/private_api_recorder.js b/test/common/modules/private_api_recorder.js index 9992d522cb..ac3d66b42c 100644 --- a/test/common/modules/private_api_recorder.js +++ b/test/common/modules/private_api_recorder.js @@ -15,6 +15,7 @@ define([], function () { 'call.PresenceMessage.fromValues', 'call.Utils.mixin', 'call.Utils.toQueryString', + 'call.Utils.getRetryTime', 'call.channel.checkPendingState', 'call.channel.processMessage', 'call.channel.requestState', @@ -45,6 +46,7 @@ define([], function () { 'read.connectionManager.connectionId', 'read.realtime.connection.connectionManager.activeProtocol.transport', 'read.rest.serverTimeOffset', + 'read.transport.params.mode', 'replace.channel.attachImpl', 'replace.channel.processMessage', 'replace.channel.sendMessage', @@ -55,6 +57,21 @@ define([], function () { 'replace.transport.send', 'write.channel._lastPayload', 'write.realtime.options.timeouts.realtimeRequestTimeout', + 'write.channel.state', + 'write.connectionManager.connectionKey', + 'write.connectionManager.connectionId', + 'write.connectionManager.msgSerial', + 'read.connectionManager.msgSerial', + 'read.connectionManager.connectionId', + 'call.connectionManager.disconnectAllTransports', + 'write.auth.tokenDetails.token', + 'read.auth.key', + 'write.auth.key', + 'replace.connectionManager.tryATransport', + 'write.connectionManager.lastActivity', + 'replace.connectionManager.send', + 'call.connectionManager.send', + 'call.ProtocolMessage.setFlag', ]; class PrivateApiRecorder { diff --git a/test/realtime/message.test.js b/test/realtime/message.test.js index 1a2c85331b..e6626625d1 100644 --- a/test/realtime/message.test.js +++ b/test/realtime/message.test.js @@ -1,11 +1,14 @@ 'use strict'; -define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, helper, async, chai) { +define(['ably', 'shared_helper', 'async', 'chai', 'private_api_recorder'], function (Ably, helper, async, chai, privateApiRecorder) { var expect = chai.expect; var displayError = helper.displayError; + // TODO var utils = helper.Utils; + // TODO let config = Ably.Realtime.Platform.Config; var closeAndFinish = helper.closeAndFinish; + // TODO var createPM = Ably.protocolMessageFromDeserialized; var monitorConnection = helper.monitorConnection; var testOnAllTransports = helper.testOnAllTransports; diff --git a/test/realtime/resume.test.js b/test/realtime/resume.test.js index 812db0f668..60ef8fd96b 100644 --- a/test/realtime/resume.test.js +++ b/test/realtime/resume.test.js @@ -1,6 +1,6 @@ 'use strict'; -define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { +define(['shared_helper', 'async', 'chai', 'private_api_recorder'], function (helper, async, chai, privateApiRecorder) { var expect = chai.expect; var closeAndFinish = helper.closeAndFinish; var simulateDroppedConnection = helper.simulateDroppedConnection; @@ -41,7 +41,7 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { * Empty resume case * Send 5 messages; disconnect; reconnect; send 5 messages */ - function resume_inactive(done, channelName, txOpts, rxOpts) { + function resume_inactive(done, channelName, txOpts, rxOpts, privateApiContext) { var count = 5; var txRest = helper.AblyRest(mixin(txOpts)); @@ -79,8 +79,10 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { /* re-open the connection, verify resume mode */ rxRealtime.connection.connect(); var connectionManager = rxRealtime.connection.connectionManager; + privateApiContext.record('listen.connectionManager.transport.active'); connectionManager.once('transport.active', function (transport) { try { + privateApiContext.record('read.transport.params.mode'); expect(transport.params.mode).to.equal('resume', 'Verify reconnect is resume mode'); } catch (err) { callback(err); @@ -139,8 +141,8 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { } testOnAllTransports('resume_inactive', function (realtimeOpts) { - return function (done) { - resume_inactive(done, 'resume_inactive' + String(Math.random()), {}, realtimeOpts); + return function (done, privateApiContext) { + resume_inactive(done, 'resume_inactive' + String(Math.random()), {}, realtimeOpts, privateApiContext); }; }); @@ -148,7 +150,7 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { * Simple resume case * Send 5 messages; disconnect; send 5 messages; reconnect */ - function resume_active(done, channelName, txOpts, rxOpts) { + function resume_active(done, channelName, txOpts, rxOpts, privateApiContext) { var count = 5; var txRest = helper.AblyRest(mixin(txOpts)); @@ -209,8 +211,10 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { rxCount = 0; rxRealtime.connection.connect(); var connectionManager = rxRealtime.connection.connectionManager; + privateApiContext.record('listen.connectionManager.transport.active'); connectionManager.on('transport.active', function (transport) { try { + privateApiContext.record('read.transport.params.mode'); expect(transport.params.mode).to.equal('resume', 'Verify reconnect is resume mode'); } catch (err) { callback(err); @@ -256,8 +260,8 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { } testOnAllTransports('resume_active', function (realtimeOpts) { - return function (done) { - resume_active(done, 'resume_active' + String(Math.random()), {}, realtimeOpts); + return function (done, privateApiContext) { + resume_active(done, 'resume_active' + String(Math.random()), {}, realtimeOpts, privateApiContext); }; }); @@ -266,7 +270,7 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { */ testOnAllTransports( 'resume_lost_continuity', - function (realtimeOpts) { + function (realtimeOpts, privateApiContext) { return function (done) { var realtime = helper.AblyRealtime(realtimeOpts), connection = realtime.connection, @@ -283,17 +287,23 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { }); }, function (cb) { + privateApiContext.record('write.channel.state'); suspendedChannel.state = 'suspended'; whenPromiseSettles(attachedChannel.attach(), cb); }, function (cb) { /* Sabotage the resume */ - (connection.connectionManager.connectionKey = '_____!ablyjs_test_fake-key____'), + privateApiContext.record('write.connectionManager.connectionKey'); + privateApiContext.record('write.connectionManager.connectionId'); + privateApiContext.record('write.connectionManager.msgSerial')( + (connection.connectionManager.connectionKey = '_____!ablyjs_test_fake-key____'), + ), (connection.connectionManager.connectionId = 'ablyjs_tes'); connection.connectionManager.msgSerial = 15; connection.once('disconnected', function () { cb(); }); + privateApiContext.record('call.connectionManager.disconnectAllTransports'); connection.connectionManager.disconnectAllTransports(); }, function (cb) { @@ -305,7 +315,9 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { ); expect(attachedChannel.state).to.equal('attaching', 'Attached channel went into attaching'); expect(suspendedChannel.state).to.equal('attaching', 'Suspended channel went into attaching'); + privateApiContext.record('read.connectionManager.msgSerial'); expect(connection.connectionManager.msgSerial).to.equal(0, 'Check msgSerial is reset to 0'); + privateApiContext.record('read.connectionManager.connectionId'); expect( connection.connectionManager.connectionId !== 'ablyjs_tes', 'Check connectionId is set by the new CONNECTED', @@ -332,7 +344,7 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { */ testOnAllTransports( 'resume_token_error', - function (realtimeOpts) { + function (realtimeOpts, privateApiContext) { return function (done) { var realtime = helper.AblyRealtime(mixin(realtimeOpts, { useTokenAuth: true })), badtoken, @@ -353,6 +365,7 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { }, function (cb) { /* Sabotage the resume - use a valid but now-expired token */ + privateApiContext.record('write.auth.tokenDetails.token'); realtime.auth.tokenDetails.token = badtoken.token; connection.once(function (stateChange) { try { @@ -363,6 +376,7 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { } cb(); }); + privateApiContext.record('call.connectionManager.disconnectAllTransports'); connection.connectionManager.disconnectAllTransports(); }, function (cb) { @@ -385,7 +399,7 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { */ testOnAllTransports( 'resume_fatal_error', - function (realtimeOpts) { + function (realtimeOpts, privateApiContext) { return function (done) { var realtime = helper.AblyRealtime(realtimeOpts), connection = realtime.connection; @@ -398,7 +412,9 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { }); }, function (cb) { + privateApiContext.record('read.auth.key'); var keyName = realtime.auth.key.split(':')[0]; + privateApiContext.record('write.auth.key'); realtime.auth.key = keyName + ':wrong'; connection.once(function (stateChange) { try { @@ -409,6 +425,8 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { } cb(); }); + privateApiContext.record('call.connectionManager.disconnectAllTransports'); + connection.connectionManager.disconnectAllTransports(); }, function (cb) { @@ -501,6 +519,8 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { * Check the library doesn't try to resume once the connectionStateTtl has expired */ it('no_resume_once_suspended', function (done) { + const privateApiContext = privateApiRecorder.createContext(this); + var realtime = helper.AblyRealtime(), connection = realtime.connection, channelName = 'no_resume_once_suspended'; @@ -516,6 +536,7 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { helper.becomeSuspended(realtime, cb); }, function (cb) { + privateApiContext.record('replace.connectionManager.tryATransport'); realtime.connection.connectionManager.tryATransport = function (transportParams) { try { expect(transportParams.mode).to.equal('clean', 'Check library didn’t try to resume'); @@ -539,15 +560,21 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { * connection was > connectionStateTtl ago */ it('no_resume_last_activity', function (done) { + const privateApiContext = privateApiRecorder.createContext(this); + var realtime = helper.AblyRealtime(), connection = realtime.connection, connectionManager = connection.connectionManager; connection.once('connected', function () { + privateApiContext.record('write.connectionManager.lastActivity'); connectionManager.lastActivity = Date.now() - 10000000; /* noop-out onProtocolMessage so that a DISCONNECTED message doesn't * reset the last activity timer */ + privateApiContext.record('call.realtime.connection.connectionManager.activeProtocol.getTransport'); + privateApiContext.record('replace.transport.onProtocolMessage'); connectionManager.activeProtocol.getTransport().onProtocolMessage = function () {}; + privateApiContext.record('replace.connectionManager.tryATransport'); connectionManager.tryATransport = function (transportParams) { try { expect(transportParams.mode).to.equal('clean', 'Check library didn’t try to resume'); @@ -557,11 +584,14 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { } closeAndFinish(done, realtime); }; + privateApiContext.record('call.connectionManager.disconnectAllTransports'); connectionManager.disconnectAllTransports(); }); }); it('resume_rewind_1', function (done) { + const privateApiContext = privateApiRecorder.createContext(this); + var testName = 'resume_rewind_1'; var testMessage = { foo: 'bar', count: 1, status: 'active' }; try { @@ -586,9 +616,12 @@ define(['shared_helper', 'async', 'chai'], function (helper, async, chai) { var resumed_receiver_realtime = helper.AblyRealtime(); var connectionManager = resumed_receiver_realtime.connection.connectionManager; + privateApiContext.record('replace.connectionManager.send'); var sendOrig = connectionManager.send; connectionManager.send = function (msg, queueEvent, callback) { + privateApiContext.record('call.ProtocolMessage.setFlag'); msg.setFlag('ATTACH_RESUME'); + privateApiContext.record('call.connectionManager.send'); sendOrig.call(connectionManager, msg, queueEvent, callback); }; diff --git a/test/realtime/utils.test.js b/test/realtime/utils.test.js index 244e4a3a4a..8c6c89f914 100644 --- a/test/realtime/utils.test.js +++ b/test/realtime/utils.test.js @@ -1,15 +1,18 @@ 'use strict'; -define(['shared_helper', 'chai'], function (helper, chai) { +define(['shared_helper', 'chai', 'private_api_recorder'], function (helper, chai, privateApiRecorder) { var utils = helper.Utils; var expect = chai.expect; // RTB1 describe('incremental backoff and jitter', function () { it('should calculate retry timeouts using incremental backoff and jitter', function () { + const privateApiContext = privateApiRecorder.createContext(this); + var retryAttempts = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; var initialTimeout = 15; + privateApiContext.record('call.Utils.getRetryTime'); var retryTimeouts = retryAttempts.map((attempt) => utils.getRetryTime(initialTimeout, attempt)); expect(retryTimeouts.filter((timeout) => timeout >= 30).length).to.equal(0);