diff --git a/test/browser/modular.test.js b/test/browser/modular.test.js index 739b1becb..3b529e894 100644 --- a/test/browser/modular.test.js +++ b/test/browser/modular.test.js @@ -507,6 +507,39 @@ function registerAblyModularTests(Helper) { ); } + async function testIsAbleToDecryptHistoryMessages(helper, clientClassConfig) { + const clientOptions = helper.ablyClientOptions(); + + const client = new clientClassConfig.clientClass({ + ...clientOptions, + plugins: { + ...clientClassConfig.additionalPlugins, + FetchRequest, + Crypto, + }, + }); + + await (clientClassConfig.isRealtime ? monitorConnectionThenCloseAndFinish : async (helper, op) => await op())( + helper, + async () => { + const channelName = 'encrypted_history', + messageText = 'Test message'; + + const key = await generateRandomKey(); + + const channel = client.channels.get(channelName, { cipher: { key: key } }); + await channel.publish('event0', messageText); + let items; + await helper.waitFor(async () => { + items = (await channel.history()).items; + return items.length > 0; + }, 10_000); + expect(items[0].data).to.equal(messageText); + }, + client, + ); + } + for (const clientClassConfig of [ { clientClass: BaseRest, isRealtime: false }, { @@ -522,6 +555,22 @@ function registerAblyModularTests(Helper) { }); }); } + + for (const clientClassConfig of [ + { clientClass: BaseRest, isRealtime: false }, + { + clientClass: BaseRealtime, + additionalPlugins: { WebSocketTransport, Rest }, + isRealtime: true, + }, + ]) { + describe(clientClassConfig.clientClass.name, () => { + /** @nospec */ + it('is able to decrypt history messages', async function () { + await testIsAbleToDecryptHistoryMessages(this.test.helper, clientClassConfig); + }); + }); + } }); }); diff --git a/test/common/modules/shared_helper.js b/test/common/modules/shared_helper.js index 46c4732b0..8b059038d 100644 --- a/test/common/modules/shared_helper.js +++ b/test/common/modules/shared_helper.js @@ -483,6 +483,15 @@ define([ dumpPrivateApiUsage() { privateApiRecorder.dump(); } + + async waitFor(condition, remaining) { + const success = await condition(); + if (success || remaining <= 0) { + return success; + } + await this.setTimeoutAsync(100); + return this.waitFor(condition, remaining - 100); + } } SharedHelper.testOnAllTransports.skip = function (thisInDescribe, name, testFn) { diff --git a/test/realtime/crypto.test.js b/test/realtime/crypto.test.js index 18df2f11e..f6da97e55 100644 --- a/test/realtime/crypto.test.js +++ b/test/realtime/crypto.test.js @@ -773,6 +773,31 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async }); }); + /** + * @spec RSL5a + */ + it('encrypted history', async function () { + if (!Crypto) { + done(new Error('Encryption not supported')); + return; + } + + const helper = this.test.helper, + rest = helper.AblyRest(), + channelName = 'encrypted_history', + messageText = 'Test message'; + + const key = await Crypto.generateRandomKey(); + const channel = rest.channels.get(channelName, { cipher: { key: key } }); + await channel.publish('event0', messageText); + let items; + await helper.waitFor(async () => { + items = (await channel.history()).items; + return items.length > 0; + }, 10_000); + expect(items[0].data).to.equal(messageText); + }); + /** * Connect twice to the service, using different cipher keys. * Publish an encrypted message on that channel using