def random_val(self, field): if isinstance(field, ExtendedPropertyField): if field.value_cls.property_type == 'StringArray': return [get_random_string(255) for _ in range(random.randint(1, 4))] if field.value_cls.property_type == 'IntegerArray': return [get_random_int(0, 256) for _ in range(random.randint(1, 4))] if field.value_cls.property_type == 'BinaryArray': return [get_random_string(255).encode() for _ in range(random.randint(1, 4))] if field.value_cls.property_type == 'String': return get_random_string(255) if field.value_cls.property_type == 'Integer': return get_random_int(0, 256) if field.value_cls.property_type == 'Binary': # In the test_extended_distinguished_property test, EWS rull return 4 NULL bytes after char 16 if we # send a longer bytes sequence. return get_random_string(16).encode() raise ValueError('Unsupported field %s' % field) if isinstance(field, URIField): return get_random_url() if isinstance(field, EmailAddressField): return get_random_email() if isinstance(field, ChoiceField): return get_random_choice(field.supported_choices(version=self.account.version)) if isinstance(field, CultureField): return get_random_choice(['da-DK', 'de-DE', 'en-US', 'es-ES', 'fr-CA', 'nl-NL', 'ru-RU', 'sv-SE']) if isinstance(field, BodyField): return get_random_string(400) if isinstance(field, CharListField): return [get_random_string(16) for _ in range(random.randint(1, 4))] if isinstance(field, TextListField): return [get_random_string(400) for _ in range(random.randint(1, 4))] if isinstance(field, CharField): return get_random_string(field.max_length) if isinstance(field, TextField): return get_random_string(400) if isinstance(field, MimeContentField): return get_random_string(400).encode('utf-8') if isinstance(field, Base64Field): return get_random_bytes(400) if isinstance(field, BooleanField): return get_random_bool() if isinstance(field, DecimalField): return get_random_decimal(field.min or 1, field.max or 99) if isinstance(field, IntegerField): return get_random_int(field.min or 0, field.max or 256) if isinstance(field, DateField): return get_random_date() if isinstance(field, DateTimeBackedDateField): return get_random_date() if isinstance(field, DateTimeField): return get_random_datetime(tz=self.account.default_timezone) if isinstance(field, AttachmentField): return [FileAttachment(name='my_file.txt', content=get_random_string(400).encode('utf-8'))] if isinstance(field, MailboxListField): # email_address must be a real account on the server(?) # TODO: Mailbox has multiple optional args but vals must match server account, so we can't easily test if get_random_bool(): return [Mailbox(email_address=self.account.primary_smtp_address)] return [self.account.primary_smtp_address] if isinstance(field, MailboxField): # email_address must be a real account on the server(?) # TODO: Mailbox has multiple optional args but vals must match server account, so we can't easily test if get_random_bool(): return Mailbox(email_address=self.account.primary_smtp_address) return self.account.primary_smtp_address if isinstance(field, AttendeesField): # Attendee must refer to a real mailbox on the server(?). We're only sure to have one if get_random_bool(): mbx = Mailbox(email_address=self.account.primary_smtp_address) else: mbx = self.account.primary_smtp_address with_last_response_time = get_random_bool() if with_last_response_time: return [ Attendee(mailbox=mbx, response_type='Accept', last_response_time=get_random_datetime(tz=self.account.default_timezone)) ] if get_random_bool(): return [Attendee(mailbox=mbx, response_type='Accept')] return [self.account.primary_smtp_address] if isinstance(field, EmailAddressesField): addrs = [] for label in EmailAddress.get_field_by_fieldname('label').supported_choices(version=self.account.version): addr = EmailAddress(email=get_random_email()) addr.label = label addrs.append(addr) return addrs if isinstance(field, PhysicalAddressField): addrs = [] for label in PhysicalAddress.get_field_by_fieldname('label')\ .supported_choices(version=self.account.version): addr = PhysicalAddress(street=get_random_string(32), city=get_random_string(32), state=get_random_string(32), country=get_random_string(32), zipcode=get_random_string(8)) addr.label = label addrs.append(addr) return addrs if isinstance(field, PhoneNumberField): pns = [] for label in PhoneNumber.get_field_by_fieldname('label').supported_choices(version=self.account.version): pn = PhoneNumber(phone_number=get_random_string(16)) pn.label = label pns.append(pn) return pns if isinstance(field, EWSElementField): if field.value_cls == Recurrence: return Recurrence(pattern=DailyPattern(interval=5), start=get_random_date(), number=7) if field.value_cls == TaskRecurrence: return TaskRecurrence(pattern=DailyRegeneration(interval=5), start=get_random_date(), number=7) if field.value_cls == ReminderMessageData: start = get_random_time() end = get_random_time(start_time=start) return ReminderMessageData( reminder_text=get_random_string(16), location=get_random_string(16), start_time=start, end_time=end, ) if field.value_cls == CompleteName: return CompleteName( title=get_random_string(16), first_name=get_random_string(16), middle_name=get_random_string(16), last_name=get_random_string(16), suffix=get_random_string(16), initials=get_random_string(16), full_name=get_random_string(16), nickname=get_random_string(16), yomi_first_name=get_random_string(16), yomi_last_name=get_random_string(16), ) if isinstance(field, TimeZoneField): while True: tz = zoneinfo.ZoneInfo(random.choice(tuple(zoneinfo.available_timezones()))) try: EWSTimeZone.from_zoneinfo(tz) except UnknownTimeZone: continue return tz if isinstance(field, PermissionSetField): return PermissionSet( permissions=[ Permission( user_id=UserId(primary_smtp_address=self.account.primary_smtp_address), ) ] ) raise ValueError('Unknown field %s' % field)
def test_recurring_item(self): """Changes to an occurrence of a recurring task cause one-off tasks to be generated when the following updates are made: * The status property of a regenerating or nonregenerating recurrent task is set to Completed. * The start date or end date of a nonregenerating recurrent task is changed. """ # Create a master non-regenerating item with 4 daily occurrences start = EWSDate(2016, 1, 1) recurrence = TaskRecurrence(pattern=DailyPattern(interval=1), start=start, number=4) nonregenerating_item = self.ITEM_CLASS( folder=self.test_folder, categories=self.categories, recurrence=recurrence, ).save() nonregenerating_item.refresh() master_item_id = nonregenerating_item.id self.assertEqual(nonregenerating_item.is_recurring, True) self.assertEqual(nonregenerating_item.change_count, 1) self.assertEqual(self.test_folder.filter(categories__contains=self.categories).count(), 1) # Change the start date. We should see a new task appear. master_item = self.get_item_by_id((master_item_id, None)) master_item.recurrence.boundary.start = EWSDate(2016, 2, 1) occurrence_item = master_item.save() occurrence_item.refresh() self.assertEqual(occurrence_item.is_recurring, False) # This is now the occurrence self.assertEqual(self.test_folder.filter(categories__contains=self.categories).count(), 2) # Check fields on the recurring item master_item = self.get_item_by_id((master_item_id, None)) self.assertEqual(master_item.change_count, 2) self.assertEqual(master_item.due_date, EWSDate(2016, 1, 2)) # This is the next occurrence self.assertEqual(master_item.recurrence.boundary.number, 3) # One less # Change the status to 'Completed'. We should see a new task appear. master_item.status = Task.COMPLETED occurrence_item = master_item.save() occurrence_item.refresh() self.assertEqual(occurrence_item.is_recurring, False) # This is now the occurrence self.assertEqual(self.test_folder.filter(categories__contains=self.categories).count(), 3) # Check fields on the recurring item master_item = self.get_item_by_id((master_item_id, None)) self.assertEqual(master_item.change_count, 3) self.assertEqual(master_item.due_date, EWSDate(2016, 2, 1)) # This is the next occurrence self.assertEqual(master_item.recurrence.boundary.number, 2) # One less self.test_folder.filter(categories__contains=self.categories).delete() # Create a master regenerating item with 4 daily occurrences recurrence = TaskRecurrence(pattern=DailyRegeneration(interval=1), start=start, number=4) regenerating_item = self.ITEM_CLASS( folder=self.test_folder, categories=self.categories, recurrence=recurrence, ).save() regenerating_item.refresh() master_item_id = regenerating_item.id self.assertEqual(regenerating_item.is_recurring, True) self.assertEqual(regenerating_item.change_count, 1) self.assertEqual(self.test_folder.filter(categories__contains=self.categories).count(), 1) # Change the start date. We should *not* see a new task appear. master_item = self.get_item_by_id((master_item_id, None)) master_item.recurrence.boundary.start = EWSDate(2016, 1, 2) occurrence_item = master_item.save() occurrence_item.refresh() self.assertEqual(occurrence_item.id, master_item.id) # This is not an occurrence. No new task was created self.assertEqual(self.test_folder.filter(categories__contains=self.categories).count(), 1) # Change the status to 'Completed'. We should see a new task appear. master_item.status = Task.COMPLETED occurrence_item = master_item.save() occurrence_item.refresh() self.assertEqual(occurrence_item.is_recurring, False) # This is now the occurrence self.assertEqual(self.test_folder.filter(categories__contains=self.categories).count(), 2) # Check fields on the recurring item master_item = self.get_item_by_id((master_item_id, None)) self.assertEqual(master_item.change_count, 2) # The due date is the next occurrence after today tz = self.account.default_timezone self.assertEqual(master_item.due_date, EWSDateTime.now(tz).date() + datetime.timedelta(days=1)) self.assertEqual(master_item.recurrence.boundary.number, 3) # One less