Skip to content

Commit 67a1a7f

Browse files
ECO-4787: Convert a couple of tests to use interception proxy
As an example of how to use the proxy and its test suite client class.
1 parent 12efcfc commit 67a1a7f

File tree

2 files changed

+160
-135
lines changed

2 files changed

+160
-135
lines changed

test/realtime/auth.test.js

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
'use strict';
22

3-
define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async, chai) {
3+
define(['ably', 'shared_helper', 'async', 'chai', 'interception_proxy_client'], function (
4+
Ably,
5+
Helper,
6+
async,
7+
chai,
8+
interceptionProxyClient,
9+
) {
410
var currentTime;
511
var exampleTokenDetails;
612
var exports = {};
@@ -1167,42 +1173,51 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async
11671173
* @spec RTN22
11681174
*/
11691175
it('mocked_reauth', function (done) {
1170-
var helper = this.test.helper,
1171-
rest = helper.AblyRest(),
1172-
authCallback = function (tokenParams, callback) {
1173-
// Request a token (should happen twice)
1174-
Helper.whenPromiseSettles(rest.auth.requestToken(tokenParams, null), function (err, tokenDetails) {
1175-
if (err) {
1176-
helper.closeAndFinish(done, realtime, err);
1177-
return;
1178-
}
1179-
callback(null, tokenDetails);
1180-
});
1181-
},
1182-
realtime = helper.AblyRealtime({ authCallback: authCallback, transports: [helper.bestTransport] });
1176+
interceptionProxyClient.intercept(done, (done, interceptionContext) => {
1177+
var helper = this.test.helper,
1178+
rest = helper.AblyRest(),
1179+
authCallback = function (tokenParams, callback) {
1180+
// Request a token (should happen twice)
1181+
Helper.whenPromiseSettles(rest.auth.requestToken(tokenParams, null), function (err, tokenDetails) {
1182+
if (err) {
1183+
helper.closeAndFinish(done, realtime, err);
1184+
return;
1185+
}
1186+
callback(null, tokenDetails);
1187+
});
1188+
},
1189+
realtime = helper.AblyRealtime({ authCallback: authCallback, transports: [helper.bestTransport] });
11831190

1184-
realtime.connection.once('connected', function () {
1185-
helper.recordPrivateApi('read.connectionManager.activeProtocol.transport');
1186-
var transport = realtime.connection.connectionManager.activeProtocol.transport,
1187-
originalSend = transport.send;
1188-
helper.recordPrivateApi('replace.transport.send');
1189-
/* Spy on transport.send to detect the outgoing AUTH */
1190-
transport.send = function (message) {
1191-
if (message.action === 17) {
1192-
try {
1193-
expect(message.auth.accessToken, 'Check AUTH message structure is as expected').to.be.ok;
1194-
helper.closeAndFinish(done, realtime);
1195-
} catch (err) {
1196-
helper.closeAndFinish(done, realtime, err);
1191+
realtime.connection.once('connected', function () {
1192+
/* Spy on client messages to detect the outgoing AUTH */
1193+
interceptionContext.transformClientMessage = ({ deserialized: message }) => {
1194+
if (message.action === 17) {
1195+
// TODO return value? the original code didn’t call originalSend. We should either:
1196+
// - make sure that we always return something (i.e. force it on to callers)
1197+
// - make sure that if nothing is returned then the interception proxy client makes this very obvious
1198+
// - make sure to clean up outstanding messages when the `intercept`-created `done` is called
1199+
//
1200+
// I think this is what’s causing this in the logs:
1201+
// Interception proxy client: got result of transforming message d814955d-8a15-4c2f-b873-1bd0c3448635 undefined
1202+
// and what's hence causing Realtime to send
1203+
// message: 'Invalid websocket message (decode failure). (See https://help.ably.io/error/40000 for help.)',
1204+
//
1205+
// TODO
1206+
// should we have a separate "spy" interception proxy API that doesn’t require a return value?
1207+
try {
1208+
expect(message.auth.accessToken, 'Check AUTH message structure is as expected').to.be.ok;
1209+
helper.closeAndFinish(done, realtime);
1210+
} catch (err) {
1211+
helper.closeAndFinish(done, realtime, err);
1212+
}
1213+
return null;
1214+
} else {
1215+
return message;
11971216
}
1198-
} else {
1199-
helper.recordPrivateApi('call.transport.send');
1200-
originalSend.call(this, message);
1201-
}
1202-
};
1203-
/* Inject a fake AUTH from realtime */
1204-
helper.recordPrivateApi('call.transport.onProtocolMessage');
1205-
transport.onProtocolMessage({ action: 17 });
1217+
};
1218+
/* Inject a fake AUTH from realtime */
1219+
interceptionContext.injectMessage(interceptionContext.latestConnectionID, { action: 17 }, false);
1220+
});
12061221
});
12071222
});
12081223

test/realtime/connection.test.js

Lines changed: 110 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
'use strict';
22

3-
define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async, chai) {
3+
define(['ably', 'shared_helper', 'async', 'chai', 'interception_proxy_client'], function (
4+
Ably,
5+
Helper,
6+
async,
7+
chai,
8+
interceptionProxyClient,
9+
) {
410
var expect = chai.expect;
511
var createPM = Ably.protocolMessageFromDeserialized;
612

@@ -185,119 +191,123 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, Helper, async
185191
* @spec RTN19a2
186192
*/
187193
it('connectionQueuing', function (done) {
188-
var helper = this.test.helper,
189-
realtime = helper.AblyRealtime({ transports: [helper.bestTransport] }),
190-
channel = realtime.channels.get('connectionQueuing'),
191-
connectionManager = realtime.connection.connectionManager;
192-
193-
realtime.connection.once('connected', function () {
194-
helper.recordPrivateApi('read.connectionManager.activeProtocol.transport');
195-
var transport = connectionManager.activeProtocol.transport;
196-
Helper.whenPromiseSettles(channel.attach(), function (err) {
197-
if (err) {
198-
helper.closeAndFinish(done, realtime, err);
199-
return;
200-
}
194+
interceptionProxyClient.intercept(done, (done, interceptionContext) => {
195+
var helper = this.test.helper,
196+
realtime = helper.AblyRealtime({ transports: [helper.bestTransport] }),
197+
channel = realtime.channels.get('connectionQueuing'),
198+
connectionManager = realtime.connection.connectionManager;
201199

202-
let transportSendCallback;
200+
realtime.connection.once('connected', function () {
201+
Helper.whenPromiseSettles(channel.attach(), function (err) {
202+
if (err) {
203+
helper.closeAndFinish(done, realtime, err);
204+
return;
205+
}
203206

204-
helper.recordPrivateApi('replace.transport.send');
205-
/* Sabotage sending the message */
206-
transport.send = function (msg) {
207-
if (msg.action == 15) {
208-
expect(msg.msgSerial).to.equal(0, 'Expect msgSerial to be 0');
207+
let transportSendCallback;
209208

210-
if (!transportSendCallback) {
211-
done(new Error('transport.send override called before transportSendCallback populated'));
212-
}
209+
/* Sabotage sending the message */
210+
interceptionContext.transformClientMessage = (msg) => {
211+
if (msg.deserialized.action == 15) {
212+
expect(msg.deserialized.msgSerial).to.equal(0, 'Expect msgSerial to be 0');
213213

214-
transportSendCallback(null);
215-
}
216-
};
214+
if (!transportSendCallback) {
215+
done(new Error('transport.send override called before transportSendCallback populated'));
216+
}
217217

218-
let publishCallback;
218+
transportSendCallback(null);
219+
}
220+
};
219221

220-
async.series(
221-
[
222-
function (cb) {
223-
transportSendCallback = cb;
222+
let publishCallback;
224223

225-
/* Sabotaged publish */
226-
Helper.whenPromiseSettles(channel.publish('first', null), function (err) {
227-
if (!publishCallback) {
228-
done(new Error('publish completed before publishCallback populated'));
229-
}
230-
publishCallback(err);
231-
});
232-
},
224+
async.series(
225+
[
226+
function (cb) {
227+
transportSendCallback = cb;
233228

234-
// We wait for transport.send to recieve the message that we just
235-
// published before we proceed to disconnecting the transport, to
236-
// make sure that the message got marked as `sendAttempted`.
229+
/* Sabotaged publish */
230+
Helper.whenPromiseSettles(channel.publish('first', null), function (err) {
231+
if (!publishCallback) {
232+
done(new Error('publish completed before publishCallback populated'));
233+
}
234+
publishCallback(err);
235+
});
236+
},
237237

238-
function (cb) {
239-
async.parallel(
240-
[
241-
function (cb) {
242-
publishCallback = function (err) {
243-
try {
244-
expect(!err, 'Check publish happened (eventually) without err').to.be.ok;
245-
} catch (err) {
246-
cb(err);
247-
return;
248-
}
249-
cb();
250-
};
251-
},
252-
function (cb) {
253-
/* After the disconnect, on reconnect, spy on transport.send again */
254-
helper.recordPrivateApi('listen.connectionManager.transport.pending');
255-
connectionManager.once('transport.pending', function (transport) {
256-
var oldSend = transport.send;
238+
// We wait for transport.send to recieve the message that we just
239+
// published before we proceed to disconnecting the transport, to
240+
// make sure that the message got marked as `sendAttempted`.
257241

258-
helper.recordPrivateApi('replace.transport.send');
259-
transport.send = function (msg, msgCb) {
260-
if (msg.action === 15) {
261-
if (msg.messages[0].name === 'first') {
262-
try {
263-
expect(msg.msgSerial).to.equal(0, 'Expect msgSerial of original message to still be 0');
264-
expect(msg.messages.length).to.equal(
265-
1,
266-
'Expect second message to not have been merged with the attempted message',
267-
);
268-
} catch (err) {
269-
cb(err);
270-
return;
271-
}
272-
} else if (msg.messages[0].name === 'second') {
273-
try {
274-
expect(msg.msgSerial).to.equal(1, 'Expect msgSerial of new message to be 1');
275-
} catch (err) {
276-
cb(err);
277-
return;
278-
}
279-
cb();
280-
}
242+
function (cb) {
243+
async.parallel(
244+
[
245+
function (cb) {
246+
publishCallback = function (err) {
247+
try {
248+
expect(!err, 'Check publish happened (eventually) without err').to.be.ok;
249+
} catch (err) {
250+
cb(err);
251+
return;
281252
}
282-
helper.recordPrivateApi('call.transport.send');
283-
oldSend.call(transport, msg, msgCb);
253+
cb();
284254
};
285-
channel.publish('second', null);
286-
});
255+
},
256+
function (cb) {
257+
/* After the disconnect, on reconnect, spy on transport.send again */
258+
helper.recordPrivateApi('listen.connectionManager.transport.pending');
259+
connectionManager.once('transport.pending', function (transport) {
260+
// TODO does the identity of this transport matter, and can we replace the `transport.pending` check with something external too (e.g. detecting a new connection)? perhaps let's have an EventEmitter interface on the interception context that says when there's a new connection or something
261+
interceptionContext.transformClientMessage = function (msg) {
262+
if (msg.deserialized.action === 15) {
263+
if (msg.deserialized.messages[0].name === 'first') {
264+
try {
265+
expect(msg.deserialized.msgSerial).to.equal(
266+
0,
267+
'Expect msgSerial of original message to still be 0',
268+
);
269+
expect(msg.deserialized.messages.length).to.equal(
270+
1,
271+
'Expect second message to not have been merged with the attempted message',
272+
);
273+
} catch (err) {
274+
cb(err);
275+
return msg.deserialized;
276+
}
277+
} else if (msg.deserialized.messages[0].name === 'second') {
278+
try {
279+
expect(msg.deserialized.msgSerial).to.equal(
280+
1,
281+
'Expect msgSerial of new message to be 1',
282+
);
283+
} catch (err) {
284+
cb(err);
285+
return msg.deserialized;
286+
}
287+
cb();
288+
}
289+
}
290+
291+
// preserve the message
292+
return msg.deserialized;
293+
};
294+
channel.publish('second', null);
295+
});
287296

288-
/* Disconnect the transport (will automatically reconnect and resume) () */
289-
helper.recordPrivateApi('call.connectionManager.disconnectAllTransports');
290-
connectionManager.disconnectAllTransports();
291-
},
292-
],
293-
cb,
294-
);
297+
/* Disconnect the transport (will automatically reconnect and resume) () */
298+
helper.recordPrivateApi('call.connectionManager.disconnectAllTransports');
299+
connectionManager.disconnectAllTransports();
300+
},
301+
],
302+
cb,
303+
);
304+
},
305+
],
306+
function (err) {
307+
helper.closeAndFinish(done, realtime, err);
295308
},
296-
],
297-
function (err) {
298-
helper.closeAndFinish(done, realtime, err);
299-
},
300-
);
309+
);
310+
});
301311
});
302312
});
303313
});

0 commit comments

Comments
 (0)