소스 검색

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.
JC Brand 10 년 전
부모
커밋
1ce328783c
2개의 변경된 파일120개의 추가작업 그리고 45개의 파일을 삭제
  1. 19 19
      converse.js
  2. 101 26
      spec/protocol.js

+ 19 - 19
converse.js

@@ -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

+ 101 - 26
spec/protocol.js

@@ -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));