def _simpleAccount(self, userNumber, eventText): client = StubClient(userNumber, self.mktemp()) vevent = Component.fromString(eventText) calendar = Calendar( caldavxml.calendar, set(('VEVENT',)), u'calendar', u'/cal/', None) event = Event(client.serializeLocation(), calendar.url + u'1234.ics', None, vevent) calendar.events = {u'1234.ics': event} client._events.update({event.url: event}) client._calendars.update({calendar.url: calendar}) return vevent, event, calendar, client
def _simpleAccount(self, userNumber, eventText): client = StubClient(userNumber, self.mktemp()) vevent = Component.fromString(eventText) calendar = Calendar(caldavxml.calendar, set(('VEVENT', )), u'calendar', u'/cal/', None) event = Event(client.serializeLocation(), calendar.url + u'1234.ics', None, vevent) calendar.events = {u'1234.ics': event} client._events.update({event.url: event}) client._calendars.update({calendar.url: calendar}) return vevent, event, calendar, client
def test_acceptInvitation(self): """ If the client is an attendee on an event and the PARTSTAT is NEEDS-ACTION, a response is generated which accepts the invitation and the corresponding event in the I{schedule-inbox} is deleted. """ clock = Clock() randomDelay = 7 vevent = Component.fromString(INVITED_EVENT) attendees = tuple(vevent.mainComponent().properties('ATTENDEE')) userNumber = int(attendees[1].parameterValue('CN').split(None, 1)[1]) client = StubClient(userNumber, self.mktemp()) calendarURL = '/some/calendar/' calendar = Calendar(caldavxml.calendar, set(('VEVENT', )), u'calendar', calendarURL, None) client._calendars[calendarURL] = calendar inboxURL = '/some/inbox/' inbox = Calendar(caldavxml.schedule_inbox, set(), u'the inbox', inboxURL, None) client._calendars[inboxURL] = inbox event = Event(client.serializeLocation(), calendarURL + u'1234.ics', None, vevent) client._setEvent(event.url, event) inboxEvent = Event(client.serializeLocation(), inboxURL + u'4321.ics', None, vevent) client._setEvent(inboxEvent.url, inboxEvent) accepter = Accepter(clock, self.sim, client, userNumber) accepter.setParameters( acceptDelayDistribution=Deterministic(randomDelay)) accepter.eventChanged(event.url) clock.advance(randomDelay) vevent = client._events[event.url].component attendees = tuple(vevent.mainComponent().properties('ATTENDEE')) self.assertEquals(len(attendees), 2) self.assertEquals(attendees[1].parameterValue('CN'), 'User %02d' % (userNumber, )) self.assertEquals(attendees[1].parameterValue('PARTSTAT'), 'ACCEPTED') self.assertFalse(attendees[1].hasParameter('RSVP')) self.assertNotIn(inboxEvent.url, client._events) self.assertNotIn('4321.ics', inbox.events)
def test_inboxReplyFailedDelete(self): """ When an inbox item that contains a reply is seen by the client, it deletes it immediately. If the delete fails, the appropriate response code is returned. """ userNumber = 1 clock = Clock() inboxURL = '/some/inbox/' vevent = Component.fromString(INBOX_REPLY) inbox = Calendar(caldavxml.schedule_inbox, set(), u'the inbox', inboxURL, None) client = StubClient(userNumber, self.mktemp()) client._calendars[inboxURL] = inbox inboxEvent = Event(client.serializeLocation(), inboxURL + u'4321.ics', None, vevent) client._setEvent(inboxEvent.url, inboxEvent) client._failDeleteWithObject( inboxEvent.url, IncorrectResponseCode( NO_CONTENT, Response(('HTTP', 1, 1), PRECONDITION_FAILED, 'Precondition Failed', None, None))) accepter = Accepter(clock, self.sim, client, userNumber) accepter.eventChanged(inboxEvent.url) clock.advance(3) self.assertNotIn(inboxEvent.url, client._events) self.assertNotIn('4321.ics', inbox.events)
def test_ignoreAlreadyAccepting(self): """ If the client sees an event change a second time before responding to an invitation found on it during the first change notification, the second change notification does not generate another accept attempt. """ clock = Clock() randomDelay = 7 vevent = Component.fromString(INVITED_EVENT) attendees = tuple(vevent.mainComponent().properties('ATTENDEE')) userNumber = int(attendees[1].parameterValue('CN').split(None, 1)[1]) calendarURL = '/some/calendar/' calendar = Calendar(caldavxml.calendar, set(('VEVENT', )), u'calendar', calendarURL, None) client = StubClient(userNumber, self.mktemp()) client._calendars[calendarURL] = calendar event = Event(client.serializeLocation(), calendarURL + u'1234.ics', None, vevent) client._events[event.url] = event accepter = Accepter(clock, self.sim, client, userNumber) accepter.random = Deterministic() accepter.random.gauss = lambda mu, sigma: randomDelay accepter.eventChanged(event.url) accepter.eventChanged(event.url) clock.advance(randomDelay)
def test_doNotAddExistingToEvent(self): """ If the inviter randomly selects a user which is already an invitee on the event, a different user is added instead. """ calendar = Calendar(caldavxml.calendar, set(('VEVENT', )), u'personal stuff', u'/cals/personal', None) selfNumber = 1 client = StubClient(selfNumber, self.mktemp()) client._calendars.update({calendar.url: calendar}) inviteeNumber = 20 anotherNumber = inviteeNumber + 5 values = [ inviteeNumber - selfNumber, inviteeNumber - selfNumber, anotherNumber - selfNumber ] inviter = RealisticInviter(Clock(), self.sim, client, selfNumber) inviter.setParameters( inviteeDistribution=SequentialDistribution(values), inviteeCountDistribution=Deterministic(2)) inviter._invite() self.assertEquals(len(client._events), 1) attendees = tuple(client._events.values() [0].component.mainComponent().properties('ATTENDEE')) expected = set(( "mailto:user%[email protected]" % (selfNumber, ), "mailto:user%[email protected]" % (inviteeNumber, ), "mailto:user%[email protected]" % (anotherNumber, ), )) for attendee in attendees: expected.remove(attendee.value()) self.assertEqual(len(expected), 0)
def test_addInvite(self): """ When there is a normal calendar, inviter adds an invite to it. """ calendar = Calendar(caldavxml.calendar, set(('VEVENT', )), u'personal stuff', u'/cals/personal', None) userNumber = 16 serializePath = self.mktemp() os.mkdir(serializePath) client = StubClient(userNumber, self.mktemp()) client._calendars.update({calendar.url: calendar}) inviter = RealisticInviter(Clock(), self.sim, client, userNumber) inviter.setParameters(inviteeDistribution=Deterministic(1), inviteeCountDistribution=Deterministic(1)) inviter._invite() self.assertEquals(len(client._events), 1) attendees = tuple(client._events.values() [0].component.mainComponent().properties('ATTENDEE')) expected = set(( "mailto:user%[email protected]" % (userNumber, ), "mailto:user%[email protected]" % (userNumber + 1, ), )) for attendee in attendees: expected.remove(attendee.value()) self.assertEqual(len(expected), 0)
def test_changeEventAttendeePreconditionFailed(self): """ If the attempt to accept an invitation fails because of an unmet precondition (412), the event is re-retrieved and the PUT is re-issued with the new data. """ clock = Clock() userNumber = 2 client = StubClient(userNumber, self.mktemp()) randomDelay = 3 calendarURL = '/some/calendar/' calendar = Calendar(caldavxml.calendar, set(('VEVENT', )), u'calendar', calendarURL, None) client._calendars[calendarURL] = calendar vevent = Component.fromString(INVITED_EVENT) event = Event(client.serializeLocation(), calendarURL + u'1234.ics', None, vevent) client._setEvent(event.url, event) accepter = Accepter(clock, self.sim, client, userNumber) accepter.setParameters( acceptDelayDistribution=Deterministic(randomDelay)) client.rescheduled.add(event.url) accepter.eventChanged(event.url) clock.advance(randomDelay)
def test_ignoreNonCalendar(self): """ If an event is on a calendar which is not of type {CALDAV:}calendar, it is ignored. """ userNumber = 14 calendarURL = '/some/calendar/' calendar = Calendar(csxml.dropbox_home, set(), u'notification', calendarURL, None) client = StubClient(userNumber, self.mktemp()) client._calendars[calendarURL] = calendar accepter = Accepter(None, self.sim, client, userNumber) accepter.eventChanged(calendarURL + '1234.ics')
def test_doNotAddEventOnInbox(self): """ When the only calendar is a schedule inbox, no attempt is made to add events on it. """ calendar = Calendar(caldavxml.schedule_inbox, set(), u'inbox', u'/sched/inbox', None) client = StubClient(21, self.mktemp()) client._calendars.update({calendar.url: calendar}) eventer = Eventer(None, self.sim, client, None) eventer._addEvent() self.assertEquals(client._events, {})
def test_addEvent(self): """ When there is a normal calendar to add events to, L{Eventer._addEvent} adds an event to it. """ calendar = Calendar(caldavxml.calendar, set(('VEVENT', )), u'personal stuff', u'/cals/personal', None) client = StubClient(31, self.mktemp()) client._calendars.update({calendar.url: calendar}) eventer = Eventer(Clock(), self.sim, client, None) eventer._addEvent() self.assertEquals(len(client._events), 1)
def test_everybodyInvitedAlready(self): """ If the first so-many randomly selected users we come across are already attendees on the event, the invitation attempt is abandoned. """ calendar = Calendar(caldavxml.calendar, set(('VEVENT', )), u'personal stuff', u'/cals/personal', None) userNumber = 1 client = StubClient(userNumber, self.mktemp()) client._calendars.update({calendar.url: calendar}) inviter = RealisticInviter(Clock(), self.sim, client, userNumber) inviter.setParameters(inviteeDistribution=Deterministic(1), inviteeCountDistribution=Deterministic(2)) inviter._invite() self.assertEquals(len(client._events), 0)
def test_doNotAddInviteToInbox(self): """ When the only calendar with any events is a schedule inbox, no attempt is made to add attendees to that calendar. """ calendar = Calendar(caldavxml.schedule_inbox, set(), u'inbox', u'/sched/inbox', None) userNumber = 13 client = StubClient(userNumber, self.mktemp()) client._calendars.update({calendar.url: calendar}) inviter = RealisticInviter(None, self.sim, client, userNumber, **{"enabled": False}) inviter._invite() self.assertEquals(client._events, {})
def test_ignoreAccepted(self): """ If the client is an attendee on an event but the PARTSTAT is not NEEDS-ACTION, the event is ignored. """ vevent = Component.fromString(ACCEPTED_EVENT) attendees = tuple(vevent.mainComponent().properties('ATTENDEE')) userNumber = int(attendees[1].parameterValue('CN').split(None, 1)[1]) calendarURL = '/some/calendar/' calendar = Calendar(caldavxml.calendar, set(('VEVENT', )), u'calendar', calendarURL, None) client = StubClient(userNumber, self.mktemp()) client._calendars[calendarURL] = calendar event = Event(client.serializeLocation(), calendarURL + u'1234.ics', None, vevent) client._events[event.url] = event accepter = Accepter(None, self.sim, client, userNumber) accepter.eventChanged(event.url)
def shareCalendar(self): # pick a calendar calendar = self._getRandomCalendarOfType('VEVENT', justOwned=True) if not calendar: returnValue(None) # pick a random sharee shareeRecord = self._sim.getRandomUserRecord(besides=self._number) if shareeRecord is None: returnValue(None) # POST the sharing invite mailto = "mailto:{}".format(shareeRecord.email) body = Calendar.addInviteeXML(mailto, calendar.name, readwrite=True) yield self._client.postXML(calendar.url, body, label="POST{share-calendar}")
def test_reacceptInvitation(self): """ If a client accepts an invitation on an event and then is later re-invited to the same event, the invitation is again accepted. """ clock = Clock() randomDelay = 7 vevent = Component.fromString(INVITED_EVENT) attendees = tuple(vevent.mainComponent().properties('ATTENDEE')) userNumber = int(attendees[1].parameterValue('CN').split(None, 1)[1]) calendarURL = '/some/calendar/' calendar = Calendar(caldavxml.calendar, set(('VEVENT', )), u'calendar', calendarURL, None) client = StubClient(userNumber, self.mktemp()) client._calendars[calendarURL] = calendar event = Event(client.serializeLocation(), calendarURL + u'1234.ics', None, vevent) client._events[event.url] = event accepter = Accepter(clock, self.sim, client, userNumber) accepter.setParameters( acceptDelayDistribution=Deterministic(randomDelay)) accepter.eventChanged(event.url) clock.advance(randomDelay) # Now re-set the event so it has to be accepted again event.component = Component.fromString(INVITED_EVENT) # And now re-deliver it accepter.eventChanged(event.url) clock.advance(randomDelay) # And ensure that it was accepted again vevent = client._events[event.url].component attendees = tuple(vevent.mainComponent().properties('ATTENDEE')) self.assertEquals(len(attendees), 2) self.assertEquals(attendees[1].parameterValue('CN'), 'User %02d' % (userNumber, )) self.assertEquals(attendees[1].parameterValue('PARTSTAT'), 'ACCEPTED') self.assertFalse(attendees[1].hasParameter('RSVP'))
def test_inboxReply(self): """ When an inbox item that contains a reply is seen by the client, it deletes it immediately. """ userNumber = 1 clock = Clock() inboxURL = '/some/inbox/' vevent = Component.fromString(INBOX_REPLY) inbox = Calendar(caldavxml.schedule_inbox, set(), u'the inbox', inboxURL, None) client = StubClient(userNumber, self.mktemp()) client._calendars[inboxURL] = inbox inboxEvent = Event(client.serializeLocation(), inboxURL + u'4321.ics', None, vevent) client._setEvent(inboxEvent.url, inboxEvent) accepter = Accepter(clock, self.sim, client, userNumber) accepter.eventChanged(inboxEvent.url) clock.advance(3) self.assertNotIn(inboxEvent.url, client._events) self.assertNotIn('4321.ics', inbox.events)