Commit 1ce32878 authored by JC Brand's avatar JC Brand

Also add tests for case where contact declines request.

Did a bit of renaming and fixed a bug in updateContact where a user wasn't
created when it should have been.
parent 838ad136
......@@ -3484,7 +3484,7 @@
'status': ''
}, attributes));
this.on('destroy', function () { this.removeFromRoster(); }.bind(this));
this.on('destroy', this.removeFromRoster, this);
},
subscribe: function (message) {
......@@ -3506,7 +3506,7 @@
return this;
},
acknowledgeSubscription: function () {
ackSubscribe: function () {
/* Upon receiving the presence stanza of type "subscribed",
* the user SHOULD acknowledge receipt of that subscription
* state notification by sending a presence stanza of type
......@@ -3518,6 +3518,19 @@
}));
},
ackUnsubscribe: function (jid) {
/* Upon receiving the presence stanza of type "unsubscribed",
* the user SHOULD acknowledge receipt of that subscription state
* notification by sending a presence stanza of type "unsubscribe"
* this step lets the user's server know that it MUST no longer
* send notification of the subscription state change to the user.
* Parameters:
* (String) jid - The Jabber ID of the user who is unsubscribing
*/
converse.connection.send($pres({'type': 'unsubscribe', 'to': this.get('jid')}));
this.destroy(); // Will cause removeFromRoster to be called.
},
unauthorize: function (message) {
/* Unauthorize this contact's presence subscription
* Parameters:
......@@ -3841,19 +3854,6 @@
}
},
unsubscribe: function (jid) {
/* Upon receiving the presence stanza of type "unsubscribed",
* the user SHOULD acknowledge receipt of that subscription state
* notification by sending a presence stanza of type "unsubscribe"
* this step lets the user's server know that it MUST no longer
* send notification of the subscription state change to the user.
* Parameters:
* (String) jid - The Jabber ID of the user who is unsubscribing
*/
converse.connection.send($pres({'type': 'unsubscribe', 'to': jid}));
this.get(jid).destroy(); // Will cause removeFromRoster to be called.
},
getNumOnlineContacts: function () {
var count = 0,
ignored = ['offline', 'unavailable'],
......@@ -3936,7 +3936,7 @@
groups.push(Strophe.getText(group));
});
if (!contact) {
if (subscription === "none" || subscription === "remove") {
if ((subscription === "none" && ask === null) || (subscription === "remove")) {
return; // We're lazy when adding contacts.
}
this.create({
......@@ -4032,13 +4032,13 @@
contact.save({'status': status_message.text()});
}
if (presence_type === 'subscribed' && contact) {
contact.acknowledgeSubscription();
contact.ackSubscribe();
} else if (presence_type === 'unsubscribed' && contact) {
contact.ackUnsubscribe();
} else if (presence_type === 'unsubscribe') {
return;
} else if (presence_type === 'subscribe') {
this.handleIncomingSubscription(jid);
} else if (presence_type === 'unsubscribed') {
this.unsubscribe(bare_jid);
} else if (presence_type === 'unavailable' && contact) {
contact.save({'chat_status': (contact.removeResource(resource) === 0) ? "offline" : chat_status});
} else if (contact) { // presence_type is undefined
......
......@@ -58,7 +58,7 @@
/* The process by which a user subscribes to a contact, including
* the interaction between roster items and subscription states.
*/
var contact, stanza, sentStanza, iq_id;
var contact, stanza, sent_stanza, IQ_id;
runs($.proxy(function () {
var panel = this.chatboxviews.get('controlbox').contactspanel;
spyOn(panel, "addContactFromForm").andCallThrough();
......@@ -68,8 +68,8 @@
spyOn(this, "getVCard").andCallThrough();
var sendIQ = this.connection.sendIQ;
spyOn(this.connection, 'sendIQ').andCallFake(function (iq, callback, errback) {
sentStanza = iq;
iq_id = sendIQ.bind(this)(iq, callback, errback);
sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
panel.delegateEvents(); // Rebind all events so that our spy gets called
......@@ -114,8 +114,8 @@
* </iq>
*/
expect(converse.roster.sendContactAddIQ).toHaveBeenCalled();
expect(sentStanza.toLocaleString()).toBe(
"<iq type='set' xmlns='jabber:client' id='"+iq_id+"'>"+
expect(sent_stanza.toLocaleString()).toBe(
"<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
"<query xmlns='jabber:iq:roster'>"+
"<item jid='contact@example.org' name='contact@example.org'/>"+
"</query>"+
......@@ -141,7 +141,7 @@
*/
var create = converse.roster.create;
spyOn(converse.connection, 'send').andCallFake(function (stanza) {
sentStanza = stanza;
sent_stanza = stanza;
});
spyOn(converse.roster, 'create').andCallFake(function () {
contact = create.apply(converse.roster, arguments);
......@@ -157,11 +157,11 @@
/*
* <iq type='result' id='set1'/>
*/
stanza = $iq({'type': 'result', 'id':iq_id});
stanza = $iq({'type': 'result', 'id':IQ_id});
this.connection._dataRecv(test_utils.createRequest(stanza));
// A contact should now have been created
expect(this.roster.get('contact@example.org') instanceof converse.RosterContact).toBeTruthy();
expect(this.roster.get('contact@example.org') instanceof this.RosterContact).toBeTruthy();
expect(contact.get('jid')).toBe('contact@example.org');
expect(this.getVCard).toHaveBeenCalled();
......@@ -172,7 +172,7 @@
* <presence to='contact@example.org' type='subscribe'/>
*/
expect(contact.subscribe).toHaveBeenCalled();
expect(sentStanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
"<presence to='contact@example.org' type='subscribe' xmlns='jabber:client'/>"
);
/* As a result, the user's server MUST initiate a second roster
......@@ -204,7 +204,7 @@
this.connection._dataRecv(test_utils.createRequest(stanza));
expect(converse.roster.updateContact).toHaveBeenCalled();
}, this));
waits(50); // Needed, due to debounce
waits(50);
runs($.proxy(function () {
// Check that the user is now properly shown as a pending
// contact in the roster.
......@@ -214,7 +214,7 @@
var $contacts = $header.parent().nextUntil('dt', 'dd');
expect($contacts.length).toBe(1);
spyOn(contact, "acknowledgeSubscription").andCallThrough();
spyOn(contact, "ackSubscribe").andCallThrough();
/* Here we assume the "happy path" that the contact
* approves the subscription request
*
......@@ -228,15 +228,15 @@
'from': 'contact@example.org',
'type': 'subscribed'
});
sentStanza = ""; // Reset
sent_stanza = ""; // Reset
this.connection._dataRecv(test_utils.createRequest(stanza));
/* Upon receiving the presence stanza of type "subscribed",
* the user SHOULD acknowledge receipt of that
* subscription state notification by sending a presence
* stanza of type "subscribe".
*/
expect(contact.acknowledgeSubscription).toHaveBeenCalled();
expect(sentStanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
expect(contact.ackSubscribe).toHaveBeenCalled();
expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
"<presence type='subscribe' to='contact@example.org' xmlns='jabber:client'/>"
);
......@@ -256,8 +256,8 @@
* </query>
* </iq>
*/
iq_id = converse.connection.getUniqueId('roster');
stanza = $iq({'type': 'set', 'id': iq_id})
IQ_id = converse.connection.getUniqueId('roster');
stanza = $iq({'type': 'set', 'id': IQ_id})
.c('query', {'xmlns': 'jabber:iq:roster'})
.c('item', {
'jid': 'contact@example.org',
......@@ -265,8 +265,8 @@
'name': 'contact@example.org'});
this.connection._dataRecv(test_utils.createRequest(stanza));
// Check that the IQ set was acknowledged.
expect(sentStanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
"<iq type='result' id='"+iq_id+"' from='dummy@localhost/resource' xmlns='jabber:client'/>"
expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
"<iq type='result' id='"+IQ_id+"' from='dummy@localhost/resource' xmlns='jabber:client'/>"
);
expect(converse.roster.updateContact).toHaveBeenCalled();
......@@ -317,7 +317,7 @@
* <presence to='contact@example.org' type='subscribed'/>
*/
expect(contact.authorize).toHaveBeenCalled();
expect(sentStanza.toLocaleString()).toBe(
expect(sent_stanza.toLocaleString()).toBe(
"<presence to='contact@example.org' type='subscribed' xmlns='jabber:client'/>"
);
......@@ -352,15 +352,90 @@
}, converse));
it("Alternate Flow: Contact Declines Subscription Request", $.proxy(function () {
// TODO
}, converse));
/* The process by which a user subscribes to a contact, including
* the interaction between roster items and subscription states.
*/
var contact, stanza, sent_stanza, sent_IQ, IQ_id;
runs($.proxy(function () {
// Add a new roster contact via roster push
stanza = $iq({'type': 'set'}).c('query', {'xmlns': 'jabber:iq:roster'})
.c('item', {
'jid': 'contact@example.org',
'subscription': 'none',
'ask': 'subscribe',
'name': 'contact@example.org'});
this.connection._dataRecv(test_utils.createRequest(stanza));
}, this));
waits(50);
runs($.proxy(function () {
// A pending contact should now exist.
contact = this.roster.get('contact@example.org');
expect(this.roster.get('contact@example.org') instanceof this.RosterContact).toBeTruthy();
spyOn(contact, "ackUnsubscribe").andCallThrough();
it("Creating a Mutual Subscription", $.proxy(function () {
// TODO
}, converse));
var send = this.connection.send;
spyOn(converse.connection, 'send').andCallFake(function (stanza) {
sent_stanza = stanza;
});
var sendIQ = this.connection.sendIQ;
spyOn(this.connection, 'sendIQ').andCallFake(function (iq, callback, errback) {
sent_IQ = iq;
});
/* We now assume the contact declines the subscription
* requests.
*
/* Upon receiving the presence stanza of type "unsubscribed"
* addressed to the user, the user's server (1) MUST deliver
* that presence stanza to the user and (2) MUST initiate a
* roster push to all of the user's available resources that
* have requested the roster, containing an updated roster
* item for the contact with the 'subscription' attribute
* set to a value of "none" and with no 'ask' attribute:
*
* <presence
* from='contact@example.org'
* to='user@example.com'
* type='unsubscribed'/>
*
* <iq type='set'>
* <query xmlns='jabber:iq:roster'>
* <item
* jid='contact@example.org'
* subscription='none'
* name='MyContact'>
* <group>MyBuddies</group>
* </item>
* </query>
* </iq>
*/
stanza = $pres({
'to': converse.bare_jid,
'from': 'contact@example.org',
'type': 'unsubscribed'
});
this.connection._dataRecv(test_utils.createRequest(stanza));
/* Upon receiving the presence stanza of type "unsubscribed",
* the user SHOULD acknowledge receipt of that subscription
* state notification through either "affirming" it by
* sending a presence stanza of type "unsubscribe
*/
expect(contact.ackUnsubscribe).toHaveBeenCalled();
expect(sent_stanza.toLocaleString()).toBe(
"<presence type='unsubscribe' to='contact@example.org' xmlns='jabber:client'/>"
);
it("Alternate Flow: User Declines Subscription Request", $.proxy(function () {
// TODO
/* Converse.js will then also automatically remove the
* contact from the user's roster.
*/
expect(sent_IQ.toLocaleString()).toBe(
"<iq type='set' xmlns='jabber:client'>"+
"<query xmlns='jabber:iq:roster'>"+
"<item jid='contact@example.org' subscription='remove'/>"+
"</query>"+
"</iq>"
);
}, this));
}, converse));
}, converse, mock, test_utils));
}, converse, mock, test_utils));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment