Make sure the roster is fetched again if stream resumption fails

This commit is contained in:
JC Brand 2019-10-15 14:24:01 +02:00
parent 9d619820f9
commit 99805d2510
4 changed files with 77 additions and 10 deletions

View File

@ -54,23 +54,27 @@
`<iq from="romeo@montague.lit" id="${disco_iq.getAttribute('id')}" to="romeo@montague.lit" type="get" xmlns="jabber:client">`+ `<iq from="romeo@montague.lit" id="${disco_iq.getAttribute('id')}" to="romeo@montague.lit" type="get" xmlns="jabber:client">`+
`<pubsub xmlns="http://jabber.org/protocol/pubsub"><items node="eu.siacs.conversations.axolotl.devicelist"/></pubsub></iq>`); `<pubsub xmlns="http://jabber.org/protocol/pubsub"><items node="eu.siacs.conversations.axolotl.devicelist"/></pubsub></iq>`);
iq = IQ_stanzas.pop(); iq = IQ_stanzas[IQ_stanzas.length-1];
expect(Strophe.serialize(iq)).toBe( expect(Strophe.serialize(iq)).toBe(
`<iq id="${iq.getAttribute('id')}" type="get" xmlns="jabber:client"><query xmlns="jabber:iq:roster"/></iq>`); `<iq id="${iq.getAttribute('id')}" type="get" xmlns="jabber:client"><query xmlns="jabber:iq:roster"/></iq>`);
await test_utils.waitForRoster(_converse, 'current', 1);
expect(sent_stanzas.filter(s => (s.nodeName === 'r')).length).toBe(2); expect(sent_stanzas.filter(s => (s.nodeName === 'r')).length).toBe(2);
expect(_converse.session.get('unacked_stanzas').length).toBe(4); expect(_converse.session.get('unacked_stanzas').length).toBe(5);
// test handling of acks // test handling of acks
let ack = u.toStanza(`<a xmlns="urn:xmpp:sm:3" h="1"/>`); let ack = u.toStanza(`<a xmlns="urn:xmpp:sm:3" h="1"/>`);
_converse.connection._dataRecv(test_utils.createRequest(ack)); _converse.connection._dataRecv(test_utils.createRequest(ack));
expect(_converse.session.get('unacked_stanzas').length).toBe(3); expect(_converse.session.get('unacked_stanzas').length).toBe(4);
// test handling of ack requests // test handling of ack requests
let r = u.toStanza(`<r xmlns="urn:xmpp:sm:3"/>`); let r = u.toStanza(`<r xmlns="urn:xmpp:sm:3"/>`);
_converse.connection._dataRecv(test_utils.createRequest(r)); _converse.connection._dataRecv(test_utils.createRequest(r));
ack = await u.waitUntil(() => sent_stanzas.filter(s => (s.nodeName === 'a')).pop()); ack = await u.waitUntil(() => sent_stanzas.filter(s => (s.nodeName === 'a')).pop());
expect(Strophe.serialize(ack)).toBe('<a h="0" xmlns="urn:xmpp:sm:3"/>'); expect(Strophe.serialize(ack)).toBe('<a h="1" xmlns="urn:xmpp:sm:3"/>');
const disco_result = $iq({ const disco_result = $iq({
'type': 'result', 'type': 'result',
@ -88,7 +92,7 @@
ack = u.toStanza(`<a xmlns="urn:xmpp:sm:3" h="2"/>`); ack = u.toStanza(`<a xmlns="urn:xmpp:sm:3" h="2"/>`);
_converse.connection._dataRecv(test_utils.createRequest(ack)); _converse.connection._dataRecv(test_utils.createRequest(ack));
expect(_converse.session.get('unacked_stanzas').length).toBe(2); expect(_converse.session.get('unacked_stanzas').length).toBe(3);
r = u.toStanza(`<r xmlns="urn:xmpp:sm:3"/>`); r = u.toStanza(`<r xmlns="urn:xmpp:sm:3"/>`);
_converse.connection._dataRecv(test_utils.createRequest(r)); _converse.connection._dataRecv(test_utils.createRequest(r));
@ -99,15 +103,14 @@
_converse.connection.IQ_stanzas = []; _converse.connection.IQ_stanzas = [];
IQ_stanzas = _converse.connection.IQ_stanzas; IQ_stanzas = _converse.connection.IQ_stanzas;
_converse.api.connection.reconnect(); _converse.api.connection.reconnect();
stanza = await u.waitUntil(() => stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'resume')).pop());
sent_stanzas.filter(s => (s.tagName === 'resume')).pop()); expect(Strophe.serialize(stanza)).toEqual('<resume h="2" previd="some-long-sm-id" xmlns="urn:xmpp:sm:3"/>');
expect(Strophe.serialize(stanza)).toEqual('<resume h="1" previd="some-long-sm-id" xmlns="urn:xmpp:sm:3"/>');
result = u.toStanza(`<resumed xmlns="urn:xmpp:sm:3" h="another-sequence-number" previd="some-long-sm-id"/>`); result = u.toStanza(`<resumed xmlns="urn:xmpp:sm:3" h="another-sequence-number" previd="some-long-sm-id"/>`);
_converse.connection._dataRecv(test_utils.createRequest(result)); _converse.connection._dataRecv(test_utils.createRequest(result));
// Another <enable> stanza doesn't get sent out // Another <enable> stanza doesn't get sent out
expect(sizzle('enable', sent_stanzas).length).toBe(0); expect(sent_stanzas.filter(s => (s.tagName === 'enable')).length).toBe(1);
expect(_converse.session.get('smacks_enabled')).toBe(true); expect(_converse.session.get('smacks_enabled')).toBe(true);
await u.waitUntil(() => IQ_stanzas.length === 2); await u.waitUntil(() => IQ_stanzas.length === 2);
@ -119,11 +122,67 @@
`<query xmlns="http://jabber.org/protocol/disco#info"/></iq>`); `<query xmlns="http://jabber.org/protocol/disco#info"/></iq>`);
// We don't fetch the roster again because it's cached. // We don't fetch the roster again because it's cached.
expect(_converse.session.get('roster_fetched')).toBeFalsy(); expect(_converse.session.get('roster_fetched')).toBeTruthy();
expect(IQ_stanzas.filter(iq => sizzle('query[xmlns="jabber:iq:roster"]', iq).pop()).length).toBe(0); expect(IQ_stanzas.filter(iq => sizzle('query[xmlns="jabber:iq:roster"]', iq).pop()).length).toBe(0);
await _converse.api.waitUntil('statusInitialized'); await _converse.api.waitUntil('statusInitialized');
done(); done();
})); }));
it("might not resume and the session will then be reset",
mock.initConverse(
['chatBoxesInitialized'],
{ 'auto_login': false,
'enable_smacks': true,
'show_controlbox_by_default': true,
'smacks_max_unacked_stanzas': 2
},
async function (done, _converse) {
const view = _converse.chatboxviews.get('controlbox');
spyOn(view, 'renderControlBoxPane').and.callThrough();
_converse.api.user.login('romeo@montague.lit/orchard', 'secret');
const sent_stanzas = _converse.connection.sent_stanzas;
let stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'enable')).pop());
expect(Strophe.serialize(stanza)).toEqual('<enable resume="true" xmlns="urn:xmpp:sm:3"/>');
let result = u.toStanza(`<enabled xmlns="urn:xmpp:sm:3" id="some-long-sm-id" resume="true"/>`);
_converse.connection._dataRecv(test_utils.createRequest(result));
await test_utils.waitForRoster(_converse, 'current', 1);
// test session resumption
_converse.api.connection.reconnect();
stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'resume')).pop());
expect(Strophe.serialize(stanza)).toEqual('<resume h="1" previd="some-long-sm-id" xmlns="urn:xmpp:sm:3"/>');
result = u.toStanza(
`<failed xmlns="urn:xmpp:sm:3" h="another-sequence-number">`+
`<item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>`+
`</failed>`);
_converse.connection._dataRecv(test_utils.createRequest(result));
// Session data gets reset
expect(_converse.session.get('smacks_enabled')).toBe(false);
expect(_converse.session.get('num_stanzas_handled')).toBe(0);
expect(_converse.session.get('num_stanzas_handled_by_server')).toBe(0);
expect(_converse.session.get('num_stanzas_since_last_ack')).toBe(0);
expect(_converse.session.get('unacked_stanzas').length).toBe(0);
expect(_converse.session.get('roster_fetched')).toBeFalsy();
await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'enable')).length === 2);
stanza = sent_stanzas.filter(s => (s.tagName === 'enable')).pop();
expect(Strophe.serialize(stanza)).toEqual('<enable resume="true" xmlns="urn:xmpp:sm:3"/>');
result = u.toStanza(`<enabled xmlns="urn:xmpp:sm:3" id="another-long-sm-id" resume="true"/>`);
_converse.connection._dataRecv(test_utils.createRequest(result));
expect(_converse.session.get('smacks_enabled')).toBe(true);
// Check that the roster gets fetched
await test_utils.waitForRoster(_converse, 'current', 1);
done();
}));
}); });
})); }));

View File

@ -939,6 +939,8 @@ converse.plugins.add('converse-roster', {
} }
} }
_converse.api.listen.on('streamResumptionFailed', () => _converse.session.set('roster_fetched', false));
_converse.api.listen.on('clearSession', () => { _converse.api.listen.on('clearSession', () => {
clearPresences(); clearPresences();
if (_converse.shouldClearCache()) { if (_converse.shouldClearCache()) {

View File

@ -132,6 +132,11 @@ converse.plugins.add('converse-smacks', {
_converse.log(el.outerHTML, Strophe.LogLevel.ERROR); _converse.log(el.outerHTML, Strophe.LogLevel.ERROR);
} }
resetSessionData(); resetSessionData();
/**
* Triggered when the XEP-0198 stream could not be resumed.
* @event _converse#streamResumptionFailed
*/
_converse.api.trigger('streamResumptionFailed');
return true; return true;
} }

View File

@ -262,6 +262,7 @@
try { try {
await func(_done, _converse); await func(_done, _converse);
} catch(e) { } catch(e) {
console.error(e);
fail(e); fail(e);
_done(); _done();
} }