summaryrefslogtreecommitdiff
path: root/tests/twisted/vcard/set-contact-info.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/twisted/vcard/set-contact-info.py')
-rw-r--r--tests/twisted/vcard/set-contact-info.py302
1 files changed, 302 insertions, 0 deletions
diff --git a/tests/twisted/vcard/set-contact-info.py b/tests/twisted/vcard/set-contact-info.py
new file mode 100644
index 000000000..080a24686
--- /dev/null
+++ b/tests/twisted/vcard/set-contact-info.py
@@ -0,0 +1,302 @@
+
+"""
+Test ContactInfo setting support.
+"""
+
+from servicetest import (EventPattern, call_async, assertEquals, assertLength,
+ assertContains, sync_dbus)
+from gabbletest import exec_test, acknowledge_iq, sync_stream
+import constants as cs
+
+from twisted.words.xish import xpath
+from twisted.words.protocols.jabber.client import IQ
+
+def repeat_previous_vcard(stream, iq, previous):
+ result = IQ(stream, 'result')
+ result['id'] = iq['id']
+ to = iq.getAttribute('to')
+
+ if to is not None:
+ result["from"] = to
+
+ result.addRawXml(previous.firstChildElement().toXml())
+ stream.send(result)
+
+def test(q, bus, conn, stream):
+ conn.Connect()
+ _, event = q.expect_many(
+ EventPattern('dbus-signal', signal='StatusChanged',
+ args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]),
+ EventPattern('stream-iq', to=None, query_ns='vcard-temp',
+ query_name='vCard'),
+ )
+
+ sync_stream(q, stream)
+ sync_dbus(bus, q, conn)
+
+ acknowledge_iq(stream, event.stanza)
+
+ call_async(q, conn.ContactInfo, 'SetContactInfo',
+ [(u'fn', [], [u'Wee Ninja']),
+ (u'n', [], [u'Ninja', u'Wee', u'', u'', u'-san']),
+ (u'org', [], ['Collabora, Ltd.']),
+ (u'adr', ['type=work','type=postal','type=parcel'],
+ ['', '', '11 Kings Parade', 'Cambridge', 'Cambridgeshire',
+ 'CB2 1SJ', 'UK']),
+ (u'label', ['type=work'], [
+ '11 Kings Parade\n'
+ 'Cambridge\n'
+ 'Cambridgeshire\n'
+ 'CB2 1SJ\n'
+ 'UK\n']),
+ (u'tel', ['type=voice','type=work'], ['+44 1223 362967']),
+ (u'tel', ['type=voice','type=work'], ['+44 7700 900753']),
+ (u'email', ['type=internet','type=pref'],
+ ['wee.ninja@collabora.co.uk']),
+ (u'email', ['type=internet'], ['wee.ninja@example.com']),
+ (u'x-jabber', [], ['wee.ninja@collabora.co.uk']),
+ (u'x-jabber', [], ['wee.ninja@example.com']),
+ (u'url', [], ['http://www.thinkgeek.com/geektoys/plush/8823/']),
+ (u'nickname', [], [u'HR Ninja']),
+ (u'nickname', [], [u'Enforcement Ninja'])])
+
+ vcard_set_event = q.expect('stream-iq', iq_type='set',
+ query_ns='vcard-temp', query_name='vCard')
+
+ assertLength(2, xpath.queryForNodes('/iq/vCard/NICKNAME',
+ vcard_set_event.stanza))
+ nicknames = []
+ for nickname in xpath.queryForNodes('/iq/vCard/NICKNAME',
+ vcard_set_event.stanza):
+ nicknames.append(str(nickname))
+ assertEquals(['HR Ninja', 'Enforcement Ninja'], nicknames)
+
+ assertEquals(None, xpath.queryForNodes('/iq/vCard/PHOTO',
+ vcard_set_event.stanza))
+ assertLength(1, xpath.queryForNodes('/iq/vCard/N',
+ vcard_set_event.stanza))
+ assertEquals('Wee', xpath.queryForString('/iq/vCard/N/GIVEN',
+ vcard_set_event.stanza))
+ assertEquals('Ninja', xpath.queryForString('/iq/vCard/N/FAMILY',
+ vcard_set_event.stanza))
+ assertEquals('-san', xpath.queryForString('/iq/vCard/N/SUFFIX',
+ vcard_set_event.stanza))
+ assertEquals('Wee Ninja', xpath.queryForString('/iq/vCard/FN',
+ vcard_set_event.stanza))
+
+ assertLength(1, xpath.queryForNodes('/iq/vCard/ORG',
+ vcard_set_event.stanza))
+ assertEquals('Collabora, Ltd.',
+ xpath.queryForString('/iq/vCard/ORG/ORGNAME',
+ vcard_set_event.stanza))
+ assertEquals(None, xpath.queryForNodes('/iq/vCard/ORG/ORGUNIT',
+ vcard_set_event.stanza))
+
+ assertLength(1, xpath.queryForNodes('/iq/vCard/LABEL',
+ vcard_set_event.stanza))
+ lines = xpath.queryForNodes('/iq/vCard/LABEL/LINE', vcard_set_event.stanza)
+ assertLength(5, lines)
+ for i, exp_line in enumerate(['11 Kings Parade', 'Cambridge',
+ 'Cambridgeshire', 'CB2 1SJ', 'UK']):
+ assertEquals(exp_line, str(lines[i]))
+
+ assertLength(2, xpath.queryForNodes('/iq/vCard/TEL',
+ vcard_set_event.stanza))
+ for tel in xpath.queryForNodes('/iq/vCard/TEL', vcard_set_event.stanza):
+ assertLength(1, xpath.queryForNodes('/TEL/NUMBER', tel))
+ assertContains(xpath.queryForString('/TEL/NUMBER', tel),
+ ('+44 1223 362967', '+44 7700 900753'))
+ assertLength(1, xpath.queryForNodes('/TEL/VOICE', tel))
+ assertLength(1, xpath.queryForNodes('/TEL/WORK', tel))
+
+ assertLength(2, xpath.queryForNodes('/iq/vCard/EMAIL',
+ vcard_set_event.stanza))
+ for email in xpath.queryForNodes('/iq/vCard/EMAIL',
+ vcard_set_event.stanza):
+ assertContains(xpath.queryForString('/EMAIL/USERID', email),
+ ('wee.ninja@example.com', 'wee.ninja@collabora.co.uk'))
+ assertLength(1, xpath.queryForNodes('/EMAIL/INTERNET', email))
+ if 'collabora' in xpath.queryForString('/EMAIL/USERID', email):
+ assertLength(1, xpath.queryForNodes('/EMAIL/PREF', email))
+ else:
+ assertEquals(None, xpath.queryForNodes('/EMAIL/PREF', email))
+
+ assertLength(2, xpath.queryForNodes('/iq/vCard/JABBERID',
+ vcard_set_event.stanza))
+ for jid in xpath.queryForNodes('/iq/vCard/JABBERID',
+ vcard_set_event.stanza):
+ assertContains(xpath.queryForString('/JABBERID', jid),
+ ('wee.ninja@example.com', 'wee.ninja@collabora.co.uk'))
+
+ acknowledge_iq(stream, vcard_set_event.stanza)
+ q.expect_many(
+ EventPattern('dbus-return', method='SetContactInfo'),
+ EventPattern('dbus-signal', signal='AliasesChanged',
+ predicate=lambda e: e.args[0][0][1] == 'HR Ninja'),
+ EventPattern('dbus-signal', signal='ContactInfoChanged'),
+ )
+
+ # Exercise various invalid SetContactInfo operations
+ sync_stream(q, stream)
+ sync_dbus(bus, q, conn)
+
+ forbidden = [EventPattern('stream-iq', query_ns='vcard-temp')]
+ q.forbid_events(forbidden)
+
+ # unknown field
+ call_async(q, conn.ContactInfo, 'SetContactInfo',
+ [('x-salary', [], ['547 espressos per month'])])
+ q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT)
+
+ # not enough values for a simple field
+ call_async(q, conn.ContactInfo, 'SetContactInfo',
+ [('fn', [], [])])
+ q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT)
+
+ # too many values for a simple field
+ call_async(q, conn.ContactInfo, 'SetContactInfo',
+ [('fn', [], ['Wee', 'Ninja'])])
+ q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT)
+
+ # unsupported type-parameter for a simple field
+ call_async(q, conn.ContactInfo, 'SetContactInfo',
+ [('fn', ['language=ja'], ['Wee Ninja'])])
+ q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT)
+
+ # unsupported type-parameter for a structured field
+ call_async(q, conn.ContactInfo, 'SetContactInfo',
+ [(u'n', ['language=ja'], [u'Ninja', u'Wee', u'', u'', u'-san'])])
+ q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT)
+
+ # unsupported type-parameter for LABEL
+ call_async(q, conn.ContactInfo, 'SetContactInfo',
+ [('label', ['language=en'], ['Collabora Ltd.\n11 Kings Parade'])])
+ q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT)
+
+ # not enough values for LABEL
+ call_async(q, conn.ContactInfo, 'SetContactInfo',
+ [('label', [], [])])
+ q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT)
+
+ # too many values for LABEL
+ call_async(q, conn.ContactInfo, 'SetContactInfo',
+ [('label', [], ['11 Kings Parade', 'Cambridge'])])
+ q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT)
+
+ # unsupported type-parameter for ORG
+ call_async(q, conn.ContactInfo, 'SetContactInfo',
+ [('org', ['language=en'], ['Collabora Ltd.'])])
+ q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT)
+
+ # empty ORG
+ call_async(q, conn.ContactInfo, 'SetContactInfo',
+ [('org', [], [])])
+ q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT)
+
+ # not enough values for N
+ call_async(q, conn.ContactInfo, 'SetContactInfo',
+ [('n', [], ['Ninja'])])
+ q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT)
+
+ # too many values for N
+ call_async(q, conn.ContactInfo, 'SetContactInfo',
+ [('n', [],
+ 'what could it mean if you have too many field values?'.split())])
+ q.expect('dbus-error', method='SetContactInfo', name=cs.INVALID_ARGUMENT)
+
+ q.unforbid_events(forbidden)
+
+ # Following a reshuffle, Company Policy Enforcement is declared to be
+ # a sub-department within Human Resources, and the ninja no longer
+ # qualifies for a company phone
+
+ vcard_in = [(u'fn', [], [u'Wee Ninja']),
+ (u'n', [], [u'Ninja', u'Wee', u'', u'', u'-san']),
+ (u'org', [], ['Collabora, Ltd.',
+ 'Human Resources', 'Company Policy Enforcement']),
+ (u'adr', ['type=work','type=postal','type=parcel'],
+ ['', '', '11 Kings Parade', 'Cambridge', 'Cambridgeshire',
+ 'CB2 1SJ', 'UK']),
+ (u'tel', ['type=voice','type=work'], ['+44 1223 362967']),
+ (u'email', ['type=internet','type=pref'],
+ ['wee.ninja@collabora.co.uk']),
+ (u'email', ['type=internet'], ['wee.ninja@example.com']),
+ (u'url', [], ['http://www.thinkgeek.com/geektoys/plush/8823/']),
+ (u'nickname', [], [u'HR Ninja']),
+ (u'nickname', [], [u'Enforcement Ninja'])]
+
+ call_async(q, conn.ContactInfo, 'SetContactInfo', vcard_in)
+
+ event = q.expect('stream-iq', iq_type='get', query_ns='vcard-temp',
+ query_name='vCard')
+ repeat_previous_vcard(stream, event.stanza, vcard_set_event.stanza)
+
+ _, vcard_set_event = q.expect_many(
+ EventPattern('dbus-signal', signal='ContactInfoChanged'),
+ EventPattern('stream-iq', iq_type='set', query_ns='vcard-temp',
+ query_name='vCard'),
+ )
+
+ assertLength(1, xpath.queryForNodes('/iq/vCard/ORG',
+ vcard_set_event.stanza))
+ assertEquals('Collabora, Ltd.',
+ xpath.queryForString('/iq/vCard/ORG/ORGNAME',
+ vcard_set_event.stanza))
+ units = xpath.queryForNodes('/iq/vCard/ORG/ORGUNIT',
+ vcard_set_event.stanza)
+ assertLength(2, units)
+ for i, exp_unit in enumerate(['Human Resources',
+ 'Company Policy Enforcement']):
+ assertEquals(exp_unit, str(units[i]))
+
+ assertLength(1, xpath.queryForNodes('/iq/vCard/TEL',
+ vcard_set_event.stanza))
+ for tel in xpath.queryForNodes('/iq/vCard/TEL', vcard_set_event.stanza):
+ assertLength(1, xpath.queryForNodes('/TEL/NUMBER', tel))
+ assertEquals('+44 1223 362967',
+ xpath.queryForString('/TEL/NUMBER', tel))
+ assertLength(1, xpath.queryForNodes('/TEL/VOICE', tel))
+ assertLength(1, xpath.queryForNodes('/TEL/WORK', tel))
+
+ acknowledge_iq(stream, vcard_set_event.stanza)
+ _, event = q.expect_many(
+ EventPattern('dbus-return', method='SetContactInfo'),
+ EventPattern('dbus-signal', signal='ContactInfoChanged'),
+ )
+
+ vcard_out = event.args[1][:]
+
+ # the only change we expect to see is that perhaps the fields are
+ # re-ordered, and perhaps the types on the 'tel' are re-ordered
+
+ assertEquals(vcard_in[4][0], 'tel')
+ vcard_in[4][1].sort()
+ assertEquals(vcard_out[4][0], 'tel')
+ vcard_out[4][1].sort()
+ assertEquals(vcard_in, vcard_out)
+
+ # Finally, the ninja decides that publishing his contact details is not
+ # very ninja-like, and decides to be anonymous. The first (most important)
+ # of his nicknames from the old vCard is kept, due to nickname's dual role
+ # as ContactInfo and the alias.
+ call_async(q, conn.ContactInfo, 'SetContactInfo', [])
+
+ event = q.expect('stream-iq', iq_type='get', query_ns='vcard-temp',
+ query_name='vCard')
+ repeat_previous_vcard(stream, event.stanza, vcard_set_event.stanza)
+
+ vcard_set_event = q.expect('stream-iq', iq_type='set',
+ query_ns='vcard-temp', query_name='vCard')
+ assertLength(1, xpath.queryForNodes('/iq/vCard/*',
+ vcard_set_event.stanza))
+ assertEquals('HR Ninja', xpath.queryForString('/iq/vCard/NICKNAME',
+ vcard_set_event.stanza))
+
+ acknowledge_iq(stream, vcard_set_event.stanza)
+ q.expect_many(
+ EventPattern('dbus-return', method='SetContactInfo'),
+ EventPattern('dbus-signal', signal='ContactInfoChanged'),
+ )
+
+if __name__ == '__main__':
+ exec_test(test)