diff --git a/docs/internal/private-api-usage.md b/docs/internal/private-api-usage.md index ec522c0f1..55d52db7e 100644 --- a/docs/internal/private-api-usage.md +++ b/docs/internal/private-api-usage.md @@ -21,17 +21,25 @@ None ### `test/realtime/delta.test.js` +Marked in code. + - `channel._lastPayload.messageId = null` - to make decoding fail +Note that this test passes an overridden VCDiff decoder, but some SDKs don't use a VCDiff decoder + ### `test/realtime/encoding.test.js` +Marked in code. + - `var BufferUtils = Ably.Realtime.Platform.BufferUtils;` - `var Defaults = Ably.Rest.Platform.Defaults;` - just used for accessing library’s baked-in protocol version, to pass to `request()` ### `test/realtime/presence.test.js` +Marked in code. + - `var createPM = Ably.protocolMessageFromDeserialized;` - `var PresenceMessage = Ably.Realtime.PresenceMessage;` - replacing `channel.sendPresence` with a version that checks the presence message’s client ID @@ -47,6 +55,8 @@ None ### `test/realtime/event_emitter.test.js` +Marked in code. + - `eventEmitter.emit('custom');` — RTE6 says that `emit` is internal ### `test/realtime/api.test.js` @@ -55,15 +65,18 @@ None ### `test/realtime/crypto.test.js` +Marked in code. + - `var BufferUtils = Ably.Realtime.Platform.BufferUtils;` - `var msgpack = typeof window == 'object' ? Ably.msgpack : require('@ably/msgpack-js');` - `Message.encode(testMessage, channelOpts)` - `Message.decode(encryptedMessage, channelOpts);` -- `Message.fromValues(` - `expect(channel.channelOptions.cipher.algorithm).to.equal('aes');` — `channel.channelOptions` is not public API ### `test/realtime/failure.test.js` +Marked in code. + - `webSocketConnectTimeout: 50` client option - replacing `channel.processMessage` to drop `ATTACHED` - replacing `realtime.connection.connectionManager.activeProtocol.transport.onProtocolMessage` to drop `ACK` @@ -75,6 +88,8 @@ None ### `test/realtime/channel.test.js` +Marked in code. + - `var createPM = Ably.protocolMessageFromDeserialized;` - `expect(channel.channelOptions).to.deep.equal(channelOptions, 'Check requested channel options');` (`channelOptions` isn’t public API) - listens for `channel._allChannelChanges.on(['update'],` @@ -88,13 +103,18 @@ None ### `test/realtime/auth.test.js` +Marked in code. + - `var http = new Ably.Realtime._Http();` — just uses this as an HTTP client to fetch a JWT +- reads `realtime.auth.method` to check it’s `token` - spies on `rest.time` to count how many times called - checks `rest.serverTimeOffset` - spies on `transport.send` to look for an outgoing `AUTH` and check its properties ### `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;` @@ -111,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 @@ -132,6 +158,8 @@ Ah, I just realised that some of the properties on `shared_helper` actually refe ### `test/realtime/message.test.js` +Marked in code. + - `let config = Ably.Realtime.Platform.Config;` - `var createPM = Ably.protocolMessageFromDeserialized;` - modifies `transport.send` to check the `clientId` on the outgoing `MESSAGE` @@ -141,6 +169,8 @@ Ah, I just realised that some of the properties on `shared_helper` actually refe ### `test/realtime/connection.test.js` +Marked in code. + - creates a `recover` client option which uses knowledge of ably-js’s serialization of recovery key - spies on `transport.send` to listen for `MESSAGE`, check its properties, and then continue the test - calls `connectionManager.disconnectAllTransports();` @@ -149,6 +179,8 @@ Ah, I just realised that some of the properties on `shared_helper` actually refe ### `test/realtime/init.test.js` +Marked in code. + - accesses `var transport = realtime.connection.connectionManager.activeProtocol.transport.uri` or `.recvRequest.recvUri` to check the `v=3` query parameter - `expect(realtime.options).to.deep.equal(realtime.connection.connectionManager.options);` - checks `realtime.connection.connectionManager.httpHosts[0];` to check it’s using correct default host, also checks length of that array @@ -165,6 +197,8 @@ None ### `test/realtime/connectivity.test.js` +Marked in code. + - directly calls `new Ably.Realtime._Http().checkConnectivity()` and checks it succeeds (i.e. directly tests this method) ### `test/realtime/reauth.test.js` @@ -173,19 +207,27 @@ None ### `test/realtime/sync.test.js` +Marked in code. + - calling `channel.processMessage` to inject an `ATTACHED` with a presence flag, and then a `SYNC`, later on a `PRESENCE` - spies on `channel.processMessage` to, after processing a received `SYNC`, inject a `PRESENCE` ### `test/browser/simple.test.js` +Skipped marking in code since it’s browser-specific. + - checks whether a transport is available using `transport in Ably.Realtime.ConnectionManager.supportedTransports(Ably.Realtime._transports)` ### `test/browser/http.test.js` +Skipped marking in code since it’s browser-specific. + - changes `Ably.Rest.Platform.Config.xhrSupported` to false to make it use Fetch ### `test/browser/connection.test.js` +Skipped marking in code since it’s browser-specific. + (I guess that this is a test that we might not include in the unified test suite.) - uses knowledge of library’s usage of `window.sessionStorage` for transport preference and recovery key @@ -197,6 +239,8 @@ None ### `test/browser/modular.test.js` +Skipped marking in code since it’s browser-specific. + Another file that probably wouldn’t be part of a unified test suite. - `const BufferUtils = BaseRest.Platform.BufferUtils;` @@ -227,10 +271,14 @@ N/A ### `test/common/modules/client_module.js` -- uses `Ably.Realtime.Utils` for its `mixin` function +Marked in code. + +- uses `Ably.Realtime.Utils` for its `mixin` and `copy` function ### `test/common/modules/testapp_manager.js` +Marked in code. + - uses `ably.Realtime.Platform.BufferUtils` ### `test/common/modules/testapp_module.js` @@ -239,6 +287,8 @@ None ### `test/common/modules/shared_helper.js` +Marked in code. + - `var utils = clientModule.Ably.Realtime.Utils;` - `var platform = clientModule.Ably.Realtime.Platform;` - uses `platform.Config.nextTick()` @@ -314,15 +364,21 @@ N/A ### `test/rest/bufferutils.test.js` +Skipped marking in code. + This file is a unit test of `Ably.Realtime.Platform.BufferUtils`; something we wouldn’t include in a unified test suite. ### `test/rest/presence.test.js` +Marked in code. + - `var BufferUtils = Ably.Realtime.Platform.BufferUtils;` - I’m going to stop mentioning the use of BufferUtils as a test util now; the pattern is clear and not hard to fix. ### `test/rest/fallbacks.test.js` +Marked in code. + - checks `rest._currentFallback.{host, validUntil}` to check that the working fallback has been stored correctly - modifies `rest._currentFallback.validUntil` to check library correctly forgets stored fallback @@ -344,12 +400,16 @@ None ### `test/rest/auth.test.js` +Marked in code. + - ditto will stop mentioning usage of `Utils` for stuff that will be pretty easy to replace None ### `test/rest/http.test.js` +Marked in code. + - accesses `Ably.Rest.Platform.Defaults` to check its `version` is being used to populate `Ably-Agent` - spies on `rest.http.do` to make assertions about request headers - replaces `rest.http.do` to simulate a 204 response @@ -360,10 +420,14 @@ None ### `test/rest/push.test.js` +Marked in code. + None ### `test/rest/message.test.js` +Marked in code. + - spies on `channel._publish` to verify that client does / doesn’t add a `clientId` - ditto to check that idempotent REST publishing generates message IDs - ditto to check `params` @@ -371,14 +435,20 @@ None ### `test/rest/init.test.js` +Marked in code. + - accesses various properties of `rest.options` to check the effect of passing various things to the constructor ### `test/rest/history.test.js` +Marked in code. + None ### `test/rest/defaults.test.js` +TODO decide what to do re marking this one. + This appears to be a unit test of the `Defaults` class’s `normaliseOptions()`, `getHosts()`, and `getPort()` methods. But I imagine it’s actually providing the test suite’s coverage of a bunch of spec points which aren’t written in terms of this API. ### `test/rest/status.test.js` @@ -387,6 +457,8 @@ None ### `test/rest/request.test.js` +Marked in code. + - overrides `rest.http.do()` to check `X-Ably-Version` request header ### `test/package/browser/template/server/resources/runTest.js` diff --git a/test/common/globals/named_dependencies.js b/test/common/globals/named_dependencies.js index 0558b575e..f406284b6 100644 --- a/test/common/globals/named_dependencies.js +++ b/test/common/globals/named_dependencies.js @@ -13,5 +13,9 @@ define(function () { shared_helper: { browser: 'test/common/modules/shared_helper', node: 'test/common/modules/shared_helper' }, async: { browser: 'node_modules/async/lib/async' }, chai: { browser: 'node_modules/chai/chai', node: 'node_modules/chai/chai' }, + private_api_recorder: { + browser: 'test/common/modules/private_api_recorder', + node: 'test/common/modules/private_api_recorder', + }, }); }); diff --git a/test/common/modules/client_module.js b/test/common/modules/client_module.js index 5ea3c37ba..786a0cd22 100644 --- a/test/common/modules/client_module.js +++ b/test/common/modules/client_module.js @@ -5,8 +5,11 @@ define(['ably', 'globals', 'test/common/modules/testapp_module'], function (Ably, ablyGlobals, testAppHelper) { var utils = Ably.Realtime.Utils; - function ablyClientOptions(options) { + function ablyClientOptions(helper, options) { + helper = helper.addingHelperFunction('ablyClientOptions'); + helper.recordPrivateApi('call.Utils.copy'); var clientOptions = utils.copy(ablyGlobals); + helper.recordPrivateApi('call.Utils.mixin'); utils.mixin(clientOptions, options); var authMethods = ['authUrl', 'authCallback', 'token', 'tokenDetails', 'key']; @@ -22,12 +25,14 @@ define(['ably', 'globals', 'test/common/modules/testapp_module'], function (Ably return clientOptions; } - function ablyRest(options) { - return new Ably.Rest(ablyClientOptions(options)); + function ablyRest(helper, options) { + helper = helper.addingHelperFunction('ablyRest'); + return new Ably.Rest(ablyClientOptions(helper, options)); } - function ablyRealtime(options) { - return new Ably.Realtime(ablyClientOptions(options)); + function ablyRealtime(helper, options) { + helper = helper.addingHelperFunction('ablyRealtime'); + return new Ably.Realtime(ablyClientOptions(helper, options)); } return (module.exports = { diff --git a/test/common/modules/private_api_recorder.js b/test/common/modules/private_api_recorder.js new file mode 100644 index 000000000..283047ded --- /dev/null +++ b/test/common/modules/private_api_recorder.js @@ -0,0 +1,159 @@ +'use strict'; + +define([], function () { + const privateAPIIdentifiers = [ + 'call.BufferUtils.areBuffersEqual', + 'call.BufferUtils.base64Decode', + 'call.BufferUtils.base64Encode', + 'call.BufferUtils.utf8Encode', + 'call.BufferUtils.hexEncode', + 'call.BufferUtils.isBuffer', + 'call.BufferUtils.toArrayBuffer', + 'call.ConnectionManager.supportedTransports', + 'call.Defaults.getHost', + 'call.EventEmitter.emit', + 'call.Message.decode', + 'call.Message.encode', + 'call.Platform.nextTick', + 'call.PresenceMessage.fromValues', + 'call.ProtocolMessage.setFlag', + 'call.Utils.copy', + 'call.Utils.getRetryTime', + 'call.Utils.inspectError', + 'call.Utils.keysArray', + 'call.Utils.mixin', + 'call.Utils.toQueryString', + 'call.auth.getAuthHeaders', + 'call.channel.checkPendingState', + 'call.channel.processMessage', + 'call.channel.requestState', + 'call.channel.sendPresence', + 'call.channel.sync', + 'call.connectionManager.disconnectAllTransports', + 'call.connectionManager.notifyState', + 'call.connectionManager.onChannelMessage', + 'call.connectionManager.requestState', + 'call.connectionManager.send', + 'call.filteredSubscriptions.has', + 'call.http._getHosts', + 'call.http.checkConnectivity', + 'call.http.doUri', + 'call.msgpack.decode', + 'call.msgpack.encode', + 'call.presence._myMembers.put', + 'call.presence.waitSync', + 'call.protocolMessageFromDeserialized', + 'call.realtime.baseUri', + 'call.realtime.connection.connectionManager.activeProtocol.getTransport', + 'call.rest.baseUri', + 'call.rest.http.do', + 'call.restChannel._publish', + 'call.transport.onProtocolMessage', + 'call.transport.send', + 'delete.auth.authOptions.requestHeaders', + 'deserialize.recoveryKey', + 'listen.channel._allChannelChanges.attached', + 'listen.channel._allChannelChanges.update', + 'listen.connectionManager.connectiondetails', + 'listen.connectionManager.transport.active', + 'listen.connectionManager.transport.pending', + 'listen.transport.disposed', + 'new.Crypto.CipherParams', // This is not _really_ a private API since the CipherParams class is part of the IDL (although not part of the JS typings) + 'pass.clientOption.connectivityCheckUrl', // actually ably-js public API but no other SDK has it and it doesn’t enable ably-js-specific functionality + 'pass.clientOption.disableConnectivityCheck', // actually ably-js public API but no other SDK has it and it doesn’t enable ably-js-specific functionality + 'pass.clientOption.webSocketConnectTimeout', + 'read.Defaults.protocolVersion', + 'read.Defaults.version', + 'read.EventEmitter.events', + 'read.Realtime._transports', + 'read.auth.authOptions.authUrl', + 'read.auth.key', + 'read.auth.method', + 'read.auth.tokenParams.version', + 'read.channel.channelOptions', + 'read.channel.channelOptions.cipher', + 'read.connectionManager.activeProtocol', + 'read.connectionManager.baseTransport', + 'read.connectionManager.connectionId', + 'read.connectionManager.connectionId', + 'read.connectionManager.connectionStateTtl', + 'read.connectionManager.httpHosts', + 'read.connectionManager.msgSerial', + 'read.connectionManager.options', + 'read.connectionManager.options.timeouts.httpMaxRetryDuration', + 'read.connectionManager.options.timeouts.httpRequestTimeout', + 'read.connectionManager.pendingTransport', + 'read.connectionManager.queuedMessages.messages', + 'read.connectionManager.states.disconnected.retryDelay', + 'read.connectionManager.states.suspended.retryDelay', + 'read.connectionManager.webSocketTransportAvailable', + 'read.realtime.connection.connectionManager.activeProtocol.transport', + 'read.realtime.options', + 'read.realtime.options.key', + 'read.realtime.options.maxMessageSize', + 'read.realtime.options.token', + 'read.rest._currentFallback', + 'read.rest._currentFallback.host', + 'read.rest._currentFallback.validUntil', + 'read.rest.options.key', + 'read.rest.options.token', + 'read.rest.options.realtimeHost', + 'read.rest.serverTimeOffset', + 'read.transport.params.mode', + 'read.transport.recvRequest.recvUri', + 'read.transport.uri', + 'replace.channel.attachImpl', + 'replace.channel.processMessage', + 'replace.channel.sendMessage', + 'replace.channel.sendPresence', + 'replace.connectionManager.onChannelMessage', + 'replace.connectionManager.send', + 'replace.connectionManager.tryATransport', + 'replace.http.doUri', + 'replace.rest.http.do', + 'replace.rest.time', + 'replace.restChannel._publish', + 'replace.transport.onProtocolMessage', + 'replace.transport.send', + 'serialize.recoveryKey', + 'write.auth.authOptions.requestHeaders', + 'write.auth.key', + 'write.auth.tokenDetails.token', + 'write.channel._lastPayload', + 'write.channel.state', + 'write.connectionManager.connectionDetails.maxMessageSize', + 'write.connectionManager.connectionId', + 'write.connectionManager.connectionKey', + 'write.connectionManager.lastActivity', + 'write.connectionManager.msgSerial', + 'write.realtime.options.timeouts.realtimeRequestTimeout', + 'write.rest._currentFallback.validUntil', + ]; + + class PrivateApiRecorder { + privateAPIUsages = []; + + /** + * Creates a recording context for the current Mocha test case. + * + * @param description A description of the context for which the calls will be recorded. + */ + createContext(description) { + if (!description) { + throw new Error('No description passed to createContext'); + } + + return { + record: (privateAPIIdentifier) => { + if (privateAPIIdentifiers.indexOf(privateAPIIdentifier) == -1) { + throw new Error(`(${description}) Recorded unknown private API: ${privateAPIIdentifier}`); + } + console.log(`(${description}) Recorded private API: ${privateAPIIdentifier}`); + this.privateAPIUsages.push({ contextDescription: description, privateAPIIdentifier }); + }, + }; + } + } + + return (module.exports = new PrivateApiRecorder()); +}); diff --git a/test/common/modules/shared_helper.js b/test/common/modules/shared_helper.js index 34b7643e5..cfea7d2e2 100644 --- a/test/common/modules/shared_helper.js +++ b/test/common/modules/shared_helper.js @@ -10,7 +10,8 @@ define([ 'globals', 'async', 'chai', -], function (testAppModule, clientModule, testAppManager, globals, async, chai) { + 'private_api_recorder', +], function (testAppModule, clientModule, testAppManager, globals, async, chai, privateApiRecorder) { var utils = clientModule.Ably.Realtime.Utils; var platform = clientModule.Ably.Realtime.Platform; var BufferUtils = platform.BufferUtils; @@ -20,14 +21,9 @@ define([ var unroutableAddress = 'http://' + unroutableHost + '/'; class SharedHelper { - setupApp = testAppModule.setup; - tearDownApp = testAppModule.tearDown; - createStats = testAppModule.createStatsFixtureData; getTestApp = testAppModule.getTestApp; Ably = clientModule.Ably; - AblyRest = clientModule.AblyRest; - ablyClientOptions = clientModule.ablyClientOptions; Utils = utils; loadTestData = testAppManager.loadJsonData; @@ -37,11 +33,20 @@ define([ unroutableAddress = unroutableAddress; flushTestLogs = globals.flushLogs; - constructor(context) { + constructor(context, helperFunctionNames) { if (!context) { throw new Error('SharedHelper created without context'); } this.context = context; + this.helperFunctionNames = helperFunctionNames ?? []; + this.privateApiContext = privateApiRecorder.createContext( + `${this.context} (helpers: ${this.helperFunctionNames.join(' -> ')})`, + ); + } + + addingHelperFunction(helperFunctionName) { + const newHelperFunctionNames = [...this.helperFunctionNames, helperFunctionName]; + return new SharedHelper(this.context, newHelperFunctionNames); } static forTest(thisInBeforeEach) { @@ -59,13 +64,30 @@ define([ return new this(`${thisInDescribe.title} (defining ${label})`); } + recordPrivateApi(identifier) { + this.privateApiContext.record(identifier); + } + get availableTransports() { + const helper = this.addingHelperFunction('availableTransports'); + return helper._availableTransports; + } + + get _availableTransports() { + this.recordPrivateApi('call.Utils.keysArray'); + this.recordPrivateApi('call.ConnectionManager.supportedTransports'); + this.recordPrivateApi('read.Realtime._transports'); return utils.keysArray( clientModule.Ably.Realtime.ConnectionManager.supportedTransports(clientModule.Ably.Realtime._transports), ); } get bestTransport() { + const helper = this.addingHelperFunction('bestTransport'); + return helper._bestTransport; + } + + get _bestTransport() { return this.availableTransports[0]; } @@ -99,6 +121,11 @@ define([ } closeAndFinish(done, realtime, err) { + const helper = this.addingHelperFunction('closeAndFinish'); + helper._closeAndFinish(done, realtime, err); + } + + _closeAndFinish(done, realtime, err) { if (typeof realtime === 'undefined') { // Likely called in a catch block for an exception // that occured before realtime was initialized @@ -117,6 +144,11 @@ define([ }); } + async closeAndFinishAsync(realtime, err) { + const helper = this.addingHelperFunction('closeAndFinishAsync'); + return helper._closeAndFinishAsync(realtime, err); + } + async closeAndFinishAsync(realtime, err) { return new Promise((resolve, reject) => { this.closeAndFinish((err) => (err ? reject(err) : resolve()), realtime, err); @@ -137,18 +169,34 @@ define([ } simulateDroppedConnection(realtime) { + const helper = this.addingHelperFunction('simulateDroppedConnection'); + helper._simulateDroppedConnection(realtime); + } + + _simulateDroppedConnection(realtime) { + const self = this; // Go into the 'disconnected' state before actually disconnecting the transports // to avoid the instantaneous reconnect attempt that would be triggered in // notifyState by the active transport getting disconnected from a connected state realtime.connection.once('disconnected', function () { + self.recordPrivateApi('call.connectionManager.disconnectAllTransports'); realtime.connection.connectionManager.disconnectAllTransports(); }); + this.recordPrivateApi('call.connectionManager.requestState'); realtime.connection.connectionManager.requestState({ state: 'disconnected' }); } becomeSuspended(realtime, cb) { + const helper = this.addingHelperFunction('becomeSuspended'); + helper._becomeSuspended(realtime, cb); + } + + _becomeSuspended(realtime, cb) { + this.recordPrivateApi('call.connectionManager.disconnectAllTransports'); realtime.connection.connectionManager.disconnectAllTransports(); + const self = this; realtime.connection.once('disconnected', function () { + self.recordPrivateApi('call.connectionManager.notifyState'); realtime.connection.connectionManager.notifyState({ state: 'suspended' }); }); if (cb) @@ -158,25 +206,40 @@ define([ } callbackOnClose(realtime, callback) { + const helper = this.addingHelperFunction('callbackOnClose'); + helper._callbackOnClose(realtime, callback); + } + + _callbackOnClose(realtime, callback) { + this.recordPrivateApi('read.connectionManager.activeProtocol'); if (!realtime.connection.connectionManager.activeProtocol) { + this.recordPrivateApi('call.Platform.nextTick'); platform.Config.nextTick(function () { realtime.close(); callback(); }); return; } + this.recordPrivateApi('read.realtime.connection.connectionManager.activeProtocol.transport'); + this.recordPrivateApi('listen.transport.disposed'); realtime.connection.connectionManager.activeProtocol.transport.on('disposed', function () { callback(); }); /* wait a tick before closing in order to avoid the final close * happening synchronously in a publish/attach callback, which * complicates channelattach_publish_invalid etc. */ + this.recordPrivateApi('call.Platform.nextTick'); platform.Config.nextTick(function () { realtime.close(); }); } closeAndFinishSeveral(done, realtimeArray, e) { + const helper = this.addingHelperFunction('closeAndFinishSeveral'); + helper._closeAndFinishSeveral(done, realtimeArray, e); + } + + _closeAndFinishSeveral(done, realtimeArray, e) { async.map( realtimeArray, (realtime, mapCb) => { @@ -225,10 +288,14 @@ define([ static restTestOnJsonMsgpack(name, testFn, skip) { var itFn = skip ? it.skip : it; itFn(name + ' with binary protocol', async function () { - await testFn(new clientModule.AblyRest({ useBinaryProtocol: true }), name + '_binary', this.helper); + await testFn( + new clientModule.AblyRest(this.helper, { useBinaryProtocol: true }), + name + '_binary', + this.helper, + ); }); itFn(name + ' with text protocol', async function () { - await testFn(new clientModule.AblyRest({ useBinaryProtocol: false }), name + '_text', this.helper); + await testFn(new clientModule.AblyRest(this.helper, { useBinaryProtocol: false }), name + '_text', this.helper); }); } @@ -251,6 +318,11 @@ define([ } testMessageEquality(one, two) { + const helper = this.addingHelperFunction('testMessageEquality'); + return helper._testMessageEquality(one, two); + } + + _testMessageEquality(one, two) { // treat `null` same as `undefined` (using ==, rather than ===) expect(one.encoding == two.encoding, "Encoding mismatch ('" + one.encoding + "' != '" + two.encoding + "').").to .be.ok; @@ -260,7 +332,9 @@ define([ return; } + this.recordPrivateApi('call.BufferUtils.isBuffer'); if (BufferUtils.isBuffer(one.data) && BufferUtils.isBuffer(two.data)) { + this.recordPrivateApi('call.BufferUtils.areBuffersEqual'); expect(BufferUtils.areBuffersEqual(one.data, two.data), 'Buffer data contents mismatch.').to.equal(true); return; } @@ -274,10 +348,18 @@ define([ expect(json1 === json2, 'JSON data contents mismatch.').to.be.ok; } + ablyClientOptions(options) { + return clientModule.ablyClientOptions(this, options); + } + + AblyRest(options) { + return clientModule.AblyRest(this, options); + } + static activeClients = []; AblyRealtime(options) { - const client = clientModule.AblyRealtime(options); + const client = clientModule.AblyRealtime(this, options); SharedHelper.activeClients.push(client); return client; } @@ -305,6 +387,18 @@ define([ } } } + + createStats(app, statsData, callback) { + testAppModule.createStatsFixtureData(this, app, statsData, callback); + } + + setupApp(forceSetup, done) { + return testAppModule.setup(this, forceSetup, done); + } + + tearDownApp(app, callback) { + testAppModule.tearDown(this, app, callback); + } } SharedHelper.testOnAllTransports.skip = function (thisInDescribe, name, testFn) { diff --git a/test/common/modules/testapp_manager.js b/test/common/modules/testapp_manager.js index d69fcb904..0f4b7fa9d 100644 --- a/test/common/modules/testapp_manager.js +++ b/test/common/modules/testapp_manager.js @@ -31,9 +31,12 @@ define(['globals', 'ably'], function (ablyGlobals, ably) { } } - function toBase64(str) { + function toBase64(helper, str) { + helper = helper.addingHelperFunction('toBase64'); var bufferUtils = ably.Realtime.Platform.BufferUtils; + helper.recordPrivateApi('call.BufferUtils.utf8Encode'); var buffer = bufferUtils.utf8Encode(str); + helper.recordPrivateApi('call.BufferUtils.base64Encode'); return bufferUtils.base64Encode(buffer); } @@ -164,11 +167,12 @@ define(['globals', 'ably'], function (ablyGlobals, ably) { }); } - function createStatsFixtureData(app, statsData, callback) { + function createStatsFixtureData(helper, app, statsData, callback) { + helper = helper.addingHelperFunction('createStatsFixtureData'); var postData = JSON.stringify(statsData); var authKey = app.keys[0].keyStr; - var authHeader = toBase64(authKey); + var authHeader = toBase64(helper, authKey); var postOptions = { host: restHost, @@ -195,9 +199,10 @@ define(['globals', 'ably'], function (ablyGlobals, ably) { }); } - function deleteApp(app, callback) { + function deleteApp(helper, app, callback) { + helper = helper.addingHelperFunction('deleteApp'); var authKey = app.keys[0].keyStr, - authHeader = toBase64(authKey); + authHeader = toBase64(helper, authKey); var delOptions = { host: restHost, diff --git a/test/common/modules/testapp_module.js b/test/common/modules/testapp_module.js index 3e2e7db1b..2b8da166f 100644 --- a/test/common/modules/testapp_module.js +++ b/test/common/modules/testapp_module.js @@ -20,7 +20,7 @@ define(['test/common/modules/testapp_manager', 'globals'], function (testAppMana then no need to recreate a test app, unless forceSetup is true. If forceSetup is true and existing app exists, then the app will be torn down (deleted) first */ - function setup(forceSetup, done) { + function setup(helper, forceSetup, done) { if (typeof forceSetup === 'function') { done = forceSetup; forceSetup = false; @@ -63,13 +63,13 @@ define(['test/common/modules/testapp_manager', 'globals'], function (testAppMana /* tearDown is typically called by an afterAll test suite block. If tearDown is called more than once i.e. across multiple suites, and other test suites are still to run, then we must not yet delete the test app */ - function tearDown(done) { + function tearDown(helper, done) { if (!configuredTestApp()) { done(); return; } - testAppManager.tearDown(configuredTestApp(), function (err) { + testAppManager.tearDown(helper, configuredTestApp(), function (err) { if (err) { done(new Error('Could not tear down Test App: ' + JSON.stringify(err))); } else { diff --git a/test/realtime/auth.test.js b/test/realtime/auth.test.js index 9bdb50c10..b3595cc92 100644 --- a/test/realtime/auth.test.js +++ b/test/realtime/auth.test.js @@ -13,8 +13,9 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async /* * Helper function to fetch JWT tokens from the echo server */ - function getJWT(params, callback) { + function getJWT(params, helper, callback) { var authUrl = echoServer + '/createJWT'; + helper.recordPrivateApi('call.http.doUri'); Helper.whenPromiseSettles(http.doUri('get', authUrl, null, null, params), function (err, result) { if (result.error) { callback(result.error, null); @@ -182,6 +183,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async realtime.connection.on('connected', function () { try { + helper.recordPrivateApi('read.auth.method'); expect(realtime.auth.method).to.equal('token'); helper.closeAndFinish(done, realtime); } catch (err) { @@ -222,6 +224,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async realtime.connection.on('connected', function () { try { + helper.recordPrivateApi('read.auth.method'); expect(realtime.auth.method).to.equal('token'); helper.closeAndFinish(done, realtime); } catch (err) { @@ -258,6 +261,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async realtime.connection.on('connected', function () { try { + helper.recordPrivateApi('read.auth.method'); expect(realtime.auth.method).to.equal('token'); helper.closeAndFinish(done, realtime); } catch (err) { @@ -296,6 +300,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async keyName: tokenRequest.keyName, mac: tokenRequest.mac, }; + helper.recordPrivateApi('call.Utils.toQueryString'); var authPath = echoServer + '/qs_to_body' + helper.Utils.toQueryString(lowerPrecedenceTokenRequestParts); realtime = helper.AblyRealtime({ authUrl: authPath, authParams: higherPrecedenceTokenRequestParts }); @@ -666,6 +671,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async done(err); return; } + helper.recordPrivateApi('call.Utils.mixin'); clientRealtime = helper.AblyRealtime( helper.Utils.mixin(realtimeOpts, { tokenDetails: tokenDetails, queryTime: true }), ); @@ -701,12 +707,14 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async originalTime = rest.time; /* stub time */ + helper.recordPrivateApi('replace.rest.time'); rest.time = async function () { timeRequestCount += 1; return originalTime.call(rest); }; try { + helper.recordPrivateApi('read.rest.serverTimeOffset'); expect( isNaN(parseInt(rest.serverTimeOffset)) && !rest.serverTimeOffset, 'Server time offset is empty and falsey until a time request has been made', @@ -723,6 +731,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async if (err) { return callback(err); } + helper.recordPrivateApi('read.rest.serverTimeOffset'); expect( !isNaN(parseInt(rest.serverTimeOffset)), 'Server time offset is configured when time is requested', @@ -768,6 +777,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); }; + helper.recordPrivateApi('call.Utils.mixin'); realtime = helper.AblyRealtime( helper.Utils.mixin(realtimeOpts, { authCallback: authCallback, clientId: clientId }), ); @@ -812,6 +822,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); }; + helper.recordPrivateApi('call.Utils.mixin'); realtime = helper.AblyRealtime( helper.Utils.mixin(realtimeOpts, { authCallback: authCallback, clientId: clientId }), ); @@ -851,6 +862,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async helper.closeAndFinish(done, realtime, err); return; } + helper.recordPrivateApi('call.Utils.mixin'); realtime = helper.AblyRealtime( helper.Utils.mixin(realtimeOpts, { token: tokenDetails.token, clientId: clientId }), ); @@ -896,6 +908,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async return; } setTimeout(function () { + helper.recordPrivateApi('call.Utils.mixin'); realtime = helper.AblyRealtime( helper.Utils.mixin(realtimeOpts, { token: tokenDetails.token, clientId: clientId }), ); @@ -946,6 +959,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); }; + helper.recordPrivateApi('call.Utils.mixin'); realtime = helper.AblyRealtime(helper.Utils.mixin(realtimeOpts, { authCallback: authCallback })); realtime.connection.once('connected', function () { var channel = realtime.channels.get('right'); @@ -992,6 +1006,9 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); try { + helper.recordPrivateApi('read.auth.tokenParams.version'); + helper.recordPrivateApi('read.auth.authOptions.authUrl'); + expect(realtime.auth.tokenParams.version).to.equal(1, 'Check initial defaultTokenParams stored'); expect(realtime.auth.tokenDetails.token).to.equal('1', 'Check initial token stored'); expect(realtime.auth.authOptions.authUrl).to.equal('1', 'Check initial authUrl stored'); @@ -1030,8 +1047,10 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async realtime = helper.AblyRealtime({ authCallback: authCallback, transports: [helper.bestTransport] }); realtime.connection.once('connected', function () { + helper.recordPrivateApi('read.realtime.connection.connectionManager.activeProtocol.transport'); var transport = realtime.connection.connectionManager.activeProtocol.transport, originalSend = transport.send; + helper.recordPrivateApi('replace.transport.send'); /* Spy on transport.send to detect the outgoing AUTH */ transport.send = function (message) { if (message.action === 17) { @@ -1042,10 +1061,12 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async helper.closeAndFinish(done, realtime, err); } } else { + helper.recordPrivateApi('call.transport.send'); originalSend.call(this, message); } }; /* Inject a fake AUTH from realtime */ + helper.recordPrivateApi('call.transport.onProtocolMessage'); transport.onProtocolMessage({ action: 17 }); }); }); @@ -1059,9 +1080,10 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async var currentKey = helper.getTestApp().keys[0]; var keys = { keyName: currentKey.keyName, keySecret: currentKey.keySecret }; var clientId = 'testJWTClientId'; + helper.recordPrivateApi('call.Utils.mixin'); var params = helper.Utils.mixin(keys, { clientId: clientId }); var authCallback = function (tokenParams, callback) { - getJWT(params, callback); + getJWT(params, helper, callback); }; var realtime = helper.AblyRealtime({ authCallback: authCallback }); @@ -1093,9 +1115,10 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async var currentKey = helper.getTestApp().keys[0]; var keys = { keyName: currentKey.keyName, keySecret: currentKey.keySecret, returnType: 'jwt' }; var clientId = 'testJWTClientId'; + helper.recordPrivateApi('call.Utils.mixin'); var params = helper.Utils.mixin(keys, { clientId: clientId }); var authCallback = function (tokenParams, callback) { - getJWT(params, callback); + getJWT(params, helper, callback); }; var realtime = helper.AblyRealtime({ authCallback: authCallback }); @@ -1127,7 +1150,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async var currentKey = helper.getTestApp().keys[3]; // get subscribe-only keys { "*":["subscribe"] } var params = { keyName: currentKey.keyName, keySecret: currentKey.keySecret }; var authCallback = function (tokenParams, callback) { - getJWT(params, callback); + getJWT(params, helper, callback); }; var realtime = helper.AblyRealtime({ authCallback: authCallback }); @@ -1155,7 +1178,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async var currentKey = helper.getTestApp().keys[0]; var params = { keyName: currentKey.keyName, keySecret: currentKey.keySecret }; var authCallback = function (tokenParams, callback) { - getJWT(params, callback); + getJWT(params, helper, callback); }; var publishEvent = 'publishEvent', @@ -1185,7 +1208,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async var currentKey = helper.getTestApp().keys[0]; var params = { keyName: currentKey.keyName, keySecret: currentKey.keySecret, expiresIn: 5 }; var authCallback = function (tokenParams, callback) { - getJWT(params, callback); + getJWT(params, helper, callback); }; var realtime = helper.AblyRealtime({ authCallback: authCallback }); @@ -1213,7 +1236,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async // We create a token that lasts 35 so there's room to receive the update event message. var params = { keyName: currentKey.keyName, keySecret: currentKey.keySecret, expiresIn: 35 }; var authCallback = function (tokenParams, callback) { - getJWT(params, callback); + getJWT(params, helper, callback); }; var realtime = helper.AblyRealtime({ authCallback: authCallback }); @@ -1239,7 +1262,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async const helper = this.helper; var currentKey = helper.getTestApp().keys[0]; var params = { keyName: currentKey.keyName, keySecret: currentKey.keySecret }; - getJWT(params, function (err, token) { + getJWT(params, helper, function (err, token) { if (err) { done(err); return; @@ -1302,6 +1325,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async return; } /* Fake an expired token */ + // TODO is _writing_ token.expires a private API? token.expires = Date.now() - 5000; var authCallbackCallCount = 0; var authCallback = function (_, callback) { diff --git a/test/realtime/channel.test.js b/test/realtime/channel.test.js index b6cffeb3d..077f86b74 100644 --- a/test/realtime/channel.test.js +++ b/test/realtime/channel.test.js @@ -172,6 +172,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async var realtime = helper.AblyRealtime(realtimeOpts); realtime.connection.on('connected', function () { try { + helper.recordPrivateApi('read.channel.channelOptions'); /* set options on init */ var channel0 = realtime.channels.get('channelinit0', { fakeOption: true }); expect(channel0.channelOptions.fakeOption).to.equal(true); @@ -518,6 +519,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async return; } try { + helper.recordPrivateApi('read.channel.channelOptions'); expect(channel.channelOptions).to.deep.equal(channelOptions, 'Check requested channel options'); expect(channel.params).to.deep.equal(params, 'Check result params'); expect(channel.modes).to.deep.equal(['subscribe'], 'Check result modes'); @@ -572,6 +574,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async helper.closeAndFinish(done, realtime, err); return; } + helper.recordPrivateApi('read.channel.channelOptions'); expect(channel.channelOptions).to.deep.equal(channelOptions, 'Check requested channel options'); expect(channel.params).to.deep.equal(params, 'Check result params'); expect(channel.modes).to.deep.equal(['subscribe'], 'Check result modes'); @@ -696,6 +699,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }, function (cb) { var channelUpdated = false; + helper.recordPrivateApi('listen.channel._allChannelChanges.update'); channel._allChannelChanges.on(['update'], function () { channelUpdated = true; }); @@ -709,6 +713,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async function () { /* Wait a tick so we don' depend on whether the update event runs the * channelUpdated listener or the setOptions listener first */ + helper.recordPrivateApi('call.Platform.nextTick'); Ably.Realtime.Platform.Config.nextTick(function () { expect( channelUpdated, @@ -721,6 +726,8 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }, function (cb) { var channelUpdated = false; + helper.recordPrivateApi('listen.channel._allChannelChanges.update'); + helper.recordPrivateApi('listen.channel._allChannelChanges.attached'); channel._allChannelChanges.on(['attached', 'update'], function () { channelUpdated = true; }); @@ -730,6 +737,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async modes: ['subscribe'], }), function () { + helper.recordPrivateApi('call.Platform.nextTick'); Ably.Realtime.Platform.Config.nextTick(function () { expect(channelUpdated, 'Check channel went to the server to update the channel mode').to.be.ok; cb(); @@ -773,6 +781,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async return; } try { + helper.recordPrivateApi('read.channel.channelOptions'); expect(channel.channelOptions).to.deep.equal(channelOptions, 'Check requested channel options'); expect(channel.params).to.deep.equal(params, 'Check result params'); expect(channel.modes).to.deep.equal(paramsModes, 'Check result modes'); @@ -824,6 +833,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async return; } try { + helper.recordPrivateApi('read.channel.channelOptions'); expect(channel.channelOptions).to.deep.equal(channelOptions, 'Check requested channel options'); expect(channel.modes).to.deep.equal(modes, 'Check result modes'); } catch (err) { @@ -875,6 +885,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async return; } try { + helper.recordPrivateApi('read.channel.channelOptions'); expect(channel.channelOptions).to.deep.equal(channelOptions, 'Check requested channel options'); expect(channel.params).to.deep.equal({ delta: 'vcdiff' }, 'Check result params'); expect(channel.modes).to.deep.equal(modes, 'Check result modes'); @@ -1149,14 +1160,19 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }, function (cb) { /* Sabotage the reattach attempt, then simulate a server-sent detach */ + helper.recordPrivateApi('replace.channel.sendMessage'); channel.sendMessage = function () {}; + helper.recordPrivateApi('write.realtime.options.timeouts.realtimeRequestTimeout'); realtime.options.timeouts.realtimeRequestTimeout = 100; channel.once(function (stateChange) { expect(stateChange.current).to.equal('attaching', 'Channel reattach attempt happens immediately'); expect(stateChange.reason.code).to.equal(50000, 'check error is propogated in the reason'); cb(); }); + helper.recordPrivateApi('call.realtime.connection.connectionManager.activeProtocol.getTransport'); var transport = realtime.connection.connectionManager.activeProtocol.getTransport(); + helper.recordPrivateApi('call.protocolMessageFromDeserialized'); + helper.recordPrivateApi('call.transport.onProtocolMessage'); transport.onProtocolMessage( createPM({ action: 13, @@ -1190,8 +1206,10 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async channel = realtime.channels.get(channelName); realtime.connection.once('connected', function () { + helper.recordPrivateApi('call.realtime.connection.connectionManager.activeProtocol.getTransport'); var transport = realtime.connection.connectionManager.activeProtocol.getTransport(); /* Mock sendMessage to respond to attaches with a DETACHED */ + helper.recordPrivateApi('replace.channel.sendMessage'); channel.sendMessage = function (msg) { try { expect(msg.action).to.equal(10, 'check attach action'); @@ -1199,7 +1217,10 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async helper.closeAndFinish(done, realtime, err); return; } + helper.recordPrivateApi('call.Platform.nextTick'); Ably.Realtime.Platform.Config.nextTick(function () { + helper.recordPrivateApi('call.protocolMessageFromDeserialized'); + helper.recordPrivateApi('call.transport.onProtocolMessage'); transport.onProtocolMessage( createPM({ action: 13, @@ -1245,7 +1266,10 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async helper.closeAndFinish(done, realtime, err); } }); + helper.recordPrivateApi('call.realtime.connection.connectionManager.activeProtocol.getTransport'); var transport = realtime.connection.connectionManager.activeProtocol.getTransport(); + helper.recordPrivateApi('call.protocolMessageFromDeserialized'); + helper.recordPrivateApi('call.transport.onProtocolMessage'); transport.onProtocolMessage( createPM({ action: 9, @@ -1288,7 +1312,10 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async expect(channel.state).to.equal('attached', 'check channel still attached'); cb(); }); + helper.recordPrivateApi('call.realtime.connection.connectionManager.activeProtocol.getTransport'); var transport = realtime.connection.connectionManager.activeProtocol.getTransport(); + helper.recordPrivateApi('call.protocolMessageFromDeserialized'); + helper.recordPrivateApi('call.transport.onProtocolMessage'); transport.onProtocolMessage( createPM({ action: 11, @@ -1338,6 +1365,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async channel = realtime.channels.get(channelName); /* Stub out the channel's ability to communicate */ + helper.recordPrivateApi('replace.channel.sendMessage'); channel.sendMessage = function () {}; async.series( @@ -1357,6 +1385,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }, function (cb) { /* nexttick so that it doesn't pick up the suspended event */ + helper.recordPrivateApi('call.Platform.nextTick'); Ably.Realtime.Platform.Config.nextTick(function () { channel.once(function (stateChange) { expect(stateChange.current).to.equal('attaching', 'Check channel tries again after a bit'); @@ -1400,13 +1429,16 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async /* Have the connection go into the suspended state, and check that the * channel goes into the suspended state and doesn't try to reattach * until the connection reconnects */ + helper.recordPrivateApi('replace.channel.sendMessage'); channel.sendMessage = function (msg) { expect(false, 'Channel tried to send a message ' + JSON.stringify(msg)).to.be.ok; }; + helper.recordPrivateApi('write.realtime.options.timeouts.realtimeRequestTimeout'); realtime.options.timeouts.realtimeRequestTimeout = 2000; helper.becomeSuspended(realtime, function () { /* nextTick as connection event is emitted before channel state is changed */ + helper.recordPrivateApi('call.Platform.nextTick'); Ably.Realtime.Platform.Config.nextTick(function () { expect(channel.state).to.equal('suspended', 'check channel state is suspended'); cb(); @@ -1417,6 +1449,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async realtime.connection.once(function (stateChange) { expect(stateChange.current).to.equal('connecting', 'Check we try to connect again'); /* We no longer want to fail the test for an attach, but still want to sabotage it */ + helper.recordPrivateApi('replace.channel.sendMessage'); channel.sendMessage = function () {}; cb(); }); @@ -1465,6 +1498,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async /* Sabotage the detach attempt, detach, then simulate a server-sent attached while * the detach is ongoing. Expect to see the library reassert the detach */ let detachCount = 0; + helper.recordPrivateApi('replace.channel.sendMessage'); channel.sendMessage = function (msg) { expect(msg.action).to.equal(12, 'Check we only see a detach. No attaches!'); expect(channel.state).to.equal('detaching', 'Check still in detaching state after both detaches'); @@ -1477,7 +1511,10 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async /* */ channel.detach(); setTimeout(function () { + helper.recordPrivateApi('call.realtime.connection.connectionManager.activeProtocol.getTransport'); var transport = realtime.connection.connectionManager.activeProtocol.getTransport(); + helper.recordPrivateApi('call.protocolMessageFromDeserialized'); + helper.recordPrivateApi('call.transport.onProtocolMessage'); transport.onProtocolMessage(createPM({ action: 11, channel: channelName })); }, 0); }, diff --git a/test/realtime/connection.test.js b/test/realtime/connection.test.js index cbd33b99e..4cc3a68b1 100644 --- a/test/realtime/connection.test.js +++ b/test/realtime/connection.test.js @@ -69,8 +69,10 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async realtime = helper.AblyRealtime(); realtime.connection.on('connected', function () { try { + helper.recordPrivateApi('deserialize.recoveryKey'); const recoveryContext = JSON.parse(realtime.connection.recoveryKey); expect(recoveryContext.connectionKey).to.equal(realtime.connection.key); + helper.recordPrivateApi('read.connectionManager.msgSerial'); expect(recoveryContext.msgSerial).to.equal(realtime.connection.connectionManager.msgSerial); } catch (err) { helper.closeAndFinish(done, realtime, err); @@ -88,8 +90,10 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async function (cb) { channel.subscribe(function () { setTimeout(function () { + helper.recordPrivateApi('deserialize.recoveryKey'); const recoveryContext = JSON.parse(realtime.connection.recoveryKey); expect(recoveryContext.connectionKey).to.equal(realtime.connection.key); + helper.recordPrivateApi('read.connectionManager.msgSerial'); expect(recoveryContext.msgSerial).to.equal(realtime.connection.connectionManager.msgSerial); cb(); }, 0); @@ -126,6 +130,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async it('unrecoverableConnection', function (done) { const helper = this.helper; var realtime; + helper.recordPrivateApi('serialize.recoveryKey'); const fakeRecoveryKey = JSON.stringify({ connectionKey: '_____!ablyjs_test_fake-key____', msgSerial: 3, @@ -143,6 +148,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async 80018, 'verify unrecoverable-connection error set in connection.errorReason', ); + helper.recordPrivateApi('read.connectionManager.msgSerial'); expect(realtime.connection.connectionManager.msgSerial).to.equal( 0, 'verify msgSerial is 0 (new connection), not 3', @@ -174,6 +180,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async connectionManager = realtime.connection.connectionManager; realtime.connection.once('connected', function () { + helper.recordPrivateApi('read.realtime.connection.connectionManager.activeProtocol.transport'); var transport = connectionManager.activeProtocol.transport; Helper.whenPromiseSettles(channel.attach(), function (err) { if (err) { @@ -183,6 +190,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async let transportSendCallback; + helper.recordPrivateApi('replace.transport.send'); /* Sabotage sending the message */ transport.send = function (msg) { if (msg.action == 15) { @@ -232,9 +240,11 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }, function (cb) { /* After the disconnect, on reconnect, spy on transport.send again */ + helper.recordPrivateApi('listen.connectionManager.transport.pending'); connectionManager.once('transport.pending', function (transport) { var oldSend = transport.send; + helper.recordPrivateApi('replace.transport.send'); transport.send = function (msg, msgCb) { if (msg.action === 15) { if (msg.messages[0].name === 'first') { @@ -258,12 +268,14 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async cb(); } } + helper.recordPrivateApi('call.transport.send'); oldSend.call(transport, msg, msgCb); }; channel.publish('second', null); }); /* Disconnect the transport (will automatically reconnect and resume) () */ + helper.recordPrivateApi('call.connectionManager.disconnectAllTransports'); connectionManager.disconnectAllTransports(); }, ], @@ -287,15 +299,18 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async realtime = helper.AblyRealtime(), connectionManager = realtime.connection.connectionManager; realtime.connection.once('connected', function () { + helper.recordPrivateApi('listen.connectionManager.connectiondetails'); connectionManager.once('connectiondetails', function (details) { try { expect(details.connectionStateTtl).to.equal(12345, 'Check connectionStateTtl in event'); + helper.recordPrivateApi('read.connectionManager.connectionStateTtl'); expect(connectionManager.connectionStateTtl).to.equal( 12345, 'Check connectionStateTtl set in connectionManager', ); expect(details.clientId).to.equal('foo', 'Check clientId in event'); expect(realtime.auth.clientId).to.equal('foo', 'Check clientId set in auth'); + helper.recordPrivateApi('read.realtime.options.maxMessageSize'); expect(realtime.options.maxMessageSize).to.equal(98765, 'Check maxMessageSize set'); } catch (err) { helper.closeAndFinish(done, realtime, err); @@ -303,6 +318,9 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async } helper.closeAndFinish(done, realtime); }); + helper.recordPrivateApi('call.realtime.connection.connectionManager.activeProtocol.getTransport'); + helper.recordPrivateApi('replace.transport.onProtocolMessage'); + helper.recordPrivateApi('call.protocolMessageFromDeserialized'); connectionManager.activeProtocol.getTransport().onProtocolMessage( createPM({ action: 4, diff --git a/test/realtime/connectivity.test.js b/test/realtime/connectivity.test.js index 6ad70a75d..351d38f8e 100644 --- a/test/realtime/connectivity.test.js +++ b/test/realtime/connectivity.test.js @@ -21,9 +21,14 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { */ it('http_connectivity_check', function (done) { const helper = this.helper; + helper.recordPrivateApi('call.http.checkConnectivity'); Helper.whenPromiseSettles(new Ably.Realtime._Http().checkConnectivity(), function (err, res) { try { - expect(res && !err, 'Connectivity check completed ' + (err && helper.Utils.inspectError(err))).to.be.ok; + expect( + res && !err, + 'Connectivity check completed ' + + (err && (helper.recordPrivateApi('call.Utils.inspectError'), helper.Utils.inspectError(err))), + ).to.be.ok; } catch (err) { done(err); return; @@ -32,7 +37,9 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { }); }); - function options(connectivityCheckUrl, disableConnectivityCheck) { + function options(helper, connectivityCheckUrl, disableConnectivityCheck) { + helper.recordPrivateApi('pass.clientOption.connectivityCheckUrl'); + helper.recordPrivateApi('pass.clientOption.disableConnectivityCheck'); return { connectivityCheckUrl, disableConnectivityCheck, @@ -48,11 +55,16 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { it('succeeds with scheme', function (done) { const helper = this.helper; + helper.recordPrivateApi('call.http.checkConnectivity'); Helper.whenPromiseSettles( - helper.AblyRealtime(options(urlScheme + successUrl)).http.checkConnectivity(), + helper.AblyRealtime(options(helper, urlScheme + successUrl)).http.checkConnectivity(), function (err, res) { try { - expect(res && !err, 'Connectivity check completed ' + (err && helper.Utils.inspectError(err))).to.be.ok; + expect( + res && !err, + 'Connectivity check completed ' + + (err && (helper.recordPrivateApi('call.Utils.inspectError'), helper.Utils.inspectError(err))), + ).to.be.ok; } catch (err) { done(err); return; @@ -64,8 +76,9 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { it('fails with scheme', function (done) { const helper = this.helper; + helper.recordPrivateApi('call.http.checkConnectivity'); Helper.whenPromiseSettles( - helper.AblyRealtime(options(urlScheme + failUrl)).http.checkConnectivity(), + helper.AblyRealtime(options(helper, urlScheme + failUrl)).http.checkConnectivity(), function (err, res) { try { expect(!res, 'Connectivity check expected to return false').to.be.ok; @@ -79,11 +92,16 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { it('succeeds with querystring', function (done) { const helper = this.helper; + helper.recordPrivateApi('call.http.checkConnectivity'); Helper.whenPromiseSettles( - helper.AblyRealtime(options(successUrl)).http.checkConnectivity(), + helper.AblyRealtime(options(helper, successUrl)).http.checkConnectivity(), function (err, res) { try { - expect(res && !err, 'Connectivity check completed ' + (err && helper.Utils.inspectError(err))).to.be.ok; + expect( + res && !err, + 'Connectivity check completed ' + + (err && (helper.recordPrivateApi('call.Utils.inspectError'), helper.Utils.inspectError(err))), + ).to.be.ok; done(); } catch (err) { done(err); @@ -94,23 +112,31 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { it('fails with querystring', function (done) { const helper = this.helper; - Helper.whenPromiseSettles(helper.AblyRealtime(options(failUrl)).http.checkConnectivity(), function (err, res) { - try { - expect(!res, 'Connectivity check expected to return false').to.be.ok; - done(); - } catch (err) { - done(err); - } - }); + helper.recordPrivateApi('call.http.checkConnectivity'); + Helper.whenPromiseSettles( + helper.AblyRealtime(options(helper, failUrl)).http.checkConnectivity(), + function (err, res) { + try { + expect(!res, 'Connectivity check expected to return false').to.be.ok; + done(); + } catch (err) { + done(err); + } + }, + ); }); it('succeeds with plain url', function (done) { const helper = this.helper; Helper.whenPromiseSettles( - helper.AblyRealtime(options('sandbox-rest.ably.io/time')).http.checkConnectivity(), + helper.AblyRealtime(options(helper, 'sandbox-rest.ably.io/time')).http.checkConnectivity(), function (err, res) { try { - expect(res && !err, 'Connectivity check completed ' + (err && helper.Utils.inspectError(err))).to.be.ok; + expect( + res && !err, + 'Connectivity check completed ' + + (err && (helper.recordPrivateApi('call.Utils.inspectError'), helper.Utils.inspectError(err))), + ).to.be.ok; done(); } catch (err) { done(err); @@ -121,8 +147,9 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { it('fails with plain url', function (done) { const helper = this.helper; + helper.recordPrivateApi('call.http.checkConnectivity'); Helper.whenPromiseSettles( - helper.AblyRealtime(options('echo.ably.io')).http.checkConnectivity(), + helper.AblyRealtime(options(helper, 'echo.ably.io')).http.checkConnectivity(), function (err, res) { try { expect(!res, 'Connectivity check expected to return false').to.be.ok; @@ -137,11 +164,16 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { it('disable_connectivity_check', function (done) { const helper = this.helper; + helper.recordPrivateApi('call.http.checkConnectivity'); Helper.whenPromiseSettles( - helper.AblyRealtime(options('notarealhost', true)).http.checkConnectivity(), + helper.AblyRealtime(options(helper, 'notarealhost', true)).http.checkConnectivity(), function (err, res) { try { - expect(res && !err, 'Connectivity check completed ' + (err && helper.Utils.inspectError(err))).to.be.ok; + expect( + res && !err, + 'Connectivity check completed ' + + (err && (helper.recordPrivateApi('call.Utils.inspectError'), helper.Utils.inspectError(err))), + ).to.be.ok; done(); } catch (err) { done(err); diff --git a/test/realtime/crypto.test.js b/test/realtime/crypto.test.js index 7573cb859..532bc27be 100644 --- a/test/realtime/crypto.test.js +++ b/test/realtime/crypto.test.js @@ -37,6 +37,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async return; } var realtime = helper.AblyRealtime(); + helper.recordPrivateApi('call.BufferUtils.base64Decode'); var key = BufferUtils.base64Decode(testData.key); var iv = BufferUtils.base64Decode(testData.iv); var channel = realtime.channels.get(channelName, { cipher: { key: key, iv: iv } }); @@ -63,9 +64,11 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async if (testPlaintextVariants) { var testMessage = await createTestMessage(); + helper.recordPrivateApi('call.BufferUtils.isBuffer'); if (BufferUtils.isBuffer(testMessage.data) && !(testMessage.data instanceof ArrayBuffer)) { // Now, check that we can also handle an ArrayBuffer plaintext. var testMessageWithArrayBufferData = await createTestMessage(); + helper.recordPrivateApi('call.BufferUtils.toArrayBuffer'); testMessageWithArrayBufferData.data = BufferUtils.toArrayBuffer(testMessageWithArrayBufferData.data); runTest(testMessageWithArrayBufferData); } @@ -143,13 +146,16 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); it('getDefaultParams_ArrayBuffer_key', function (done) { + const helper = this.helper; Helper.whenPromiseSettles(Crypto.generateRandomKey(), function (err, key) { if (err) { done(err); } + helper.recordPrivateApi('call.BufferUtils.toArrayBuffer'); var arrayBufferKey = Ably.Realtime.Platform.BufferUtils.toArrayBuffer(key); var params = Crypto.getDefaultParams({ key: arrayBufferKey }); try { + helper.recordPrivateApi('call.BufferUtils.areBuffersEqual'); expect(BufferUtils.areBuffersEqual(params.key, key)).to.equal(true); done(); } catch (err) { @@ -159,14 +165,17 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); it('getDefaultParams_base64_key', function (done) { + const helper = this.helper; Helper.whenPromiseSettles(Crypto.generateRandomKey(), function (err, key) { if (err) { done(err); return; } + helper.recordPrivateApi('call.BufferUtils.base64Encode'); var b64key = Ably.Realtime.Platform.BufferUtils.base64Encode(key); var params = Crypto.getDefaultParams({ key: b64key }); try { + helper.recordPrivateApi('call.BufferUtils.areBuffersEqual'); expect(BufferUtils.areBuffersEqual(params.key, key)).to.equal(true); done(); } catch (err) { @@ -220,6 +229,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async true, function (channelOpts, testMessage, encryptedMessage) { /* encrypt plaintext message; encode() also to handle data that is not already string or buffer */ + helper.recordPrivateApi('call.Message.encode'); Helper.whenPromiseSettles(Message.encode(testMessage, channelOpts), function () { /* compare */ testMessageEquality(done, helper, testMessage, encryptedMessage); @@ -239,6 +249,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async true, function (channelOpts, testMessage, encryptedMessage) { /* encrypt plaintext message; encode() also to handle data that is not already string or buffer */ + helper.recordPrivateApi('call.Message.encode'); Helper.whenPromiseSettles(Message.encode(testMessage, channelOpts), function () { /* compare */ testMessageEquality(done, helper, testMessage, encryptedMessage); @@ -258,6 +269,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async false, async function (channelOpts, testMessage, encryptedMessage) { /* decrypt encrypted message; decode() also to handle data that is not string or buffer */ + helper.recordPrivateApi('call.Message.decode'); await Message.decode(encryptedMessage, channelOpts); /* compare */ testMessageEquality(done, helper, testMessage, encryptedMessage); @@ -276,6 +288,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async false, async function (channelOpts, testMessage, encryptedMessage) { /* decrypt encrypted message; decode() also to handle data that is not string or buffer */ + helper.recordPrivateApi('call.Message.decode'); await Message.decode(encryptedMessage, channelOpts); /* compare */ testMessageEquality(done, helper, testMessage, encryptedMessage); @@ -296,6 +309,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async done(err); return; } + helper.recordPrivateApi('call.BufferUtils.base64Decode'); var key = BufferUtils.base64Decode(testData.key); var iv = BufferUtils.base64Decode(testData.iv); @@ -321,9 +335,13 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async 2, false, function (channelOpts, testMessage, encryptedMessage, msgpackEncodedMessage) { + helper.recordPrivateApi('call.Message.encode'); Helper.whenPromiseSettles(Message.encode(testMessage, channelOpts), function () { + helper.recordPrivateApi('call.msgpack.encode'); var msgpackFromEncoded = msgpack.encode(testMessage); var msgpackFromEncrypted = msgpack.encode(encryptedMessage); + helper.recordPrivateApi('call.BufferUtils.base64Decode'); + helper.recordPrivateApi('call.msgpack.decode'); var messageFromMsgpack = Message.fromValues( msgpack.decode(BufferUtils.base64Decode(msgpackEncodedMessage)), ); @@ -331,6 +349,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async try { /* Mainly testing that we're correctly encoding the direct output from * the platform's ICipher implementation into the msgpack binary type */ + helper.recordPrivateApi('call.BufferUtils.areBuffersEqual'); expect(BufferUtils.areBuffersEqual(msgpackFromEncoded, msgpackFromEncrypted)).to.equal( true, 'verify msgpack encodings of newly-encrypted and preencrypted messages identical using areBuffersEqual', @@ -358,8 +377,11 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async false, function (channelOpts, testMessage, encryptedMessage, msgpackEncodedMessage) { Helper.whenPromiseSettles(Message.encode(testMessage, channelOpts), function () { + helper.recordPrivateApi('call.msgpack.encode'); var msgpackFromEncoded = msgpack.encode(testMessage); var msgpackFromEncrypted = msgpack.encode(encryptedMessage); + helper.recordPrivateApi('call.BufferUtils.base64Decode'); + helper.recordPrivateApi('call.msgpack.decode'); var messageFromMsgpack = Message.fromValues( msgpack.decode(BufferUtils.base64Decode(msgpackEncodedMessage)), ); @@ -367,6 +389,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async try { /* Mainly testing that we're correctly encoding the direct output from * the platform's ICipher implementation into the msgpack binary type */ + helper.recordPrivateApi('call.BufferUtils.areBuffersEqual'); expect(BufferUtils.areBuffersEqual(msgpackFromEncoded, msgpackFromEncrypted)).to.equal( true, 'verify msgpack encodings of newly-encrypted and preencrypted messages identical using areBuffersEqual', @@ -408,6 +431,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async return; } try { + helper.recordPrivateApi('read.channel.channelOptions.cipher'); expect(channel.channelOptions.cipher.algorithm).to.equal('aes'); expect(channel.channelOptions.cipher.keyLength).to.equal(keyLength); } catch (err) { @@ -456,6 +480,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async Helper.whenPromiseSettles(Crypto.generateRandomKey(128), function (err, key) { channel.setOptions({ cipher: { key: key } }); try { + helper.recordPrivateApi('read.channel.channelOptions.cipher'); expect(channel.channelOptions.cipher.algorithm).to.equal('aes'); expect(channel.channelOptions.cipher.keyLength).to.equal(128); } catch (err) { @@ -557,6 +582,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async return; } try { + helper.recordPrivateApi('read.channel.channelOptions.cipher'); expect(txChannel.channelOptions.cipher.algorithm).to.equal('aes'); expect(rxChannel.channelOptions.cipher.algorithm).to.equal('aes'); } catch (err) { diff --git a/test/realtime/delta.test.js b/test/realtime/delta.test.js index b1d000ca4..321ed6f02 100644 --- a/test/realtime/delta.test.js +++ b/test/realtime/delta.test.js @@ -155,6 +155,7 @@ define(['shared_helper', 'vcdiff-decoder', 'async', 'chai'], function (Helper, v if (index === 1) { /* Simulate issue */ + helper.recordPrivateApi('write.channel._lastPayload'); channel._lastPayload.messageId = null; channel.once('attaching', function (stateChange) { try { diff --git a/test/realtime/encoding.test.js b/test/realtime/encoding.test.js index 84f66e362..1b761bbf9 100644 --- a/test/realtime/encoding.test.js +++ b/test/realtime/encoding.test.js @@ -65,6 +65,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async channel.subscribe(name, function (msg) { try { if (encodingSpec.expectedHexValue) { + helper.recordPrivateApi('call.BufferUtils.hexEncode'); expect(BufferUtils.hexEncode(msg.data)).to.equal( encodingSpec.expectedHexValue, 'Check data matches', @@ -83,6 +84,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async binarychannel.subscribe(name, function (msg) { try { if (encodingSpec.expectedHexValue) { + helper.recordPrivateApi('call.BufferUtils.hexEncode'); expect(BufferUtils.hexEncode(msg.data)).to.equal( encodingSpec.expectedHexValue, 'Check data matches', @@ -98,6 +100,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); }, function (parallelCb) { + helper.recordPrivateApi('read.Defaults.protocolVersion'); Helper.whenPromiseSettles( realtime.request( 'post', @@ -163,6 +166,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async var data, name = index.toString(); if (encodingSpec.expectedHexValue) { + helper.recordPrivateApi('call.BufferUtils.base64Decode'); data = BufferUtils.base64Decode(encodingSpec.data); } else { data = encodingSpec.expectedValue; @@ -181,6 +185,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async eachOfCb(err); return; } + helper.recordPrivateApi('read.Defaults.protocolVersion'); Helper.whenPromiseSettles( realtime.request('get', channelPath, Defaults.protocolVersion, null, null, null), function (err, resultPage) { diff --git a/test/realtime/event_emitter.test.js b/test/realtime/event_emitter.test.js index 568e1136f..7984dd2cb 100644 --- a/test/realtime/event_emitter.test.js +++ b/test/realtime/event_emitter.test.js @@ -84,6 +84,7 @@ define(['shared_helper', 'chai'], function (Helper, chai) { callbackCalled = true; }); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('custom'); try { expect(callbackCalled, 'Last callback should have been called').to.be.ok; @@ -108,6 +109,7 @@ define(['shared_helper', 'chai'], function (Helper, chai) { onCallbackCalled += 1; }); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('custom'); eventEmitter.emit('custom'); eventEmitter.emit('custom'); @@ -137,6 +139,7 @@ define(['shared_helper', 'chai'], function (Helper, chai) { eventEmitter.once('custom', callback); eventEmitter.once('custom', callback); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('custom'); eventEmitter.emit('custom'); @@ -165,11 +168,13 @@ define(['shared_helper', 'chai'], function (Helper, chai) { eventEmitter.on('custom', callback); eventEmitter.on('custom', callback); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('custom'); expect(callbackCalled).to.equal(3, 'The same callback should have been called for every registration'); callbackCalled = 0; eventEmitter.off(callback); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('custom'); expect(callbackCalled).to.equal(0, 'All callbacks should have been removed'); } catch (err) { @@ -195,11 +200,13 @@ define(['shared_helper', 'chai'], function (Helper, chai) { eventEmitter.on('custom', callback); eventEmitter.on('custom', callback); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('custom'); expect(callbackCalled).to.equal(3, 'The same callback should have been called for every registration'); callbackCalled = 0; eventEmitter.off(); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('custom'); expect(callbackCalled).to.equal(0, 'All callbacks should have been removed'); } catch (err) { @@ -225,11 +232,13 @@ define(['shared_helper', 'chai'], function (Helper, chai) { eventEmitter.on('custom', callback); eventEmitter.on('custom', callback); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('custom'); expect(callbackCalled).to.equal(3, 'The same callback should have been called for every registration'); callbackCalled = 0; eventEmitter.off('custom', callback); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('custom'); expect(callbackCalled).to.equal(0, 'All callbacks should have been removed'); } catch (err) { @@ -255,11 +264,13 @@ define(['shared_helper', 'chai'], function (Helper, chai) { eventEmitter.on('custom', callback); eventEmitter.on('custom', callback); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('custom'); expect(callbackCalled).to.equal(3, 'The same callback should have been called for every registration'); callbackCalled = 0; eventEmitter.off('custom'); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('custom'); expect(callbackCalled).to.equal(0, 'All callbacks should have been removed'); } catch (err) { @@ -287,16 +298,20 @@ define(['shared_helper', 'chai'], function (Helper, chai) { try { eventEmitter.once('custom', callback); eventEmitter.on('custom', callback); + helper.recordPrivateApi('read.EventEmitter.events'); expect('custom' in eventEmitter.events, 'custom event array exists').to.be.ok; eventEmitter.off('custom', callback); + helper.recordPrivateApi('read.EventEmitter.events'); expect(!('custom' in eventEmitter.events), 'custom event listener array is removed from object').to.be.ok; eventEmitter.once('custom', callback); eventEmitter.on('custom', callback); + helper.recordPrivateApi('read.EventEmitter.events'); expect('custom' in eventEmitter.events, 'custom event array exists').to.be.ok; eventEmitter.off(callback); + helper.recordPrivateApi('read.EventEmitter.events'); expect(!('custom' in eventEmitter.events), 'event listener array is removed from object').to.be.ok; } catch (err) { helper.closeAndFinish(done, realtime, err); @@ -317,6 +332,7 @@ define(['shared_helper', 'chai'], function (Helper, chai) { }; try { + helper.recordPrivateApi('call.EventEmitter.emit'); callbackCalled = 0; eventEmitter.on(['a', 'b', 'c'], callback); eventEmitter.emit('a'); @@ -360,6 +376,7 @@ define(['shared_helper', 'chai'], function (Helper, chai) { try { callbackCalled = 0; eventEmitter.once(['a', 'b', 'c'], callback); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('a', 'expected'); eventEmitter.emit('b', 'wrong'); eventEmitter.emit('c', 'wrong'); @@ -387,6 +404,7 @@ define(['shared_helper', 'chai'], function (Helper, chai) { secondCbCalled = true; }); }); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('a'); try { @@ -431,6 +449,7 @@ define(['shared_helper', 'chai'], function (Helper, chai) { eventEmitter.off(); }); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('a'); try { @@ -483,6 +502,7 @@ define(['shared_helper', 'chai'], function (Helper, chai) { eventEmitter = realtime.connection; const p = eventEmitter.once(); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('b'); p.then(function () { helper.closeAndFinish(done, realtime); @@ -497,6 +517,7 @@ define(['shared_helper', 'chai'], function (Helper, chai) { eventEmitter = realtime.connection; const p = eventEmitter.once(['a', 'b', 'c']); + helper.recordPrivateApi('call.EventEmitter.emit'); eventEmitter.emit('b'); p.then(function () { helper.closeAndFinish(done, realtime); diff --git a/test/realtime/failure.test.js b/test/realtime/failure.test.js index 28e4f0495..00a54410b 100644 --- a/test/realtime/failure.test.js +++ b/test/realtime/failure.test.js @@ -116,6 +116,8 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async var lifecycleTest = function (transports) { return function (cb) { var connectionEvents = []; + + helper.recordPrivateApi('pass.clientOption.webSocketConnectTimeout'); var realtime = helper.AblyRealtime({ transports: transports, realtimeHost: 'invalid', @@ -346,10 +348,12 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async channel = realtime.channels.get('failed_attach'), originalProcessMessage = channel.processMessage.bind(channel); + helper.recordPrivateApi('replace.channel.processMessage'); channel.processMessage = async function (message) { if (message.action === 11) { return; } + helper.recordPrivateApi('call.channel.processMessage'); await originalProcessMessage(message); }; @@ -389,17 +393,20 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async var performance = isBrowser ? window.performance : require('perf_hooks').performance; + helper.recordPrivateApi('replace.channel.processMessage'); channel.processMessage = async function (message) { // Ignore ATTACHED messages if (message.action === 11) { return; } + helper.recordPrivateApi('call.channel.processMessage'); await originalProcessMessage(message); }; var retryTimeouts = []; realtime.connection.on('connected', function () { + helper.recordPrivateApi('write.realtime.options.timeouts.realtimeRequestTimeout'); realtime.options.timeouts.realtimeRequestTimeout = 1; Helper.whenPromiseSettles(channel.attach(), function (err) { if (err) { @@ -461,12 +468,15 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async Helper.whenPromiseSettles(channel.attach(), cb); }, function (cb) { + helper.recordPrivateApi('read.realtime.connection.connectionManager.activeProtocol.transport'); var transport = realtime.connection.connectionManager.activeProtocol.transport, originalOnProtocolMessage = transport.onProtocolMessage; + helper.recordPrivateApi('replace.transport.onProtocolMessage'); transport.onProtocolMessage = function (message) { /* make sure we don't get an ack! */ if (message.action !== 1) { + helper.recordPrivateApi('call.transport.onProtocolMessage'); originalOnProtocolMessage.apply(this, arguments); } }; @@ -483,6 +493,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async cb(err); } }); + helper.recordPrivateApi('call.Platform.nextTick'); Ably.Realtime.Platform.Config.nextTick(function () { failureFn(realtime, helper); }); @@ -509,7 +520,9 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async it( 'nack_on_connection_failed', nack_on_connection_failure( - function (realtime) { + function (realtime, helper) { + helper.recordPrivateApi('read.realtime.connection.connectionManager.activeProtocol.transport'); + helper.recordPrivateApi('call.transport.onProtocolMessage'); realtime.connection.connectionManager.activeProtocol.transport.onProtocolMessage({ action: 9, error: { statusCode: 401, code: 40100, message: 'connection failed because reasons' }, @@ -536,12 +549,15 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async realtime = helper.AblyRealtime({ realtimeRequestTimeout: 2000 }), originalOnProtocolMessage; + helper.recordPrivateApi('listen.connectionManager.transport.pending'); realtime.connection.connectionManager.on('transport.pending', function (transport) { originalOnProtocolMessage = transport.onProtocolMessage; + helper.recordPrivateApi('replace.transport.onProtocolMessage'); transport.onProtocolMessage = function (message) { if (message.action === 4) { message.connectionDetails.maxIdleInterval = 100; } + helper.recordPrivateApi('call.transport.onProtocolMessage'); originalOnProtocolMessage.call(this, message); }; }); @@ -569,10 +585,11 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async * we try again we use a fallback host */ Helper.testOnAllTransports(this, 'try_fallback_hosts_on_placement_constraint', function (realtimeOpts) { return function (done) { + const helper = this.helper; /* Use the echoserver as a fallback host because it doesn't support * websockets, so it'll fail to connect, which we can detect */ - var helper = this.helper, - realtime = helper.AblyRealtime(helper.Utils.mixin({ fallbackHosts: ['echo.ably.io'] }, realtimeOpts)), + helper.recordPrivateApi('call.Utils.mixin'); + var realtime = helper.AblyRealtime(helper.Utils.mixin({ fallbackHosts: ['echo.ably.io'] }, realtimeOpts)), connection = realtime.connection, connectionManager = connection.connectionManager; @@ -591,6 +608,9 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async helper.closeAndFinish(done, realtime); }); }); + helper.recordPrivateApi('call.protocolMessageFromDeserialized'); + helper.recordPrivateApi('call.realtime.connection.connectionManager.activeProtocol.getTransport'); + helper.recordPrivateApi('call.transport.onProtocolMessage'); connectionManager.activeProtocol.getTransport().onProtocolMessage( createPM({ action: 6, @@ -628,10 +648,13 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async var connectionManager = sender_realtime.connection.connectionManager; var onChannelMsgOrig = connectionManager.onChannelMessage; + helper.recordPrivateApi('replace.connectionManager.onChannelMessage'); connectionManager.onChannelMessage = function (msg, transport) { if (msg.action === 15) { + helper.recordPrivateApi('call.channel.requestState'); sender_channel.requestState('attaching'); } + helper.recordPrivateApi('call.connectionManager.onChannelMessage'); onChannelMsgOrig.call(connectionManager, msg, transport); }; diff --git a/test/realtime/init.test.js b/test/realtime/init.test.js index b655a88ab..b310d36f0 100644 --- a/test/realtime/init.test.js +++ b/test/realtime/init.test.js @@ -30,8 +30,17 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { realtime = helper.AblyRealtime({ transports: ['web_socket', 'xhr_polling'] }); realtime.connection.on('connected', function () { /* check api version */ + helper.recordPrivateApi('read.realtime.connection.connectionManager.activeProtocol.transport'); var transport = realtime.connection.connectionManager.activeProtocol.transport; - var connectUri = helper.isWebsocket(transport) ? transport.uri : transport.recvRequest.recvUri; + var connectUri = helper.isWebsocket(transport) + ? (() => { + helper.recordPrivateApi('read.transport.uri'); + return transport.uri; + })() + : (() => { + helper.recordPrivateApi('read.transport.recvRequest.recvUri'); + return transport.recvRequest.recvUri; + })(); try { expect(connectUri.indexOf('v=3') > -1, 'Check uri includes v=3').to.be.ok; } catch (err) { @@ -57,7 +66,10 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { realtime = new helper.Ably.Realtime(keyStr); try { + helper.recordPrivateApi('read.realtime.options.key'); expect(realtime.options.key).to.equal(keyStr); + helper.recordPrivateApi('read.realtime.options'); + helper.recordPrivateApi('read.connectionManager.options'); expect(realtime.options).to.deep.equal(realtime.connection.connectionManager.options); } catch (err) { helper.closeAndFinish(done, realtime, err); @@ -87,7 +99,10 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { realtime = new helper.Ably.Realtime(tokenStr); try { + helper.recordPrivateApi('read.realtime.options.token'); expect(realtime.options.token).to.equal(tokenStr); + helper.recordPrivateApi('read.realtime.options'); + helper.recordPrivateApi('read.connectionManager.options'); expect(realtime.options).to.deep.equal(realtime.connection.connectionManager.options); helper.closeAndFinish(done, realtime); } catch (err) { @@ -106,7 +121,9 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { try { var keyStr = helper.getTestApp().keys[0].keyStr; realtime = helper.AblyRealtime({ key: keyStr, useTokenAuth: true }); + helper.recordPrivateApi('read.realtime.options.key'); expect(realtime.options.key).to.equal(keyStr); + helper.recordPrivateApi('read.auth.method'); expect(realtime.auth.method).to.equal('token'); expect(realtime.auth.clientId).to.equal(undefined); /* Check that useTokenAuth by default results in an anonymous (and not wildcard) token */ @@ -230,6 +247,7 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { * host set, so not using helpers.realtime this time, which will use a * test env */ var realtime = new Ably.Realtime({ key: 'not_a.real:key', autoConnect: false }); + helper.recordPrivateApi('read.connectionManager.httpHosts'); var defaultHost = realtime.connection.connectionManager.httpHosts[0]; expect(defaultHost).to.equal('rest.ably.io', 'Verify correct default rest host chosen'); realtime.close(); @@ -252,18 +270,22 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { }); /* Note: uses internal knowledge of connectionManager */ try { + helper.recordPrivateApi('read.connectionManager.states.disconnected.retryDelay'); expect(realtime.connection.connectionManager.states.disconnected.retryDelay).to.equal( 123, 'Verify disconnected retry frequency is settable', ); + helper.recordPrivateApi('read.connectionManager.states.suspended.retryDelay'); expect(realtime.connection.connectionManager.states.suspended.retryDelay).to.equal( 456, 'Verify suspended retry frequency is settable', ); + helper.recordPrivateApi('read.connectionManager.options.timeouts.httpRequestTimeout'); expect(realtime.connection.connectionManager.options.timeouts.httpRequestTimeout).to.equal( 789, 'Verify http request timeout is settable', ); + helper.recordPrivateApi('read.connectionManager.options.timeouts.httpMaxRetryDuration'); expect(realtime.connection.connectionManager.options.timeouts.httpMaxRetryDuration).to.equal( 321, 'Verify http max retry duration is settable', @@ -290,6 +312,7 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { fallbackHosts: ['b', 'c', 'd', 'e'], }); /* Note: uses internal knowledge of connectionManager */ + helper.recordPrivateApi('read.connectionManager.httpHosts'); expect(realtime.connection.connectionManager.httpHosts.length).to.equal( 3, 'Verify hosts list is the expected length', @@ -297,6 +320,7 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { expect(realtime.connection.connectionManager.httpHosts[0]).to.equal('a', 'Verify given restHost is first'); /* Replace chooseTransportForHost with a spy, then try calling * chooseHttpTransport to see what host is picked */ + helper.recordPrivateApi('replace.connectionManager.tryATransport'); realtime.connection.connectionManager.tryATransport = function (transportParams, transport, cb) { switch (transportParams.host) { case 'a': @@ -332,7 +356,9 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { var realtime; try { realtime = helper.AblyRealtime({ transports: helper.availableTransports }); + helper.recordPrivateApi('read.connectionManager.baseTransport'); expect(realtime.connection.connectionManager.baseTransport).to.equal('comet'); + helper.recordPrivateApi('read.connectionManager.webSocketTransportAvailable'); expect(realtime.connection.connectionManager.webSocketTransportAvailable).to.be.ok; helper.closeAndFinish(done, realtime); } catch (err) { @@ -348,9 +374,12 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { try { var keyStr = helper.getTestApp().keys[0].keyStr; var realtime = helper.AblyRealtime({ key: keyStr, useTokenAuth: true }); + helper.recordPrivateApi('listen.connectionManager.transport.pending'); realtime.connection.connectionManager.once('transport.pending', function (state) { + helper.recordPrivateApi('read.connectionManager.pendingTransport'); var transport = realtime.connection.connectionManager.pendingTransport, originalOnProtocolMessage = transport.onProtocolMessage; + helper.recordPrivateApi('replace.transport.onProtocolMessage'); realtime.connection.connectionManager.pendingTransport.onProtocolMessage = function (message) { try { if (message.action === 4) { @@ -358,6 +387,7 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { message.connectionDetails.connectionKey = 'importantConnectionKey'; message.connectionDetails.clientId = 'customClientId'; } + helper.recordPrivateApi('call.transport.onProtocolMessage'); originalOnProtocolMessage.call(transport, message); } catch (err) { helper.closeAndFinish(done, realtime, err); @@ -394,6 +424,7 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { }); realtime.connection.once('connected', function () { try { + helper.recordPrivateApi('call.http._getHosts'); var hosts = new Ably.Rest._Http()._getHosts(realtime); /* restHost rather than realtimeHost as that's what connectionManager * knows about; converted to realtimeHost by the websocketTransport */ @@ -416,6 +447,7 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { fallbackHosts: [goodHost, 'b', 'c'], }); realtime.connection.once('connected', function () { + helper.recordPrivateApi('call.http._getHosts'); var hosts = new Ably.Realtime._Http()._getHosts(realtime); /* restHost rather than realtimeHost as that's what connectionManager * knows about; converted to realtimeHost by the websocketTransport */ diff --git a/test/realtime/message.test.js b/test/realtime/message.test.js index 7cee97f47..ab2cd80df 100644 --- a/test/realtime/message.test.js +++ b/test/realtime/message.test.js @@ -143,6 +143,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async txRealtime, rxRealtime; try { + helper.recordPrivateApi('call.Utils.mixin'); txRealtime = helper.AblyRealtime(helper.Utils.mixin(realtimeOpts, { autoConnect: false })); rxRealtime = helper.AblyRealtime(); var txChannel = txRealtime.channels.get('publishQueued_' + String(Math.random()).substr(2)); @@ -634,9 +635,11 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async realtime = helper.AblyRealtime({ clientId: clientId }); realtime.connection.once('connected', function () { + helper.recordPrivateApi('read.realtime.connection.connectionManager.activeProtocol.transport'); var transport = realtime.connection.connectionManager.activeProtocol.transport, originalSend = transport.send; + helper.recordPrivateApi('replace.transport.send'); transport.send = function (message) { try { if (message.action === 15) { @@ -644,6 +647,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async expect(!message.messages[0].clientId, 'client ID is not added by the client library as it is implicit').to .be.ok; } + helper.recordPrivateApi('call.transport.send'); originalSend.apply(transport, arguments); } catch (err) { helper.closeAndFinish(done, realtime, err); @@ -674,15 +678,18 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async realtime = helper.AblyRealtime({ clientId: clientId, transports: [helper.bestTransport] }); realtime.connection.once('connected', function () { + helper.recordPrivateApi('read.realtime.connection.connectionManager.activeProtocol.transport'); var transport = realtime.connection.connectionManager.activeProtocol.transport, originalSend = transport.send; + helper.recordPrivateApi('replace.transport.send'); transport.send = function (message) { try { if (message.action === 15) { expect(message.messages[0].name === 'event0', 'Outgoing message interecepted').to.be.ok; expect(message.messages[0].clientId === clientId, 'client ID is present when published to Ably').to.be.ok; } + helper.recordPrivateApi('call.transport.send'); originalSend.apply(transport, arguments); } catch (err) { helper.closeAndFinish(done, realtime, err); @@ -764,9 +771,11 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }, 500); // ensure that the message is not published }); + helper.recordPrivateApi('listen.connectionManager.transport.pending'); realtime.connection.connectionManager.on('transport.pending', function (transport) { var originalSend = transport.send; + helper.recordPrivateApi('replace.transport.send'); transport.send = function (message) { try { if (message.action === 15) { @@ -774,6 +783,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async expect(message.messages[0].clientId === invalidClientId, 'client ID is present when published to Ably') .to.be.ok; } + helper.recordPrivateApi('call.transport.send'); originalSend.apply(transport, arguments); } catch (err) { helper.closeAndFinish(done, realtime, err); @@ -820,6 +830,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async ++received; if (received === 2) { /* wait a tick to make sure no more messages come in */ + helper.recordPrivateApi('call.Platform.nextTick'); config.nextTick(function () { innercb(); }); @@ -901,6 +912,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async return cb(e); } // Wait for any errant messages to arrive before continuing + helper.recordPrivateApi('call.Platform.nextTick'); config.nextTick(cb); }, ); @@ -954,12 +966,14 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async return expect.fail('Listener should not fire'); }; channel.subscribe({ refType: 'com.ably.test', refTimeserial: '0123456789' }, listener); + helper.recordPrivateApi('call.filteredSubscriptions.has'); expect(channel.filteredSubscriptions.has(listener), 'Listener should initially be present').to.be.true; channel.unsubscribe(listener); expect( channel.filteredSubscriptions.has(listener), 'Listener should no longer be present after unsubscribing', ).to.be.false; + helper.recordPrivateApi('call.Platform.nextTick'); config.nextTick(cb); } catch (e) { cb(e); @@ -1038,6 +1052,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async channel = realtime.channels.get('maxMessageSize'); realtime.connection.once('connected', function () { + helper.recordPrivateApi('listen.connectionManager.connectiondetails'); connectionManager.once('connectiondetails', function (details) { Helper.whenPromiseSettles( channel.publish('foo', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'), @@ -1054,7 +1069,11 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async ); }); var connectionDetails = connectionManager.connectionDetails; + helper.recordPrivateApi('write.connectionManager.connectionDetails.maxMessageSize'); connectionDetails.maxMessageSize = 64; + helper.recordPrivateApi('call.realtime.connection.connectionManager.activeProtocol.getTransport'); + helper.recordPrivateApi('call.protocolMessageFromDeserialized'); + helper.recordPrivateApi('call.transport.onProtocolMessage'); connectionManager.activeProtocol.getTransport().onProtocolMessage( createPM({ action: 4, @@ -1099,6 +1118,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async channelOne.publish({ name: 'm', id: 'bundle_m', data: { expectedBundle: 9 } }); channelOne.publish('z_last', { expectedBundle: 10 }); + helper.recordPrivateApi('call.transport.onProtocolMessage'); var queue = realtime.connection.connectionManager.queuedMessages; var messages; try { diff --git a/test/realtime/presence.test.js b/test/realtime/presence.test.js index 21a568539..770092f78 100644 --- a/test/realtime/presence.test.js +++ b/test/realtime/presence.test.js @@ -416,6 +416,8 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async } cb(); }); + + helper.recordPrivateApi('call.PresenceMessage.fromValues'); presence.enter( PresenceMessage.fromValues({ extras: { headers: { key: 'value' } }, @@ -436,6 +438,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async } cb(); }); + helper.recordPrivateApi('call.PresenceMessage.fromValues'); presence.leave( PresenceMessage.fromValues({ extras: { headers: { otherKey: 'otherValue' } }, @@ -1191,6 +1194,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async var channel = client.channels.get('presenceClientIdIsImplicit'), presence = channel.presence; + helper.recordPrivateApi('replace.channel.sendPresence'); var originalSendPresence = channel.sendPresence; channel.sendPresence = function (presence, callback) { try { @@ -1199,6 +1203,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async helper.closeAndFinish(done, client, err); return; } + helper.recordPrivateApi('call.channel.sendPresence'); originalSendPresence.apply(channel, arguments); }; @@ -1237,13 +1242,16 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async transports: [helper.bestTransport], }; + helper.recordPrivateApi('call.Utils.mixin'); var realtimeBin = helper.AblyRealtime(helper.Utils.mixin(options, { useBinaryProtocol: true })); var realtimeJson = helper.AblyRealtime(helper.Utils.mixin(options, { useBinaryProtocol: false })); var runTest = function (realtime, callback) { + helper.recordPrivateApi('listen.connectionManager.transport.active'); realtime.connection.connectionManager.once('transport.active', function (transport) { var originalSend = transport.send; + helper.recordPrivateApi('replace.transport.send'); transport.send = function (message) { if (message.action === 14) { /* Message is formatted for Ably by the toJSON method, so need to @@ -1257,9 +1265,11 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async callback(err); return; } + helper.recordPrivateApi('replace.transport.send'); transport.send = originalSend; callback(); } + helper.recordPrivateApi('call.transport.send'); originalSend.apply(transport, arguments); }; @@ -1558,6 +1568,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }, function (cb) { if (!channel.presence.syncComplete) { + helper.recordPrivateApi('call.presence.waitSync'); channel.presence.members.waitSync(cb); } else { cb(); @@ -1572,7 +1583,9 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }, function (cb) { /* inject an additional member into the myMember set, then force a suspended state */ + helper.recordPrivateApi('read.connectionManager.connectionId'); var connId = realtime.connection.connectionManager.connectionId; + helper.recordPrivateApi('call.presence._myMembers.put'); channel.presence._myMembers.put({ action: 'enter', clientId: 'two', @@ -1600,8 +1613,10 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async * that realtime will feel it necessary to do a sync - if it doesn't, * we request one */ if (channel.presence.syncComplete) { + helper.recordPrivateApi('call.channel.sync'); channel.sync(); } + helper.recordPrivateApi('call.presence.waitSync'); channel.presence.members.waitSync(cb); }, function (cb) { @@ -1680,6 +1695,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }, function (cb) { if (!channel.presence.syncComplete) { + helper.recordPrivateApi('call.presence.waitSync'); channel.presence.members.waitSync(cb); } else { cb(); @@ -1698,7 +1714,9 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }, function (cb) { /* inject an additional member into the myMember set, then force a suspended state */ + helper.recordPrivateApi('read.connectionManager.connectionId'); var connId = realtime.connection.connectionManager.connectionId; + helper.recordPrivateApi('call.presence._myMembers.put'); channel.presence._myMembers.put({ action: 'enter', clientId: 'me', @@ -1761,6 +1779,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }, function (cb) { /* stub out attachimpl */ + helper.recordPrivateApi('replace.channel.attachImpl'); channel.attachImpl = function () {}; channel.attach(); @@ -1768,13 +1787,17 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async channel.presence.enterClient('client_' + i.toString(), i.toString()); } + helper.recordPrivateApi('replace.channel.attachImpl'); channel.attachImpl = originalAttachImpl; + + helper.recordPrivateApi('call.channel.checkPendingState'); channel.checkPendingState(); /* Now just wait for an enter. One enter implies all, they'll all be * sent in one protocol message */ channel.presence.subscribe('enter', function () { channel.presence.unsubscribe('enter'); + helper.recordPrivateApi('call.Platform.nextTick'); Ably.Realtime.Platform.Config.nextTick(cb); }); }, @@ -1845,6 +1868,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }, function (cb) { /* Inject an additional member locally */ + helper.recordPrivateApi('call.channel.processMessage'); channel .processMessage({ action: 14, @@ -1888,6 +1912,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async } cb(); }); + helper.recordPrivateApi('call.channel.sync'); channel.sync(); }, function (cb) { @@ -1978,6 +2003,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async cb(); }); /* Inject an ATTACHED with RESUMED and HAS_PRESENCE both false */ + helper.recordPrivateApi('call.protocolMessageFromDeserialized'); channel.processMessage( createPM({ action: 11, diff --git a/test/realtime/resume.test.js b/test/realtime/resume.test.js index 3593a2d49..c8a6d0950 100644 --- a/test/realtime/resume.test.js +++ b/test/realtime/resume.test.js @@ -75,8 +75,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; + helper.recordPrivateApi('listen.connectionManager.transport.active'); connectionManager.once('transport.active', function (transport) { try { + helper.recordPrivateApi('read.transport.params.mode'); expect(transport.params.mode).to.equal('resume', 'Verify reconnect is resume mode'); } catch (err) { callback(err); @@ -208,8 +210,10 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { rxCount = 0; rxRealtime.connection.connect(); var connectionManager = rxRealtime.connection.connectionManager; + helper.recordPrivateApi('listen.connectionManager.transport.active'); connectionManager.on('transport.active', function (transport) { try { + helper.recordPrivateApi('read.transport.params.mode'); expect(transport.params.mode).to.equal('resume', 'Verify reconnect is resume mode'); } catch (err) { callback(err); @@ -284,17 +288,23 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { }); }, function (cb) { + helper.recordPrivateApi('write.channel.state'); suspendedChannel.state = 'suspended'; Helper.whenPromiseSettles(attachedChannel.attach(), cb); }, function (cb) { /* Sabotage the resume */ - (connection.connectionManager.connectionKey = '_____!ablyjs_test_fake-key____'), + helper.recordPrivateApi('write.connectionManager.connectionKey'); + helper.recordPrivateApi('write.connectionManager.connectionId'); + helper.recordPrivateApi('write.connectionManager.msgSerial')( + (connection.connectionManager.connectionKey = '_____!ablyjs_test_fake-key____'), + ), (connection.connectionManager.connectionId = 'ablyjs_tes'); connection.connectionManager.msgSerial = 15; connection.once('disconnected', function () { cb(); }); + helper.recordPrivateApi('call.connectionManager.disconnectAllTransports'); connection.connectionManager.disconnectAllTransports(); }, function (cb) { @@ -306,7 +316,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'); + helper.recordPrivateApi('read.connectionManager.msgSerial'); expect(connection.connectionManager.msgSerial).to.equal(0, 'Check msgSerial is reset to 0'); + helper.recordPrivateApi('read.connectionManager.connectionId'); expect( connection.connectionManager.connectionId !== 'ablyjs_tes', 'Check connectionId is set by the new CONNECTED', @@ -356,6 +368,7 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { }, function (cb) { /* Sabotage the resume - use a valid but now-expired token */ + helper.recordPrivateApi('write.auth.tokenDetails.token'); realtime.auth.tokenDetails.token = badtoken.token; connection.once(function (stateChange) { try { @@ -366,6 +379,7 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { } cb(); }); + helper.recordPrivateApi('call.connectionManager.disconnectAllTransports'); connection.connectionManager.disconnectAllTransports(); }, function (cb) { @@ -403,7 +417,9 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { }); }, function (cb) { + helper.recordPrivateApi('read.auth.key'); var keyName = realtime.auth.key.split(':')[0]; + helper.recordPrivateApi('write.auth.key'); realtime.auth.key = keyName + ':wrong'; connection.once(function (stateChange) { try { @@ -414,6 +430,8 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { } cb(); }); + helper.recordPrivateApi('call.connectionManager.disconnectAllTransports'); + connection.connectionManager.disconnectAllTransports(); }, function (cb) { @@ -523,6 +541,7 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { helper.becomeSuspended(realtime, cb); }, function (cb) { + helper.recordPrivateApi('replace.connectionManager.tryATransport'); realtime.connection.connectionManager.tryATransport = function (transportParams) { try { expect(transportParams.mode).to.equal('clean', 'Check library didn’t try to resume'); @@ -552,10 +571,14 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { connectionManager = connection.connectionManager; connection.once('connected', function () { + helper.recordPrivateApi('write.connectionManager.lastActivity'); connectionManager.lastActivity = Date.now() - 10000000; /* noop-out onProtocolMessage so that a DISCONNECTED message doesn't * reset the last activity timer */ + helper.recordPrivateApi('call.realtime.connection.connectionManager.activeProtocol.getTransport'); + helper.recordPrivateApi('replace.transport.onProtocolMessage'); connectionManager.activeProtocol.getTransport().onProtocolMessage = function () {}; + helper.recordPrivateApi('replace.connectionManager.tryATransport'); connectionManager.tryATransport = function (transportParams) { try { expect(transportParams.mode).to.equal('clean', 'Check library didn’t try to resume'); @@ -565,6 +588,7 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { } helper.closeAndFinish(done, realtime); }; + helper.recordPrivateApi('call.connectionManager.disconnectAllTransports'); connectionManager.disconnectAllTransports(); }); }); @@ -595,9 +619,12 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { var resumed_receiver_realtime = helper.AblyRealtime(); var connectionManager = resumed_receiver_realtime.connection.connectionManager; + helper.recordPrivateApi('replace.connectionManager.send'); var sendOrig = connectionManager.send; connectionManager.send = function (msg, queueEvent, callback) { + helper.recordPrivateApi('call.ProtocolMessage.setFlag'); msg.setFlag('ATTACH_RESUME'); + helper.recordPrivateApi('call.connectionManager.send'); sendOrig.call(connectionManager, msg, queueEvent, callback); }; diff --git a/test/realtime/sync.test.js b/test/realtime/sync.test.js index 416d28a07..b699de48c 100644 --- a/test/realtime/sync.test.js +++ b/test/realtime/sync.test.js @@ -45,6 +45,8 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async channelName = 'syncexistingset', channel = realtime.channels.get(channelName); + helper.recordPrivateApi('call.protocolMessageFromDeserialized'); + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage( createPM({ action: 11, @@ -61,6 +63,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async async.series( [ function (cb) { + helper.recordPrivateApi('call.channel.processMessage'); channel .processMessage({ action: 16, @@ -104,6 +107,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }, function (cb) { /* Trigger another sync. Two has gone without so much as a `leave` message! */ + helper.recordPrivateApi('call.channel.processMessage'); channel .processMessage({ action: 16, @@ -166,6 +170,8 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async channelName = 'sync_member_arrives_in_middle', channel = realtime.channels.get(channelName); + helper.recordPrivateApi('call.protocolMessageFromDeserialized'); + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage( createPM({ action: 11, @@ -175,6 +181,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async ); /* First sync */ + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 16, channel: channelName, @@ -190,6 +197,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); /* A second sync, this time in multiple parts, with a presence message in the middle */ + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 16, channel: channelName, @@ -205,6 +213,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async ], }); + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 14, channel: channelName, @@ -219,6 +228,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async ], }); + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 16, channel: channelName, @@ -269,6 +279,8 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async channelName = 'sync_member_arrives_normally_after_came_in_sync', channel = realtime.channels.get(channelName); + helper.recordPrivateApi('call.protocolMessageFromDeserialized'); + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage( createPM({ action: 11, @@ -277,6 +289,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }), ); + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 16, channel: channelName, @@ -292,6 +305,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async ], }); + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 14, channel: channelName, @@ -306,6 +320,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async ], }); + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 16, channel: channelName, @@ -353,6 +368,8 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async channelName = 'sync_member_arrives_normally_before_comes_in_sync', channel = realtime.channels.get(channelName); + helper.recordPrivateApi('call.protocolMessageFromDeserialized'); + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage( createPM({ action: 11, @@ -361,6 +378,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }), ); + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 16, channel: channelName, @@ -376,6 +394,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async ], }); + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 14, channel: channelName, @@ -390,6 +409,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async ], }); + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 16, channel: channelName, @@ -438,6 +458,8 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async channelName = 'sync_ordering', channel = realtime.channels.get(channelName); + helper.recordPrivateApi('call.protocolMessageFromDeserialized'); + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage( createPM({ action: 11, @@ -446,6 +468,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async ); /* One enters */ + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 14, channel: channelName, @@ -461,6 +484,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); /* An earlier leave from one (should be ignored) */ + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 14, channel: channelName, @@ -476,6 +500,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); /* One adds some data in a newer msgSerial */ + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 14, channel: channelName, @@ -492,6 +517,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); /* Two enters */ + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 14, channel: channelName, @@ -507,6 +533,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); /* Two updates twice in the same message */ + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 14, channel: channelName, @@ -528,6 +555,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); /* Three enters */ + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 14, channel: channelName, @@ -544,6 +572,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async /* Synthesized leave for three (with earlier msgSerial, incompatible id, * and later timestamp) */ + helper.recordPrivateApi('call.channel.processMessage'); await channel.processMessage({ action: 14, channel: channelName, @@ -629,11 +658,15 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }, function (cb) { var originalProcessMessage = syncerChannel.processMessage; + helper.recordPrivateApi('replace.channel.processMessage'); syncerChannel.processMessage = async function (message) { + helper.recordPrivateApi('call.channel.processMessage'); await originalProcessMessage.apply(this, arguments); /* Inject an additional presence message after the first sync */ if (message.action === 16) { + helper.recordPrivateApi('replace.channel.processMessage'); syncerChannel.processMessage = originalProcessMessage; + helper.recordPrivateApi('call.channel.processMessage'); await syncerChannel.processMessage({ action: 14, id: 'messageid:0', diff --git a/test/realtime/utils.test.js b/test/realtime/utils.test.js index a32c266f0..b80ac10b0 100644 --- a/test/realtime/utils.test.js +++ b/test/realtime/utils.test.js @@ -10,6 +10,7 @@ define(['shared_helper', 'chai'], function (Helper, chai) { var retryAttempts = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; var initialTimeout = 15; + helper.recordPrivateApi('call.Utils.getRetryTime'); var retryTimeouts = retryAttempts.map((attempt) => helper.Utils.getRetryTime(initialTimeout, attempt)); expect(retryTimeouts.filter((timeout) => timeout >= 30).length).to.equal(0); diff --git a/test/rest/auth.test.js b/test/rest/auth.test.js index cbe7fe654..0bf4695b5 100644 --- a/test/rest/auth.test.js +++ b/test/rest/auth.test.js @@ -133,9 +133,12 @@ define(['chai', 'shared_helper', 'async', 'globals'], function (chai, Helper, as it('Token generation with explicit auth', async function () { const helper = this.helper; + helper.recordPrivateApi('call.auth.getAuthHeaders'); const authHeaders = await rest.auth.getAuthHeaders(); + helper.recordPrivateApi('write.auth.authOptions.requestHeaders'); rest.auth.authOptions.requestHeaders = authHeaders; var tokenDetails = await rest.auth.requestToken(); + helper.recordPrivateApi('delete.auth.authOptions.requestHeaders'); delete rest.auth.authOptions.requestHeaders; expect(tokenDetails.token, 'Verify token value').to.be.ok; expect(tokenDetails.issued && tokenDetails.issued >= currentTime, 'Verify token issued').to.be.ok; @@ -145,6 +148,7 @@ define(['chai', 'shared_helper', 'async', 'globals'], function (chai, Helper, as it('Token generation with explicit auth, different key', async function () { const helper = this.helper; + helper.recordPrivateApi('call.auth.getAuthHeaders'); const authHeaders = await rest.auth.getAuthHeaders(); var testKeyOpts = { key: helper.getTestApp().keys[1].keyStr }; var testCapability = JSON.parse(helper.getTestApp().keys[1].capability); @@ -280,7 +284,9 @@ define(['chai', 'shared_helper', 'async', 'globals'], function (chai, Helper, as const helper = this.helper; var currentKey = helper.getTestApp().keys[0]; var keys = { keyName: currentKey.keyName, keySecret: currentKey.keySecret }; + helper.recordPrivateApi('call.Utils.mixin'); var authParams = helper.Utils.mixin(keys, params); + helper.recordPrivateApi('call.Utils.toQueryString'); var authUrl = echoServer + '/createJWT' + helper.Utils.toQueryString(authParams); var restJWTRequester = helper.AblyRest({ authUrl: authUrl }); @@ -308,6 +314,7 @@ define(['chai', 'shared_helper', 'async', 'globals'], function (chai, Helper, as it('JWT request with invalid key', async function () { const helper = this.helper; var keys = { keyName: 'invalid.invalid', keySecret: 'invalidinvalid' }; + helper.recordPrivateApi('call.Utils.toQueryString'); var authUrl = echoServer + '/createJWT' + helper.Utils.toQueryString(keys); var restJWTRequester = helper.AblyRest({ authUrl: authUrl }); @@ -330,6 +337,7 @@ define(['chai', 'shared_helper', 'async', 'globals'], function (chai, Helper, as const helper = this.helper; var currentKey = helper.getTestApp().keys[0]; var keys = { keyName: currentKey.keyName, keySecret: currentKey.keySecret }; + helper.recordPrivateApi('call.Utils.toQueryString'); var authUrl = echoServer + '/createJWT' + helper.Utils.toQueryString(keys); var restJWTRequester = helper.AblyRest({ authUrl: authUrl }); @@ -349,6 +357,7 @@ define(['chai', 'shared_helper', 'async', 'globals'], function (chai, Helper, as it('Rest JWT with authCallback and invalid keys', async function () { const helper = this.helper; var keys = { keyName: 'invalid.invalid', keySecret: 'invalidinvalid' }; + helper.recordPrivateApi('call.Utils.toQueryString'); var authUrl = echoServer + '/createJWT' + helper.Utils.toQueryString(keys); var restJWTRequester = helper.AblyRest({ authUrl: authUrl }); diff --git a/test/rest/fallbacks.test.js b/test/rest/fallbacks.test.js index bac64944f..60e40f1e2 100644 --- a/test/rest/fallbacks.test.js +++ b/test/rest/fallbacks.test.js @@ -30,26 +30,34 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { var validUntil; var serverTime = await rest.time(); expect(serverTime, 'Check serverTime returned').to.be.ok; + helper.recordPrivateApi('read.rest._currentFallback'); var currentFallback = rest._currentFallback; expect(currentFallback, 'Check current fallback stored').to.be.ok; + helper.recordPrivateApi('read.rest._currentFallback.host'); expect(currentFallback && currentFallback.host).to.equal(goodHost, 'Check good host set'); + helper.recordPrivateApi('read.rest._currentFallback.validUntil'); validUntil = currentFallback.validUntil; /* now try again, check that this time it uses the remembered good endpoint straight away */ var serverTime = await rest.time(); expect(serverTime, 'Check serverTime returned').to.be.ok; var currentFallback = rest._currentFallback; + helper.recordPrivateApi('read.rest._currentFallback.validUntil'); expect(currentFallback.validUntil).to.equal( validUntil, 'Check validUntil is the same (implying currentFallback has not been re-set)', ); /* set the validUntil to the past and check that the stored fallback is forgotten */ var now = Date.now(); + helper.recordPrivateApi('write.rest._currentFallback.validUntil'); rest._currentFallback.validUntil = now - 1000; var serverTime = await rest.time(); expect(serverTime, 'Check serverTime returned').to.be.ok; + helper.recordPrivateApi('read.rest._currentFallback'); var currentFallback = rest._currentFallback; expect(currentFallback, 'Check current fallback re-stored').to.be.ok; + helper.recordPrivateApi('read.rest._currentFallback.host'); expect(currentFallback && currentFallback.host).to.equal(goodHost, 'Check good host set again'); + helper.recordPrivateApi('read.rest._currentFallback.validUntil'); expect(currentFallback.validUntil > now, 'Check validUntil has been re-set').to.be.ok; }); diff --git a/test/rest/history.test.js b/test/rest/history.test.js index 0841fd8b5..3df592450 100644 --- a/test/rest/history.test.js +++ b/test/rest/history.test.js @@ -46,6 +46,7 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { messages.forEach(function (msg) { ids[msg.id] = msg; }); + helper.recordPrivateApi('call.Utils.keysArray'); expect(helper.Utils.keysArray(ids).length).to.equal( testMessages.length, 'Verify correct number of distinct message ids found', @@ -69,6 +70,7 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { messages.forEach(function (msg) { ids[msg.id] = msg; }); + helper.recordPrivateApi('call.Utils.keysArray'); expect(helper.Utils.keysArray(ids).length).to.equal( testMessages.length, 'Verify correct number of distinct message ids found', @@ -107,6 +109,7 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { } } /* verify message ids are unique */ + helper.recordPrivateApi('call.Utils.keysArray'); expect(helper.Utils.keysArray(ids).length).to.equal( testMessages.length, 'Verify correct number of distinct message ids found', @@ -147,6 +150,7 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { } /* verify message ids are unique */ + helper.recordPrivateApi('call.Utils.keysArray'); expect(helper.Utils.keysArray(ids).length).to.equal( testMessages.length, 'Verify correct number of distinct message ids found', @@ -220,6 +224,7 @@ define(['shared_helper', 'async', 'chai'], function (Helper, async, chai) { } /* verify message ids are unique */ + helper.recordPrivateApi('call.Utils.keysArray'); expect(helper.Utils.keysArray(ids).length).to.equal( testMessages.length, 'Verify correct number of distinct message ids found', diff --git a/test/rest/http.test.js b/test/rest/http.test.js index eb1da43be..4dfcb357a 100644 --- a/test/rest/http.test.js +++ b/test/rest/http.test.js @@ -23,6 +23,7 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { * RSC7a */ it('Should send X-Ably-Version and Ably-Agent headers in get/post requests', async function () { + const helper = this.helper; var originalDo = rest.http.do; // Intercept Http.do with test @@ -33,6 +34,7 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { // This test should not directly validate version against Defaults.version, as // ultimately the version header has been derived from that value. expect(headers['X-Ably-Version']).to.equal('3', 'Verify current version number'); + helper.recordPrivateApi('read.Defaults.version'); expect(headers['Ably-Agent'].indexOf('ably-js/' + Defaults.version) > -1, 'Verify agent').to.be.ok; expect(headers['Ably-Agent'].indexOf('custom-agent/0.1.2') > -1, 'Verify custom agent').to.be.ok; @@ -48,9 +50,11 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { expect(headers['Ably-Agent'].indexOf('nodejs') > -1, 'Verify agent').to.be.ok; } + helper.recordPrivateApi('call.rest.http.do'); return originalDo.call(rest.http, method, path, headers, body, params); } + helper.recordPrivateApi('replace.rest.http.do'); rest.http.do = testRequestHandler; // Call all methods that use rest http calls @@ -63,12 +67,14 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { }); it('Should handle no content responses', async function () { + const helper = this.helper; //Intercept Http.do with test async function testRequestHandler() { return { error: null, body: null, headers: { 'X-Ably-Foo': 'headerValue' }, unpacked: false, statusCode: 204 }; } + helper.recordPrivateApi('replace.rest.http.do'); rest.http.do = testRequestHandler; const response = await rest.request('GET', '/foo', {}, null, {}); diff --git a/test/rest/init.test.js b/test/rest/init.test.js index db0af97b4..99ec05c18 100644 --- a/test/rest/init.test.js +++ b/test/rest/init.test.js @@ -22,6 +22,7 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { var keyStr = helper.getTestApp().keys[0].keyStr; var rest = new helper.Ably.Rest(keyStr); + helper.recordPrivateApi('read.rest.options.key'); expect(rest.options.key).to.equal(keyStr); }); @@ -35,18 +36,21 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { var tokenStr = tokenDetails.token, rest = new helper.Ably.Rest(tokenStr); + helper.recordPrivateApi('read.rest.options.token'); expect(rest.options.token).to.equal(tokenStr); }); it('Init with tls: false', function () { const helper = this.helper; var rest = helper.AblyRest({ tls: false, port: 123, tlsPort: 456 }); + helper.recordPrivateApi('call.rest.baseUri'); expect(rest.baseUri('example.com')).to.equal('http://example.com:123'); }); it('Init with tls: true', function () { const helper = this.helper; var rest = helper.AblyRest({ tls: true, port: 123, tlsPort: 456 }); + helper.recordPrivateApi('call.rest.baseUri'); expect(rest.baseUri('example.com')).to.equal('https://example.com:456'); }); @@ -54,6 +58,7 @@ define(['ably', 'shared_helper', 'chai'], function (Ably, Helper, chai) { it('Init without any tls key should enable tls', function () { const helper = this.helper; var rest = helper.AblyRest({ port: 123, tlsPort: 456 }); + helper.recordPrivateApi('call.rest.baseUri'); expect(rest.baseUri('example.com')).to.equal('https://example.com:456'); }); diff --git a/test/rest/message.test.js b/test/rest/message.test.js index e77d89724..5eccdb801 100644 --- a/test/rest/message.test.js +++ b/test/rest/message.test.js @@ -26,10 +26,12 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async channel = rest.channels.get('rest_implicit_client_id_0'); var originalPublish = channel._publish; + helper.recordPrivateApi('replace.restChannel._publish'); channel._publish = async function (requestBody) { var message = JSON.parse(requestBody)[0]; expect(message.name === 'event0', 'Outgoing message interecepted').to.be.ok; expect(!message.clientId, 'client ID is not added by the client library as it is implicit').to.be.ok; + helper.recordPrivateApi('call.restChannel._publish'); return originalPublish.apply(channel, arguments); }; @@ -49,6 +51,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async channel = rest.channels.get('rest_explicit_client_id_0'); var originalPublish = channel._publish; + helper.recordPrivateApi('replace.restChannel._publish'); channel._publish = async function (requestBody) { var message = JSON.parse(requestBody)[0]; expect(message.name === 'event0', 'Outgoing message interecepted').to.be.ok; @@ -56,6 +59,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async message.clientId == clientId, 'client ID is added by the client library as it is explicit in the publish', ).to.be.ok; + helper.recordPrivateApi('call.restChannel._publish'); return originalPublish.apply(channel, arguments); }; @@ -80,6 +84,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async channel = rest.channels.get('rest_explicit_client_id_1'); var originalPublish = channel._publish; + helper.recordPrivateApi('replace.restChannel._publish'); channel._publish = async function (requestBody) { var message = JSON.parse(requestBody)[0]; expect(message.name === 'event0', 'Outgoing message interecepted').to.be.ok; @@ -87,6 +92,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async message.clientId == invalidClientId, 'invalid client ID is added by the client library as it is explicit in the publish', ).to.be.ok; + helper.recordPrivateApi('call.restChannel._publish'); return originalPublish.apply(channel, arguments); }; @@ -150,6 +156,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async originalPublish = channel._publish, originalDoUri = Ably.Realtime._Http.doUri; + helper.recordPrivateApi('replace.restChannel._publish'); channel._publish = async function (requestBody) { var messageOne = JSON.parse(requestBody)[0]; var messageTwo = JSON.parse(requestBody)[1]; @@ -161,11 +168,15 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async expect(idTwo, 'id set on message 2').to.be.ok; expect(idOne && idOne.split(':')[1]).to.equal('0', 'check zero-based index'); expect(idTwo && idTwo.split(':')[1]).to.equal('1', 'check zero-based index'); + helper.recordPrivateApi('call.restChannel._publish'); return originalPublish.apply(channel, arguments); }; + helper.recordPrivateApi('replace.http.doUri'); Ably.Rest._Http.doUri = async function (method, uri, headers, body, params) { + helper.recordPrivateApi('call.http.doUri'); const resultPromise = originalDoUri(method, uri, headers, body, params); + helper.recordPrivateApi('replace.http.doUri'); Ably.Rest._Http.doUri = originalDoUri; const result = await resultPromise; if (result.error) { @@ -193,8 +204,10 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async var originalPublish = channel._publish; /* Stub out _publish to check params */ + helper.recordPrivateApi('replace.restChannel._publish'); channel._publish = async function (requestBody, headers, params) { expect(params && params.testParam).to.equal('testParamValue'); + helper.recordPrivateApi('call.restChannel._publish'); return originalPublish.apply(channel, arguments); }; diff --git a/test/rest/presence.test.js b/test/rest/presence.test.js index 1d5ab4046..b82ce6651 100644 --- a/test/rest/presence.test.js +++ b/test/rest/presence.test.js @@ -7,13 +7,15 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async var Crypto = Ably.Realtime.Platform.Crypto; var BufferUtils = Ably.Realtime.Platform.BufferUtils; - function cipherParamsFromConfig(cipherConfig) { + function cipherParamsFromConfig(cipherConfig, helper) { + helper.recordPrivateApi('new.Crypto.CipherParams'); var cipherParams = new Crypto.CipherParams(); for (var prop in cipherConfig) { cipherParams[prop] = cipherConfig[prop]; } cipherParams.keyLength = cipherConfig.keylength; delete cipherParams.keylength; // grr case differences + helper.recordPrivateApi('call.BufferUtils.base64Decode'); cipherParams.key = BufferUtils.base64Decode(cipherParams.key); cipherParams.iv = BufferUtils.base64Decode(cipherParams.iv); return cipherParams; @@ -33,7 +35,8 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async function presence_simple(operation) { return async function () { - var cipherParams = cipherParamsFromConfig(cipherConfig); + const helper = this.helper; + var cipherParams = cipherParamsFromConfig(cipherConfig, helper); var channel = rest.channels.get('persisted:presence_fixtures', { cipher: cipherParams }); var resultPage = await channel.presence[operation](); var presenceMessages = resultPage.items; diff --git a/test/rest/push.test.js b/test/rest/push.test.js index 9e969cd96..de603633b 100644 --- a/test/rest/push.test.js +++ b/test/rest/push.test.js @@ -83,6 +83,9 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async data: { foo: 'bar' }, }; + helper.recordPrivateApi('read.realtime.options'); + helper.recordPrivateApi('call.Defaults.getHost'); + helper.recordPrivateApi('call.realtime.baseUri'); var baseUri = realtime.baseUri(Ably.Rest.Platform.Defaults.getHost(realtime.options)); var pushRecipient = { transportType: 'ablyChannel', diff --git a/test/rest/request.test.js b/test/rest/request.test.js index 9e49ce64e..6f5fe7cc1 100644 --- a/test/rest/request.test.js +++ b/test/rest/request.test.js @@ -21,7 +21,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); }); - Helper.restTestOnJsonMsgpack('request_version', function (rest) { + Helper.restTestOnJsonMsgpack('request_version', function (rest, _, helper) { const version = 150; // arbitrarily chosen async function testRequestHandler(_, __, headers) { @@ -35,12 +35,14 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async return new Promise(() => {}); } + helper.recordPrivateApi('replace.rest.http.do'); rest.http.do = testRequestHandler; rest.request('get', '/time' /* arbitrarily chosen */, version, null, null, null); }); - Helper.restTestOnJsonMsgpack('request_time', async function (rest) { + Helper.restTestOnJsonMsgpack('request_time', async function (rest, _, helper) { + helper.recordPrivateApi('read.Defaults.protocolVersion'); const res = await rest.request('get', '/time', Defaults.protocolVersion, null, null, null); expect(res.statusCode).to.equal(200, 'Check statusCode'); expect(res.success).to.equal(true, 'Check success'); @@ -48,10 +50,11 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async expect(res.items.length).to.equal(1, 'Check array was of length 1'); }); - Helper.restTestOnJsonMsgpack('request_404', async function (rest) { + Helper.restTestOnJsonMsgpack('request_404', async function (rest, _, helper) { /* NB: can't just use /invalid or something as the CORS preflight will * fail. Need something superficially a valid path but where the actual * request fails */ + helper.recordPrivateApi('read.Defaults.protocolVersion'); const res = await rest.request( 'get', '/keys/ablyjs.test/requestToken', @@ -71,6 +74,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async const helper = this.helper; rest = helper.AblyRest({ restHost: helper.unroutableAddress }); try { + helper.recordPrivateApi('read.Defaults.protocolVersion'); var res = await rest.request('get', '/time', Defaults.protocolVersion, null, null, null); } catch (err) { expect(err, 'Check get an err').to.be.ok; @@ -81,20 +85,23 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); /* Use the request feature to publish, then retrieve (one at a time), some messages */ - Helper.restTestOnJsonMsgpack('request_post_get_messages', async function (rest, channelName) { + Helper.restTestOnJsonMsgpack('request_post_get_messages', async function (rest, channelName, helper) { var channelPath = '/channels/' + channelName + '/messages', msgone = { name: 'faye', data: 'whittaker' }, msgtwo = { name: 'martin', data: 'reed' }; + helper.recordPrivateApi('read.Defaults.protocolVersion'); var res = await rest.request('post', channelPath, Defaults.protocolVersion, null, msgone, null); expect(res.statusCode).to.equal(201, 'Check statusCode is 201'); expect(res.success).to.equal(true, 'Check post was a success'); expect(res.items && res.items.length).to.equal(1, 'Check number of results is as expected'); + helper.recordPrivateApi('read.Defaults.protocolVersion'); res = await rest.request('post', channelPath, Defaults.protocolVersion, null, msgtwo, null); expect(res.statusCode).to.equal(201, 'Check statusCode is 201'); expect(res.items && res.items.length).to.equal(1, 'Check number of results is as expected'); + helper.recordPrivateApi('read.Defaults.protocolVersion'); res = await rest.request( 'get', channelPath, @@ -171,6 +178,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async it('check' + method, async function () { const helper = this.helper; var restEcho = helper.AblyRest({ useBinaryProtocol: false, restHost: echoServerHost, tls: true }); + helper.recordPrivateApi('read.Defaults.protocolVersion'); var res = await restEcho.request(method, '/methods', Defaults.protocolVersion, {}, {}, {}); expect(res.items[0] && res.items[0].method).to.equal(method); });