Пример #1
0
 def assertEqualCalendarData(self, cal1, cal2):
     if isinstance(cal1, str):
         cal1 = Component.fromString(cal1)
     if isinstance(cal2, str):
         cal2 = Component.fromString(cal2)
     ncal1 = normalize_iCalStr(cal1)
     ncal2 = normalize_iCalStr(cal2)
     self.assertEqual(ncal1, ncal2, msg=diff_iCalStrs(ncal1, ncal2))
Пример #2
0
 def assertEqualCalendarData(self, cal1, cal2):
     if isinstance(cal1, str):
         cal1 = Component.fromString(cal1)
     if isinstance(cal2, str):
         cal2 = Component.fromString(cal2)
     ncal1 = normalize_iCalStr(cal1)
     ncal2 = normalize_iCalStr(cal2)
     self.assertEqual(ncal1, ncal2, msg=diff_iCalStrs(ncal1, ncal2))
    def _testOneResource(self, home, calendar_name, data):
        """
        Get the one resources expected in a collection
        """
        inbox = yield self.calendarUnderTest(home=home, name=calendar_name)
        objs = yield inbox.objectResources()
        self.assertEqual(len(objs), 1)

        caldata = yield objs[0].componentForUser()
        self.assertEqual(normalize_iCalStr(caldata), normalize_iCalStr(componentUpdate(data)))
Пример #4
0
    def _testOneResource(self, home, calendar_name, data):
        """
        Get the one resources expected in a collection
        """
        inbox = yield self.calendarUnderTest(home=home, name=calendar_name)
        objs = yield inbox.objectResources()
        self.assertEqual(len(objs), 1)

        caldata = yield objs[0].componentForUser()
        self.assertEqual(normalize_iCalStr(caldata), normalize_iCalStr(componentUpdate(data)))
Пример #5
0
    def test_objectresource_setcomponent(self):
        """
        Test that a remote object resource L{setComponent} works.
        """

        home01 = yield self.homeUnderTest(txn=self.theTransactionUnderTest(0),
                                          name="user01",
                                          create=True)
        self.assertTrue(home01 is not None)
        calendar01 = yield home01.childWithName("calendar")
        yield calendar01.createCalendarObjectWithName(
            "1.ics", Component.fromString(self.caldata1))
        yield self.commitTransaction(0)

        home = yield self._remoteHome(self.theTransactionUnderTest(1),
                                      "user01")
        self.assertTrue(home is not None)
        calendar = yield home.childWithName("calendar")
        resource = yield calendar.objectResourceWithName("1.ics")
        changed = yield resource.setComponent(
            Component.fromString(self.caldata1_changed))
        self.assertFalse(changed)
        caldata = yield resource.component()
        self.assertEqual(normalize_iCalStr(str(caldata)),
                         normalize_iCalStr(self.caldata1_changed))
        yield self.commitTransaction(1)

        home01 = yield self.homeUnderTest(txn=self.theTransactionUnderTest(0),
                                          name="user01",
                                          create=True)
        self.assertTrue(home01 is not None)
        calendar01 = yield home01.childWithName("calendar")
        resource01 = yield calendar01.objectResourceWithName("1.ics")
        caldata = yield resource01.component()
        self.assertEqual(normalize_iCalStr(str(caldata)),
                         normalize_iCalStr(self.caldata1_changed))
        yield self.commitTransaction(0)

        # Fail to set with different UID
        home = yield self._remoteHome(self.theTransactionUnderTest(1),
                                      "user01")
        self.assertTrue(home is not None)
        calendar = yield home.childWithName("calendar")
        resource = yield calendar.objectResourceWithName("1.ics")
        self.assertFailure(
            resource.setComponent(Component.fromString(self.caldata1_failed)),
            InvalidUIDError,
        )
        yield self.commitTransaction(1)
Пример #6
0
    def test_component(self):
        """
        Test that action=component works.
        """

        yield self.createShare("user01", "puser01")

        calendar1 = yield self.calendarUnderTest(txn=self.theTransactionUnderTest(0), home="user01", name="calendar")
        yield calendar1.createCalendarObjectWithName("1.ics", Component.fromString(self.caldata1))
        yield self.commitTransaction(0)

        shared_object = yield self.calendarObjectUnderTest(txn=self.theTransactionUnderTest(1), home="puser01", calendar_name="shared-calendar", name="1.ics")
        ical = yield shared_object.component()
        self.assertTrue(isinstance(ical, Component))
        self.assertEqual(normalize_iCalStr(str(ical)), normalize_iCalStr(self.caldata1))
        yield self.commitTransaction(1)
Пример #7
0
    def test_component(self):
        """
        Test that action=component works.
        """

        yield self.createShare("user01", "puser01")

        calendar1 = yield self.calendarUnderTest(txn=self.theTransactionUnderTest(0), home="user01", name="calendar")
        yield calendar1.createCalendarObjectWithName("1.ics", Component.fromString(self.caldata1))
        yield self.commitTransaction(0)

        shared_object = yield self.calendarObjectUnderTest(txn=self.theTransactionUnderTest(1), home="puser01", calendar_name="shared-calendar", name="1.ics")
        ical = yield shared_object.component()
        self.assertTrue(isinstance(ical, Component))
        self.assertEqual(normalize_iCalStr(str(ical)), normalize_iCalStr(self.caldata1))
        yield self.commitTransaction(1)
Пример #8
0
    def test_setcomponent(self):
        """
        Test that action=setcomponent works.
        """

        yield self.createShare("user01", "puser01")

        calendar1 = yield self.calendarUnderTest(home="user01", name="calendar")
        yield  calendar1.createCalendarObjectWithName("1.ics", Component.fromString(self.caldata1))
        yield self.commit()

        shared_object = yield self.calendarObjectUnderTest(txn=self.newOtherTransaction(), home="puser01", calendar_name="shared-calendar", name="1.ics")
        ical = yield shared_object.component()
        self.assertTrue(isinstance(ical, Component))
        self.assertEqual(normalize_iCalStr(str(ical)), normalize_iCalStr(self.caldata1))
        yield self.otherCommit()

        shared_object = yield self.calendarObjectUnderTest(txn=self.newOtherTransaction(), home="puser01", calendar_name="shared-calendar", name="1.ics")
        changed = yield shared_object.setComponent(Component.fromString(self.caldata1_changed))
        self.assertFalse(changed)
        ical = yield shared_object.component()
        self.assertTrue(isinstance(ical, Component))
        self.assertEqual(normalize_iCalStr(str(ical)), normalize_iCalStr(self.caldata1_changed))
        yield self.otherCommit()

        object1 = yield self.calendarObjectUnderTest(home="user01", calendar_name="calendar", name="1.ics")
        ical = yield object1.component()
        self.assertTrue(isinstance(ical, Component))
        self.assertEqual(normalize_iCalStr(str(ical)), normalize_iCalStr(self.caldata1_changed))
        yield self.commit()
Пример #9
0
    def test_objectresource_setcomponent(self):
        """
        Test that a remote object resource L{setComponent} works.
        """

        home01 = yield self.homeUnderTest(txn=self.theTransactionUnderTest(0), name="user01", create=True)
        self.assertTrue(home01 is not None)
        calendar01 = yield home01.childWithName("calendar")
        yield calendar01.createCalendarObjectWithName("1.ics", Component.fromString(self.caldata1))
        yield self.commitTransaction(0)

        home = yield self._remoteHome(self.theTransactionUnderTest(1), "user01")
        self.assertTrue(home is not None)
        calendar = yield home.childWithName("calendar")
        resource = yield calendar.objectResourceWithName("1.ics")
        changed = yield resource.setComponent(Component.fromString(self.caldata1_changed))
        self.assertFalse(changed)
        caldata = yield resource.component()
        self.assertEqual(normalize_iCalStr(str(caldata)), normalize_iCalStr(self.caldata1_changed))
        yield self.commitTransaction(1)

        home01 = yield self.homeUnderTest(txn=self.theTransactionUnderTest(0), name="user01", create=True)
        self.assertTrue(home01 is not None)
        calendar01 = yield home01.childWithName("calendar")
        resource01 = yield calendar01.objectResourceWithName("1.ics")
        caldata = yield resource01.component()
        self.assertEqual(normalize_iCalStr(str(caldata)), normalize_iCalStr(self.caldata1_changed))
        yield self.commitTransaction(0)

        # Fail to set with different UID
        home = yield self._remoteHome(self.theTransactionUnderTest(1), "user01")
        self.assertTrue(home is not None)
        calendar = yield home.childWithName("calendar")
        resource = yield calendar.objectResourceWithName("1.ics")
        self.assertFailure(
            resource.setComponent(Component.fromString(self.caldata1_failed)),
            InvalidUIDError,
        )
        yield self.commitTransaction(1)
Пример #10
0
    def test_validation_deleteWithDuplicatePrivateComments(self):
        """
        Test that attendee private comments are no longer restored.
        """

        data1 = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890-attendee-reply
DTSTAMP:20080601T120000Z
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
ORGANIZER;CN="User 01":mailto:[email protected]
ATTENDEE:mailto:[email protected]
ATTENDEE:mailto:[email protected]
END:VEVENT
END:VCALENDAR
"""

        data2 = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890-attendee-reply
DTSTAMP:20080601T120000Z
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
ORGANIZER;CN="User 01":mailto:[email protected]
ATTENDEE:mailto:[email protected]
ATTENDEE:mailto:[email protected]
X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:
 user02";X-CALENDARSERVER-DTSTAMP=20140224T181133Z:Comment
X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:
 user02";X-CALENDARSERVER-DTSTAMP=20140224T181133Z:Comment
END:VEVENT
END:VCALENDAR
"""

        data3 = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890-attendee-reply
DTSTAMP:20080601T120000Z
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
ORGANIZER;CN="User 01":mailto:[email protected]
ATTENDEE:mailto:[email protected]
ATTENDEE;PARTSTAT=ACCEPTED:mailto:[email protected]
END:VEVENT
END:VCALENDAR
"""

        calendar_collection = (yield self.calendarUnderTest(home="user01"))
        calendar = Component.fromString(data1)
        yield calendar_collection.createCalendarObjectWithName(
            "test.ics", calendar)
        yield self.commit()

        calendar_resource = (yield self.calendarObjectUnderTest(
            name="test.ics",
            home="user01",
        ))
        calendar = Component.fromString(data2)
        yield calendar_resource._setComponentInternal(
            calendar, internal_state=ComponentUpdateState.RAW)
        yield self.commit()

        def raiseHere(otherself, component, inserting, internal_state):
            if component.hasDuplicatePrivateComments(doFix=False):
                raise ValueError

        self.patch(CalendarObject, "preservePrivateComments", raiseHere)

        calendar2 = (yield self.calendarUnderTest(name="calendar_1",
                                                  home="user02"))
        cobjs = (yield calendar2.calendarObjects())
        self.assertTrue(len(cobjs) == 1)
        yield cobjs[0].setComponent(Component.fromString(data3))
        yield self.commit()

        calendar2 = (yield self.calendarUnderTest(name="calendar_1",
                                                  home="user02"))
        cobjs = (yield calendar2.calendarObjects())
        calendar = yield cobjs[0].component()
        self.assertTrue('SCHEDULE-STATUS=5.0' in normalize_iCalStr(calendar))
        yield self.commit()

        calendar2 = (yield self.calendarUnderTest(name="calendar_1",
                                                  home="user02"))
        cobjs = (yield calendar2.calendarObjects())
        self.assertTrue(len(cobjs) == 1)
        yield cobjs[0].remove()
        yield self.commit()

        calendar2 = (yield self.calendarUnderTest(name="calendar_1",
                                                  home="user02"))
        cobjs = (yield calendar2.calendarObjects())
        self.assertTrue(len(cobjs) == 0)
        yield self.commit()

        self.flushLoggedErrors(ValueError)
Пример #11
0
    def test_needsActionOrganizerChange(self):
        """
        Test that if the organizer makes an inconsequential change and also changes the
        attendee partstat, then the new partstat is sent to the attendee.
        """

        organizer1 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION:urn:x-uid:user02
END:VEVENT
END:VCALENDAR
""")

        organizer2 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=ACCEPTED;SCHEDULE-STATUS=2.0:urn:x-uid:user02
END:VEVENT
END:VCALENDAR
""")

        organizer3 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION:urn:x-uid:user02
SUMMARY:Test
END:VEVENT
END:VCALENDAR
""")

        attendee1 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION;RSVP=TRUE:urn:x-uid:user02
TRANSP:TRANSPARENT
END:VEVENT
END:VCALENDAR
""")

        attendee2 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user02
END:VEVENT
END:VCALENDAR
""")

        attendee3 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected];SCHEDULE-STATUS=1.2:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION;RSVP=TRUE:urn:x-uid:user02
SEQUENCE:1
SUMMARY:Test
TRANSP:TRANSPARENT
END:VEVENT
END:VCALENDAR
""")


        yield self.createOrganizerEvent("user01", organizer1)
        attendee = yield self.getAttendeeEvent("user02")
        self.assertEqual(attendee, attendee1, msg=diff_iCalStrs(attendee, attendee1))
        yield self.setAttendeeEvent("user02", attendee2)
        organizer = yield self.getOrganizerEvent("user01")
        self.assertEqual(normalize_iCalStr(organizer), normalize_iCalStr(organizer2), msg=diff_iCalStrs(organizer2, organizer))

        yield self.setOrganizerEvent("user01", organizer3)
        attendee = yield self.getAttendeeEvent("user02")
        self.assertEqual(normalize_iCalStr(attendee), normalize_iCalStr(attendee3), msg=diff_iCalStrs(attendee3, attendee))
Пример #12
0
    def test_CalendarDataTextAndJSON(self):
        """
        Text that we can both parse and generate CalendarData elements with both text and json formats.
        """
        dataText = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
ATTENDEE:mailto:[email protected]
ATTENDEE:mailto:[email protected]
DTSTAMP:20080601T120000Z
EXDATE:20080602T120000Z
EXDATE:20080603T120000Z
ORGANIZER;CN=User 01:mailto:[email protected]
RRULE:FREQ=DAILY;COUNT=400
SUMMARY:Test
END:VEVENT
END:VCALENDAR
""".replace("\n", "\r\n")

        dataXML = """<?xml version='1.0' encoding='UTF-8'?>
<calendar-data xmlns='urn:ietf:params:xml:ns:caldav'><![CDATA[%s]]></calendar-data>""" % (
            dataText, )

        jsonText = """[
  "vcalendar",
  [
    ["version", {}, "text", "2.0"],
    ["prodid", {}, "text", "-//CALENDARSERVER.ORG//NONSGML Version 1//EN"]
  ],
  [
    ["vevent",
      [
        ["uid", {}, "text", "12345-67890"],
        ["dtstart", {}, "date-time", "2008-06-01T12:00:00Z"],
        ["dtend", {}, "date-time", "2008-06-01T13:00:00Z"],
        ["attendee", {}, "cal-address", "mailto:[email protected]"],
        ["attendee", {}, "cal-address", "mailto:[email protected]"],
        ["dtstamp", {}, "date-time", "2008-06-01T12:00:00Z"],
        ["exdate", {}, "date-time", "2008-06-02T12:00:00Z"],
        ["exdate", {}, "date-time", "2008-06-03T12:00:00Z"],
        ["organizer", {"cn": "User 01"}, "cal-address", "mailto:[email protected]"],
        ["rrule", {}, "recur", {"count": 400, "freq": "DAILY"}],
        ["summary", {}, "text", "Test"]
      ],
      [
      ]
    ]
  ]
]
"""

        jsonXML = """<?xml version='1.0' encoding='UTF-8'?>
<calendar-data content-type='application/calendar+json' xmlns='urn:ietf:params:xml:ns:caldav'><![CDATA[%s]]></calendar-data>""" % (
            jsonText, )

        cd = CalendarData.fromTextData(dataText)
        self.assertEqual(
            normalize_iCalStr(cd.calendar().getTextWithTimezones(
                True, format="text/calendar")), normalize_iCalStr(dataText))
        self.assertEqual(
            normalizeJSON(cd.calendar().getTextWithTimezones(
                True, format="application/calendar+json")),
            normalizeJSON(jsonText))
        self.assertEqual(cd.content_type, "text/calendar")
        self.assertEqual(cd.toxml(), dataXML)

        comp = Component.fromString(dataText)
        cd = CalendarData.fromCalendar(comp)
        self.assertEqual(
            normalize_iCalStr(cd.calendar().getTextWithTimezones(
                True, format="text/calendar")), normalize_iCalStr(dataText))
        self.assertEqual(
            normalizeJSON(cd.calendar().getTextWithTimezones(
                True, format="application/calendar+json")),
            normalizeJSON(jsonText))
        self.assertEqual(cd.content_type, "text/calendar")
        self.assertEqual(cd.toxml(), dataXML)

        cd = CalendarData.fromCalendar(comp,
                                       format="application/calendar+json")
        self.assertEqual(
            normalize_iCalStr(cd.calendar().getTextWithTimezones(
                True, format="text/calendar")), normalize_iCalStr(dataText))
        self.assertEqual(
            normalizeJSON(cd.calendar().getTextWithTimezones(
                True, format="application/calendar+json")),
            normalizeJSON(jsonText))
        self.assertEqual(cd.content_type, "application/calendar+json")
        self.assertEqual(normalizeJSON(cd.toxml()), normalizeJSON(jsonXML))

        cd = CalendarData.fromTextData(jsonText,
                                       format="application/calendar+json")
        self.assertEqual(
            normalize_iCalStr(cd.calendar().getTextWithTimezones(
                True, format="text/calendar")), normalize_iCalStr(dataText))
        self.assertEqual(
            normalizeJSON(cd.calendar().getTextWithTimezones(
                True, format="application/calendar+json")),
            normalizeJSON(jsonText))
        self.assertEqual(cd.content_type, "application/calendar+json")
        self.assertEqual(cd.toxml(), jsonXML)

        comp = Component.fromString(jsonText,
                                    format="application/calendar+json")
        cd = CalendarData.fromCalendar(comp)
        self.assertEqual(
            normalize_iCalStr(cd.calendar().getTextWithTimezones(
                True, format="text/calendar")), normalize_iCalStr(dataText))
        self.assertEqual(
            normalizeJSON(cd.calendar().getTextWithTimezones(
                True, format="application/calendar+json")),
            normalizeJSON(jsonText))
        self.assertEqual(cd.content_type, "text/calendar")
        self.assertEqual(cd.toxml(), dataXML)

        cd = CalendarData.fromCalendar(comp,
                                       format="application/calendar+json")
        self.assertEqual(
            normalize_iCalStr(cd.calendar().getTextWithTimezones(
                True, format="text/calendar")), normalize_iCalStr(dataText))
        self.assertEqual(
            normalizeJSON(cd.calendar().getTextWithTimezones(
                True, format="application/calendar+json")),
            normalizeJSON(jsonText))
        self.assertEqual(cd.content_type, "application/calendar+json")
        self.assertEqual(normalizeJSON(cd.toxml()), normalizeJSON(jsonXML))
Пример #13
0
    def test_replyBeforeOrganizerConsequentialChange(self):
        """
        Test that the organizer and attendee see the attendee's partstat change when the organizer makes
        a consequential change whilst the attendee reply is in progress.
        """

        organizer1 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION:urn:x-uid:user02
END:VEVENT
END:VCALENDAR
""")

        organizer2 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080602T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION:urn:x-uid:user02
SUMMARY:Test
END:VEVENT
END:VCALENDAR
""")

        organizer3 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080602T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2;X-CALENDARSERVER-RESET-PARTSTAT=1:urn:x-uid:user02
SEQUENCE:1
SUMMARY:Test
END:VEVENT
END:VCALENDAR
""")

        attendee1 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION;RSVP=TRUE:urn:x-uid:user02
TRANSP:TRANSPARENT
END:VEVENT
END:VCALENDAR
""")

        attendee2 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user02
END:VEVENT
END:VCALENDAR
""")

        attendee3 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080602T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected];SCHEDULE-STATUS=1.2:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION;RSVP=TRUE:urn:x-uid:user02
SEQUENCE:1
SUMMARY:Test
TRANSP:TRANSPARENT
END:VEVENT
END:VCALENDAR
""")


        yield self.createOrganizerEvent("user01", organizer1)
        attendee = yield self.getAttendeeEvent("user02")
        self.assertEqual(attendee, attendee1, msg=diff_iCalStrs(attendee, attendee1))

        yield self.setOrganizerEvent("user01", organizer2, run_jobs=False)
        yield self._runOneJob()
        yield self.setAttendeeEvent("user02", attendee2, run_jobs=False)

        yield self._runAllJobs()

        jobs = yield JobItem.all(self.transactionUnderTest())
        self.assertEqual(len(jobs), 0)
        yield self.commit()

        organizer = yield self.getOrganizerEvent("user01")
        self.assertEqual(normalize_iCalStr(organizer), normalize_iCalStr(organizer3), msg=diff_iCalStrs(organizer3, organizer))
        attendee = yield self.getAttendeeEvent("user02")
        self.assertEqual(normalize_iCalStr(attendee), normalize_iCalStr(attendee3), msg=diff_iCalStrs(attendee3, attendee))
Пример #14
0
    def test_validation_deleteWithDuplicatePrivateComments(self):
        """
        Test that attendee private comments are no longer restored.
        """

        data1 = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890-attendee-reply
DTSTAMP:20080601T120000Z
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
ORGANIZER;CN="User 01":mailto:[email protected]
ATTENDEE:mailto:[email protected]
ATTENDEE:mailto:[email protected]
END:VEVENT
END:VCALENDAR
"""

        data2 = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890-attendee-reply
DTSTAMP:20080601T120000Z
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
ORGANIZER;CN="User 01":mailto:[email protected]
ATTENDEE:mailto:[email protected]
ATTENDEE:mailto:[email protected]
X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:
 user02";X-CALENDARSERVER-DTSTAMP=20140224T181133Z:Comment
X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:
 user02";X-CALENDARSERVER-DTSTAMP=20140224T181133Z:Comment
END:VEVENT
END:VCALENDAR
"""

        data3 = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890-attendee-reply
DTSTAMP:20080601T120000Z
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
ORGANIZER;CN="User 01":mailto:[email protected]
ATTENDEE:mailto:[email protected]
ATTENDEE;PARTSTAT=ACCEPTED:mailto:[email protected]
END:VEVENT
END:VCALENDAR
"""

        calendar_collection = (yield self.calendarUnderTest(home="user01"))
        calendar = Component.fromString(data1)
        yield calendar_collection.createCalendarObjectWithName("test.ics", calendar)
        yield self.commit()

        calendar_resource = (yield self.calendarObjectUnderTest(name="test.ics", home="user01",))
        calendar = Component.fromString(data2)
        yield calendar_resource._setComponentInternal(calendar, internal_state=ComponentUpdateState.RAW)
        yield self.commit()

        def raiseHere(otherself, component, inserting, internal_state):
            if component.hasDuplicatePrivateComments(doFix=False):
                raise ValueError

        self.patch(CalendarObject, "preservePrivateComments", raiseHere)

        calendar2 = (yield self.calendarUnderTest(name="calendar_1", home="user02"))
        cobjs = (yield calendar2.calendarObjects())
        self.assertTrue(len(cobjs) == 1)
        yield cobjs[0].setComponent(Component.fromString(data3))
        yield self.commit()

        calendar2 = (yield self.calendarUnderTest(name="calendar_1", home="user02"))
        cobjs = (yield calendar2.calendarObjects())
        calendar = yield cobjs[0].component()
        self.assertTrue('SCHEDULE-STATUS=5.0' in normalize_iCalStr(calendar))
        yield self.commit()

        calendar2 = (yield self.calendarUnderTest(name="calendar_1", home="user02"))
        cobjs = (yield calendar2.calendarObjects())
        self.assertTrue(len(cobjs) == 1)
        yield cobjs[0].remove()
        yield self.commit()

        calendar2 = (yield self.calendarUnderTest(name="calendar_1", home="user02"))
        cobjs = (yield calendar2.calendarObjects())
        self.assertTrue(len(cobjs) == 0)
        yield self.commit()
Пример #15
0
    def test_needsActionOrganizerChange(self):
        """
        Test that if the organizer makes an inconsequential change and also changes the
        attendee partstat, then the new partstat is sent to the attendee.
        """

        organizer1 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION:urn:x-uid:user02
END:VEVENT
END:VCALENDAR
""")

        organizer2 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=ACCEPTED;SCHEDULE-STATUS=2.0:urn:x-uid:user02
END:VEVENT
END:VCALENDAR
""")

        organizer3 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION:urn:x-uid:user02
SUMMARY:Test
END:VEVENT
END:VCALENDAR
""")

        attendee1 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION;RSVP=TRUE:urn:x-uid:user02
TRANSP:TRANSPARENT
END:VEVENT
END:VCALENDAR
""")

        attendee2 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user02
END:VEVENT
END:VCALENDAR
""")

        attendee3 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected];SCHEDULE-STATUS=1.2:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION;RSVP=TRUE:urn:x-uid:user02
SEQUENCE:1
SUMMARY:Test
TRANSP:TRANSPARENT
END:VEVENT
END:VCALENDAR
""")


        yield self.createOrganizerEvent("user01", organizer1)
        attendee = yield self.getAttendeeEvent("user02")
        self.assertEqual(attendee, attendee1, msg=diff_iCalStrs(attendee, attendee1))
        yield self.setAttendeeEvent("user02", attendee2)
        organizer = yield self.getOrganizerEvent("user01")
        self.assertEqual(normalize_iCalStr(organizer), normalize_iCalStr(organizer2), msg=diff_iCalStrs(organizer2, organizer))

        yield self.setOrganizerEvent("user01", organizer3)
        attendee = yield self.getAttendeeEvent("user02")
        self.assertEqual(normalize_iCalStr(attendee), normalize_iCalStr(attendee3), msg=diff_iCalStrs(attendee3, attendee))
Пример #16
0
    def test_replyBeforeOrganizerConsequentialChange(self):
        """
        Test that the organizer and attendee see the attendee's partstat change when the organizer makes
        a consequential change whilst the attendee reply is in progress.
        """

        organizer1 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION:urn:x-uid:user02
END:VEVENT
END:VCALENDAR
""")

        organizer2 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080602T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION:urn:x-uid:user02
SUMMARY:Test
END:VEVENT
END:VCALENDAR
""")

        organizer3 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080602T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2;X-CALENDARSERVER-RESET-PARTSTAT=1:urn:x-uid:user02
SEQUENCE:1
SUMMARY:Test
END:VEVENT
END:VCALENDAR
""")

        attendee1 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION;RSVP=TRUE:urn:x-uid:user02
TRANSP:TRANSPARENT
END:VEVENT
END:VCALENDAR
""")

        attendee2 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080601T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected]:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user02
END:VEVENT
END:VCALENDAR
""")

        attendee3 = Component.fromString("""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTAMP:20080601T130000Z
DTSTART:20080602T130000Z
DURATION:PT1H
ORGANIZER;CN=User 01;[email protected];SCHEDULE-STATUS=1.2:urn:x-uid:user01
ATTENDEE;CN=User 01;[email protected];PARTSTAT=ACCEPTED:urn:x-uid:user01
ATTENDEE;CN=User 02;[email protected];PARTSTAT=NEEDS-ACTION;RSVP=TRUE:urn:x-uid:user02
SEQUENCE:1
SUMMARY:Test
TRANSP:TRANSPARENT
END:VEVENT
END:VCALENDAR
""")


        yield self.createOrganizerEvent("user01", organizer1)
        attendee = yield self.getAttendeeEvent("user02")
        self.assertEqual(attendee, attendee1, msg=diff_iCalStrs(attendee, attendee1))

        yield self.setOrganizerEvent("user01", organizer2, run_jobs=False)
        yield self._runOneJob()
        yield self.setAttendeeEvent("user02", attendee2, run_jobs=False)

        yield self._runAllJobs()

        jobs = yield JobItem.all(self.transactionUnderTest())
        self.assertEqual(len(jobs), 0)
        yield self.commit()

        organizer = yield self.getOrganizerEvent("user01")
        self.assertEqual(normalize_iCalStr(organizer), normalize_iCalStr(organizer3), msg=diff_iCalStrs(organizer3, organizer))
        attendee = yield self.getAttendeeEvent("user02")
        self.assertEqual(normalize_iCalStr(attendee), normalize_iCalStr(attendee3), msg=diff_iCalStrs(attendee3, attendee))
Пример #17
0
    def test_CalendarDataTextAndJSON(self):
        """
        Text that we can both parse and generate CalendarData elements with both text and json formats.
        """
        dataText = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:12345-67890
DTSTART:20080601T120000Z
DTEND:20080601T130000Z
ATTENDEE:mailto:[email protected]
ATTENDEE:mailto:[email protected]
DTSTAMP:20080601T120000Z
EXDATE:20080602T120000Z
EXDATE:20080603T120000Z
ORGANIZER;CN=User 01:mailto:[email protected]
RRULE:FREQ=DAILY
SUMMARY:Test
END:VEVENT
END:VCALENDAR
""".replace("\n", "\r\n")

        dataXML = """<?xml version='1.0' encoding='UTF-8'?>
<calendar-data xmlns='urn:ietf:params:xml:ns:caldav'><![CDATA[%s]]></calendar-data>""" % (dataText,)

        jsonText = """[
  "vcalendar",
  [
    ["version", {}, "text", "2.0"],
    ["prodid", {}, "text", "-//CALENDARSERVER.ORG//NONSGML Version 1//EN"]
  ],
  [
    ["vevent",
      [
        ["uid", {}, "text", "12345-67890"],
        ["dtstart", {}, "date-time", "2008-06-01T12:00:00Z"],
        ["dtend", {}, "date-time", "2008-06-01T13:00:00Z"],
        ["attendee", {}, "cal-address", "mailto:[email protected]"],
        ["attendee", {}, "cal-address", "mailto:[email protected]"],
        ["dtstamp", {}, "date-time", "2008-06-01T12:00:00Z"],
        ["exdate", {}, "date-time", "2008-06-02T12:00:00Z"],
        ["exdate", {}, "date-time", "2008-06-03T12:00:00Z"],
        ["organizer", {"cn": "User 01"}, "cal-address", "mailto:[email protected]"],
        ["rrule", {}, "recur", {"freq": "DAILY"}],
        ["summary", {}, "text", "Test"]
      ],
      [
      ]
    ]
  ]
]
"""

        jsonXML = """<?xml version='1.0' encoding='UTF-8'?>
<calendar-data content-type='application/calendar+json' xmlns='urn:ietf:params:xml:ns:caldav'><![CDATA[%s]]></calendar-data>""" % (jsonText,)

        cd = CalendarData.fromTextData(dataText)
        self.assertEqual(normalize_iCalStr(cd.calendar().getTextWithTimezones(True, format="text/calendar")), normalize_iCalStr(dataText))
        self.assertEqual(normalizeJSON(cd.calendar().getTextWithTimezones(True, format="application/calendar+json")), normalizeJSON(jsonText))
        self.assertEqual(cd.content_type, "text/calendar")
        self.assertEqual(cd.toxml(), dataXML)

        comp = Component.fromString(dataText)
        cd = CalendarData.fromCalendar(comp)
        self.assertEqual(normalize_iCalStr(cd.calendar().getTextWithTimezones(True, format="text/calendar")), normalize_iCalStr(dataText))
        self.assertEqual(normalizeJSON(cd.calendar().getTextWithTimezones(True, format="application/calendar+json")), normalizeJSON(jsonText))
        self.assertEqual(cd.content_type, "text/calendar")
        self.assertEqual(cd.toxml(), dataXML)

        cd = CalendarData.fromCalendar(comp, format="application/calendar+json")
        self.assertEqual(normalize_iCalStr(cd.calendar().getTextWithTimezones(True, format="text/calendar")), normalize_iCalStr(dataText))
        self.assertEqual(normalizeJSON(cd.calendar().getTextWithTimezones(True, format="application/calendar+json")), normalizeJSON(jsonText))
        self.assertEqual(cd.content_type, "application/calendar+json")
        self.assertEqual(normalizeJSON(cd.toxml()), normalizeJSON(jsonXML))

        cd = CalendarData.fromTextData(jsonText, format="application/calendar+json")
        self.assertEqual(normalize_iCalStr(cd.calendar().getTextWithTimezones(True, format="text/calendar")), normalize_iCalStr(dataText))
        self.assertEqual(normalizeJSON(cd.calendar().getTextWithTimezones(True, format="application/calendar+json")), normalizeJSON(jsonText))
        self.assertEqual(cd.content_type, "application/calendar+json")
        self.assertEqual(cd.toxml(), jsonXML)

        comp = Component.fromString(jsonText, format="application/calendar+json")
        cd = CalendarData.fromCalendar(comp)
        self.assertEqual(normalize_iCalStr(cd.calendar().getTextWithTimezones(True, format="text/calendar")), normalize_iCalStr(dataText))
        self.assertEqual(normalizeJSON(cd.calendar().getTextWithTimezones(True, format="application/calendar+json")), normalizeJSON(jsonText))
        self.assertEqual(cd.content_type, "text/calendar")
        self.assertEqual(cd.toxml(), dataXML)

        cd = CalendarData.fromCalendar(comp, format="application/calendar+json")
        self.assertEqual(normalize_iCalStr(cd.calendar().getTextWithTimezones(True, format="text/calendar")), normalize_iCalStr(dataText))
        self.assertEqual(normalizeJSON(cd.calendar().getTextWithTimezones(True, format="application/calendar+json")), normalizeJSON(jsonText))
        self.assertEqual(cd.content_type, "application/calendar+json")
        self.assertEqual(normalizeJSON(cd.toxml()), normalizeJSON(jsonXML))