Changeset View
Changeset View
Standalone View
Standalone View
tests/unit/test-011-wallace_resources.py
import pykolab | import pykolab | ||||
import logging | import logging | ||||
import datetime | import datetime | ||||
from pykolab import itip | from pykolab import itip | ||||
from pykolab.imap import IMAP | |||||
from icalendar import Calendar | from icalendar import Calendar | ||||
from email import message | from email import message | ||||
from email import message_from_string | from email import message_from_string | ||||
from wallace import module_resources | from wallace import module_resources | ||||
from twisted.trial import unittest | from twisted.trial import unittest | ||||
# define some iTip MIME messages | # define some iTip MIME messages | ||||
Show All 22 Lines | |||||
BEGIN:VCALENDAR | BEGIN:VCALENDAR | ||||
VERSION:2.0 | VERSION:2.0 | ||||
PRODID:-//Roundcube Webmail 0.9-0.3.el6.kolab_3.0//NONSGML Calendar//EN | PRODID:-//Roundcube Webmail 0.9-0.3.el6.kolab_3.0//NONSGML Calendar//EN | ||||
CALSCALE:GREGORIAN | CALSCALE:GREGORIAN | ||||
METHOD:REQUEST | METHOD:REQUEST | ||||
BEGIN:VEVENT | BEGIN:VEVENT | ||||
UID:626421779C777FBE9C9B85A80D04DDFA-A4BF5BBB9FEAA271 | UID:626421779C777FBE9C9B85A80D04DDFA-A4BF5BBB9FEAA271 | ||||
DTSTAMP:20120713T1254140 | DTSTAMP:20120713T125414 | ||||
DTSTART;TZID=3DEurope/London:20120713T100000 | DTSTART;TZID=3DEurope/London:20120713T100000 | ||||
DTEND;TZID=3DEurope/London:20120713T110000 | DTEND;TZID=3DEurope/London:20120713T110000 | ||||
SUMMARY:test | SUMMARY:test | ||||
DESCRIPTION:test | DESCRIPTION:test | ||||
ORGANIZER;CN=3D"Doe, John":mailto:doe@example.org | ORGANIZER;CN=3D"Doe, John":mailto:doe@example.org | ||||
ATTENDEE;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DNEEDS-ACTION;RSVP=3DTRUE:mailt= | ATTENDEE;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DNEEDS-ACTION;RSVP=3DTRUE:mailt= | ||||
o:resource-collection-car@example.org | o:resource-collection-car@example.org | ||||
ATTENDEE;ROLE=3DOPT-PARTICIPANT;PARTSTAT=3DNEEDS-ACTION;RSVP=3DTRUE:mailto:anoth= | ATTENDEE;ROLE=3DOPT-PARTICIPANT;PARTSTAT=3DNEEDS-ACTION;RSVP=3DTRUE:mailto:anoth= | ||||
Show All 17 Lines | |||||
BEGIN:VCALENDAR | BEGIN:VCALENDAR | ||||
VERSION:2.0 | VERSION:2.0 | ||||
PRODID:-//Roundcube Webmail 0.9-0.3.el6.kolab_3.0//NONSGML Calendar//EN | PRODID:-//Roundcube Webmail 0.9-0.3.el6.kolab_3.0//NONSGML Calendar//EN | ||||
CALSCALE:GREGORIAN | CALSCALE:GREGORIAN | ||||
METHOD:REQUEST | METHOD:REQUEST | ||||
BEGIN:VEVENT | BEGIN:VEVENT | ||||
UID:626421779C777FBE9C9B85A80D04DDFA-A4BF5BBB9FEAA271 | UID:626421779C777FBE9C9B85A80D04DDFA-A4BF5BBB9FEAA271 | ||||
DTSTAMP:20120713T1254140 | DTSTAMP:20120713T125414 | ||||
DTSTART;TZID=3DEurope/London:20120713T100000 | DTSTART;TZID=3DEurope/London:20120713T100000 | ||||
DTEND;TZID=3DEurope/London:20120713T110000 | DTEND;TZID=3DEurope/London:20120713T110000 | ||||
SUMMARY:test | SUMMARY:test | ||||
DESCRIPTION:test | DESCRIPTION:test | ||||
ORGANIZER;CN=3D"Doe, John":mailto:doe@example.org | ORGANIZER;CN=3D"Doe, John":mailto:doe@example.org | ||||
ATTENDEE;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DACCEPTED;RSVP=3DTRUE:mailt= | ATTENDEE;ROLE=3DREQ-PARTICIPANT;PARTSTAT=3DACCEPTED;RSVP=3DTRUE:mailt= | ||||
o:resource-collection-car@example.org | o:resource-collection-car@example.org | ||||
TRANSP:OPAQUE | TRANSP:OPAQUE | ||||
Show All 13 Lines | def setUp(self): | ||||
# monkey-patch the pykolab.auth module to check API calls | # monkey-patch the pykolab.auth module to check API calls | ||||
# without actually connecting to LDAP | # without actually connecting to LDAP | ||||
self.patch(pykolab.auth.Auth, "connect", self._mock_nop) | self.patch(pykolab.auth.Auth, "connect", self._mock_nop) | ||||
self.patch(pykolab.auth.Auth, "disconnect", self._mock_nop) | self.patch(pykolab.auth.Auth, "disconnect", self._mock_nop) | ||||
self.patch(pykolab.auth.Auth, "find_resource", self._mock_find_resource) | self.patch(pykolab.auth.Auth, "find_resource", self._mock_find_resource) | ||||
self.patch(pykolab.auth.Auth, "get_entry_attributes", self._mock_get_entry_attributes) | self.patch(pykolab.auth.Auth, "get_entry_attributes", self._mock_get_entry_attributes) | ||||
self.patch(pykolab.auth.Auth, "search_entry_by_attribute", self._mock_search_entry_by_attribute) | self.patch(pykolab.auth.Auth, "search_entry_by_attribute", self._mock_search_entry_by_attribute) | ||||
# Mock IMAP operations | |||||
self.patch(pykolab.imap.IMAP, "connect", self._mock_nop) | |||||
self.patch(pykolab.imap.IMAP, "disconnect", self._mock_nop) | |||||
self.patch(pykolab.imap.IMAP, "set_acl", self._mock_nop) | |||||
self.patch(pykolab.imap.IMAP, "append", self._mock_imap_append) | |||||
# intercept calls to smtplib.SMTP.sendmail() | # intercept calls to smtplib.SMTP.sendmail() | ||||
import smtplib | import smtplib | ||||
self.patch(smtplib.SMTP, "__init__", self._mock_smtp_init) | self.patch(smtplib.SMTP, "__init__", self._mock_smtp_init) | ||||
self.patch(smtplib.SMTP, "quit", self._mock_nop) | self.patch(smtplib.SMTP, "quit", self._mock_nop) | ||||
self.patch(smtplib.SMTP, "connect", self._mock_smtp_init) | self.patch(smtplib.SMTP, "connect", self._mock_smtp_init) | ||||
self.patch(smtplib.SMTP, "sendmail", self._mock_smtp_sendmail) | self.patch(smtplib.SMTP, "sendmail", self._mock_smtp_sendmail) | ||||
self.smtplog = [] | self.smtplog = [] | ||||
self.imap_append_log = [] | |||||
def _mock_nop(self, domain=None): | def _mock_nop(self, domain=None, arg3=None, arg4=None): | ||||
pass | pass | ||||
def _mock_find_resource(self, address): | def _mock_find_resource(self, address): | ||||
if 'resource' not in address: | if 'resource' not in address: | ||||
return [] | return [] | ||||
(prefix, domain) = address.split('@') | (prefix, domain) = address.split('@') | ||||
entry_dn = "cn=" + prefix + ",ou=Resources,dc=" + ",dc=".join(domain.split('.')) | entry_dn = "cn=" + prefix + ",ou=Resources,dc=" + ",dc=".join(domain.split('.')) | ||||
Show All 11 Lines | class TestWallaceResources(unittest.TestCase): | ||||
def _mock_smtp_init(self, host=None, port=None, local_hostname=None, timeout=0): | def _mock_smtp_init(self, host=None, port=None, local_hostname=None, timeout=0): | ||||
pass | pass | ||||
def _mock_smtp_sendmail(self, from_addr, to_addr, message, mail_options=None, rcpt_options=None): | def _mock_smtp_sendmail(self, from_addr, to_addr, message, mail_options=None, rcpt_options=None): | ||||
self.smtplog.append((from_addr, to_addr, message)) | self.smtplog.append((from_addr, to_addr, message)) | ||||
return [] | return [] | ||||
def _mock_imap_append(self, folder, msg): | |||||
self.imap_append_log.append((folder, msg)) | |||||
return True | |||||
def _get_ics_part(self, message): | def _get_ics_part(self, message): | ||||
ics_part = None | ics_part = None | ||||
for part in message.walk(): | for part in message.walk(): | ||||
if part.get_content_type() == 'text/calendar': | if part.get_content_type() == 'text/calendar': | ||||
ics_part = part | ics_part = part | ||||
return ics_part | return ics_part | ||||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | def test_006_send_response_delegate(self): | ||||
self.assertEqual(ical1['attendee'][1].__str__(), "MAILTO:resource-car-audi-a4@example.org") | self.assertEqual(ical1['attendee'][1].__str__(), "MAILTO:resource-car-audi-a4@example.org") | ||||
# resource collection responds DELEGATED | # resource collection responds DELEGATED | ||||
response2 = message_from_string(self.smtplog[1][2]) | response2 = message_from_string(self.smtplog[1][2]) | ||||
ical2 = self._get_ical(self._get_ics_part(response2).get_payload(decode=True)) | ical2 = self._get_ical(self._get_ics_part(response2).get_payload(decode=True)) | ||||
self.assertIn("ACCEPTED".lower(), response2['subject'].lower(), "Delegation message subject: %r" % (response2['subject'])) | self.assertIn("ACCEPTED".lower(), response2['subject'].lower(), "Delegation message subject: %r" % (response2['subject'])) | ||||
self.assertEqual(ical2['attendee'].__str__(), "MAILTO:resource-car-audi-a4@example.org") | self.assertEqual(ical2['attendee'].__str__(), "MAILTO:resource-car-audi-a4@example.org") | ||||
self.assertEqual(ical2['attendee'].params['PARTSTAT'], u"ACCEPTED") | self.assertEqual(ical2['attendee'].params['PARTSTAT'], u"ACCEPTED") | ||||
def test_007_accept_reservation_request_store_and_notify(self): | |||||
itip_event = itip.events_from_message(message_from_string(itip_multipart))[0] | |||||
resource = { | |||||
'mail': 'resource-collection-car@example.org', | |||||
'kolabtargetfolder': 'shared/Resources/Test@example.org', | |||||
'dn': 'cn=cars,ou=Resources,cd=example,dc=org', | |||||
'cn': 'Cars', | |||||
'owner': 'uid=foo,ou=People,cd=example,dc=org', | |||||
'kolabinvitationpolicy': [module_resources.ACT_STORE_AND_NOTIFY] | |||||
} | |||||
conf.command_set('wallace', 'webmail_url', 'https://%(domain)s/roundcube') | |||||
module_resources.imap = IMAP() | |||||
module_resources.accept_reservation_request(itip_event, resource) | |||||
# Assert no reply message sent to the organizer | |||||
self.assertEqual(len(self.smtplog), 1) | |||||
self.assertEqual(len(self.imap_append_log), 1) | |||||
# Assert the notification sent to the resource owner | |||||
mail = message_from_string(self.smtplog[0][2]) | |||||
self.assertEqual("resource-collection-car@example.org", self.smtplog[0][0]) | |||||
self.assertEqual("resource-collection-car@example.org", mail['from']) | |||||
self.assertEqual("foo@example.org", self.smtplog[0][1]) | |||||
self.assertEqual("foo@example.org", mail['to']) | |||||
self.assertFalse(mail.is_multipart()) | |||||
self.assertIn("New booking request for Cars", mail['subject']) | |||||
body = mail.get_payload(decode=True) | |||||
self.assertIn("The resource booking request is for Cars by Doe, John <doe@example.org>", body) | |||||
self.assertIn("You can change the status via https://example.org/roundcube?_task=calendar", body) | |||||
# Assert the message appended to the resource folder | |||||
self.assertEqual(resource['kolabtargetfolder'], self.imap_append_log[0][0]) | |||||
self.assertIn("<text>NEEDS-ACTION</text>", self.imap_append_log[0][1]) |