71
101
self.assertTrue(self._mlist.allow_list_posts)
72
102
self.assertTrue(self._mlist.include_rfc2369_headers)
104
def test_no_overwrite_rosters(self):
105
# The mlist.members and mlist.digest_members rosters must not be
107
for rname in ('members', 'digest_members'):
108
roster = getattr(self._mlist, rname)
109
self.assertFalse(isinstance(roster, dict))
112
isinstance(roster, dict),
113
'The %s roster has been overwritten by the import' % rname)
115
def test_last_post_time(self):
116
# last_post_time -> last_post_at
117
self._pckdict['last_post_time'] = 1270420800.274485
118
self.assertEqual(self._mlist.last_post_at, None)
120
# convert 1270420800.2744851 to datetime
121
expected = datetime(2010, 4, 4, 22, 40, 0, 274485)
122
self.assertEqual(self._mlist.last_post_at, expected)
124
def test_autoresponse_grace_period(self):
125
# autoresponse_graceperiod -> autoresponse_grace_period
126
# must be a timedelta, not an int
127
self._mlist.autoresponse_grace_period = timedelta(days=42)
130
isinstance(self._mlist.autoresponse_grace_period, timedelta))
131
self.assertEqual(self._mlist.autoresponse_grace_period,
134
def test_autoresponse_admin_to_owner(self):
136
self._mlist.autorespond_owner = DummyEnum.val
137
self._mlist.autoresponse_owner_text = 'DUMMY'
139
self.assertEqual(self._mlist.autorespond_owner, ResponseAction.none)
140
self.assertEqual(self._mlist.autoresponse_owner_text, '')
142
def test_administrativia(self):
143
self._mlist.administrivia = None
145
self.assertTrue(self._mlist.administrivia)
147
def test_filter_pass_renames(self):
148
# mime_types -> types
149
# filename_extensions -> extensions
150
self._mlist.filter_types = ['dummy']
151
self._mlist.pass_types = ['dummy']
152
self._mlist.filter_extensions = ['dummy']
153
self._mlist.pass_extensions = ['dummy']
155
self.assertEqual(list(self._mlist.filter_types), [])
156
self.assertEqual(list(self._mlist.filter_extensions),
157
['exe', 'bat', 'cmd', 'com', 'pif',
158
'scr', 'vbs', 'cpl'])
159
self.assertEqual(list(self._mlist.pass_types),
160
['multipart/mixed', 'multipart/alternative', 'text/plain'])
161
self.assertEqual(list(self._mlist.pass_extensions), [])
163
def test_process_bounces(self):
164
# bounce_processing -> process_bounces
165
self._mlist.process_bounces = None
167
self.assertTrue(self._mlist.process_bounces)
169
def test_forward_unrecognized_bounces_to(self):
170
# bounce_unrecognized_goes_to_list_owner
171
# -> forward_unrecognized_bounces_to
172
self._mlist.forward_unrecognized_bounces_to = DummyEnum.val
174
self.assertEqual(self._mlist.forward_unrecognized_bounces_to,
175
UnrecognizedBounceDisposition.administrators)
177
def test_moderator_password(self):
178
# mod_password -> moderator_password
179
self._mlist.moderator_password = str('TESTDATA')
181
self.assertEqual(self._mlist.moderator_password, None)
183
def test_moderator_password_str(self):
184
# moderator_password must not be unicode
185
self._pckdict[b'mod_password'] = b'TESTVALUE'
187
self.assertFalse(isinstance(self._mlist.moderator_password, unicode))
188
self.assertEqual(self._mlist.moderator_password, b'TESTVALUE')
190
def test_newsgroup_moderation(self):
191
# news_moderation -> newsgroup_moderation
192
# news_prefix_subject_too -> nntp_prefix_subject_too
193
self._mlist.newsgroup_moderation = DummyEnum.val
194
self._mlist.nntp_prefix_subject_too = None
196
self.assertEqual(self._mlist.newsgroup_moderation,
197
NewsgroupModeration.none)
198
self.assertTrue(self._mlist.nntp_prefix_subject_too)
200
def test_msg_to_message(self):
201
# send_welcome_msg -> send_welcome_message
202
# send_goodbye_msg -> send_goodbye_message
203
self._mlist.send_welcome_message = None
204
self._mlist.send_goodbye_message = None
206
self.assertTrue(self._mlist.send_welcome_message)
207
self.assertTrue(self._mlist.send_goodbye_message)
209
def test_ban_list(self):
211
('anne@example.com', 'anne@example.com'),
212
('^.*@example.com', 'bob@example.com'),
213
('non-ascii-\xe8@example.com', 'non-ascii-\ufffd@example.com'),
215
self._pckdict['ban_list'] = [b[0].encode('iso-8859-1') for b in banned]
217
for _pattern, addr in banned:
218
self.assertTrue(IBanManager(self._mlist).is_banned(addr))
220
def test_acceptable_aliases(self):
221
# This used to be a plain-text field (values are newline-separated).
222
aliases = ['alias1@example.com',
223
'alias2@exemple.com',
224
'non-ascii-\xe8@example.com',
226
self._pckdict[b'acceptable_aliases'] = list_to_string(aliases)
228
alias_set = IAcceptableAliasSet(self._mlist)
229
self.assertEqual(sorted(alias_set.aliases), aliases)
231
def test_acceptable_aliases_invalid(self):
232
# Values without an '@' sign used to be matched against the local
233
# part, now we need to add the '^' sign to indicate it's a regexp.
234
aliases = ['invalid-value']
235
self._pckdict[b'acceptable_aliases'] = list_to_string(aliases)
237
alias_set = IAcceptableAliasSet(self._mlist)
238
self.assertEqual(sorted(alias_set.aliases),
239
[('^' + alias) for alias in aliases])
241
def test_acceptable_aliases_as_list(self):
242
# In some versions of the pickle, this can be a list, not a string
243
# (seen in the wild).
244
aliases = [b'alias1@example.com', b'alias2@exemple.com' ]
245
self._pckdict[b'acceptable_aliases'] = aliases
247
alias_set = IAcceptableAliasSet(self._mlist)
248
self.assertEqual(sorted(alias_set.aliases), aliases)
250
def test_info_non_ascii(self):
251
# info can contain non-ascii characters.
252
info = 'O idioma aceito \xe9 somente Portugu\xeas do Brasil'
253
self._pckdict[b'info'] = info.encode('utf-8')
255
self.assertEqual(self._mlist.info, info,
256
'Encoding to UTF-8 is not handled')
257
# Test fallback to ascii with replace.
258
self._pckdict[b'info'] = info.encode('iso-8859-1')
260
self.assertEqual(self._mlist.info,
261
unicode(self._pckdict[b'info'], 'ascii', 'replace'),
262
"We don't fall back to replacing non-ascii chars")
264
def test_preferred_language(self):
265
self._pckdict[b'preferred_language'] = b'ja'
266
english = getUtility(ILanguageManager).get('en')
267
japanese = getUtility(ILanguageManager).get('ja')
268
self.assertEqual(self._mlist.preferred_language, english)
270
self.assertEqual(self._mlist.preferred_language, japanese)
272
def test_preferred_language_unknown_previous(self):
273
# When the previous language is unknown, it should not fail.
274
self._mlist._preferred_language = 'xx'
276
english = getUtility(ILanguageManager).get('en')
277
self.assertEqual(self._mlist.preferred_language, english)
279
def test_new_language(self):
280
self._pckdict[b'preferred_language'] = b'xx_XX'
283
except Import21Error as error:
285
self.assertIn('[language.xx_XX]', str(error))
287
self.fail('Import21Error was not raised')
76
291
class TestArchiveImport(unittest.TestCase):
123
338
# For some reason, the old list was missing an `archive_private` key.
124
339
# For maximum safety, we treat this as private archiving.
125
340
self._do_test(dict(archive=True), ArchivePolicy.private)
344
class TestFilterActionImport(unittest.TestCase):
345
# The mlist.filter_action enum values have changed. In Mailman 2.1 the
346
# order was 'Discard', 'Reject', 'Forward to List Owner', 'Preserve'.
351
self._mlist = create_list('blank@example.com')
352
self._mlist.filter_action = DummyEnum.val
354
def _do_test(self, original, expected):
355
import_config_pck(self._mlist, dict(filter_action=original))
356
self.assertEqual(self._mlist.filter_action, expected)
358
def test_discard(self):
359
self._do_test(0, FilterAction.discard)
361
def test_reject(self):
362
self._do_test(1, FilterAction.reject)
364
def test_forward(self):
365
self._do_test(2, FilterAction.forward)
367
def test_preserve(self):
368
self._do_test(3, FilterAction.preserve)
372
class TestMemberActionImport(unittest.TestCase):
373
# The mlist.default_member_action and mlist.default_nonmember_action enum
374
# values are different in Mailman 2.1; they have been merged into a
375
# single enum in Mailman 3.
377
# For default_member_action, which used to be called
378
# member_moderation_action, the values were:
379
# 0==Hold, 1=Reject, 2==Discard
381
# For default_nonmember_action, which used to be called
382
# generic_nonmember_action, the values were:
383
# 0==Accept, 1==Hold, 2==Reject, 3==Discard
388
self._mlist = create_list('blank@example.com')
389
self._mlist.default_member_action = DummyEnum.val
390
self._mlist.default_nonmember_action = DummyEnum.val
391
self._pckdict = dict(
392
member_moderation_action=DummyEnum.val,
393
generic_nonmember_action=DummyEnum.val,
396
def _do_test(self, expected):
397
import_config_pck(self._mlist, self._pckdict)
398
for key, value in expected.iteritems():
399
self.assertEqual(getattr(self._mlist, key), value)
401
def test_member_hold(self):
402
self._pckdict[b'member_moderation_action'] = 0
403
self._do_test(dict(default_member_action=Action.hold))
405
def test_member_reject(self):
406
self._pckdict[b'member_moderation_action'] = 1
407
self._do_test(dict(default_member_action=Action.reject))
409
def test_member_discard(self):
410
self._pckdict[b'member_moderation_action'] = 2
411
self._do_test(dict(default_member_action=Action.discard))
413
def test_nonmember_accept(self):
414
self._pckdict[b'generic_nonmember_action'] = 0
415
self._do_test(dict(default_nonmember_action=Action.accept))
417
def test_nonmember_hold(self):
418
self._pckdict[b'generic_nonmember_action'] = 1
419
self._do_test(dict(default_nonmember_action=Action.hold))
421
def test_nonmember_reject(self):
422
self._pckdict[b'generic_nonmember_action'] = 2
423
self._do_test(dict(default_nonmember_action=Action.reject))
425
def test_nonmember_discard(self):
426
self._pckdict[b'generic_nonmember_action'] = 3
427
self._do_test(dict(default_nonmember_action=Action.discard))
431
class TestConvertToURI(unittest.TestCase):
432
# The following values were plain text, and are now URIs in Mailman 3:
433
# - welcome_message_uri
434
# - goodbye_message_uri
437
# - digest_header_uri
438
# - digest_footer_uri
440
# The templates contain variables that must be replaced:
441
# - %(real_name)s -> %(display_name)s
442
# - %(real_name)s@%(host_name)s -> %(fqdn_listname)s
443
# - %(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s
444
# -> %(listinfo_uri)s
449
self._mlist = create_list('blank@example.com')
450
self._conf_mapping = dict(
451
welcome_msg='welcome_message_uri',
452
goodbye_msg='goodbye_message_uri',
453
msg_header='header_uri',
454
msg_footer='footer_uri',
455
digest_header='digest_header_uri',
456
digest_footer='digest_footer_uri',
458
self._pckdict = dict()
460
def test_text_to_uri(self):
461
for oldvar, newvar in self._conf_mapping.items():
462
self._pckdict[str(oldvar)] = b'TEST VALUE'
463
import_config_pck(self._mlist, self._pckdict)
464
newattr = getattr(self._mlist, newvar)
465
text = decorate(self._mlist, newattr)
466
self.assertEqual(text, 'TEST VALUE',
467
'Old variable %s was not properly imported to %s'
470
def test_substitutions(self):
471
test_text = ('UNIT TESTING %(real_name)s mailing list\n'
472
'%(real_name)s@%(host_name)s\n'
473
'%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s')
474
expected_text = ('UNIT TESTING $display_name mailing list\n'
477
for oldvar, newvar in self._conf_mapping.items():
478
self._pckdict[str(oldvar)] = str(test_text)
479
import_config_pck(self._mlist, self._pckdict)
480
newattr = getattr(self._mlist, newvar)
481
template_uri = expand(newattr, dict(
482
listname=self._mlist.fqdn_listname,
483
language=self._mlist.preferred_language.code,
485
loader = getUtility(ITemplateLoader)
486
text = loader.get(template_uri)
487
self.assertEqual(text, expected_text,
488
'Old variables were not converted for %s' % newvar)
490
def test_keep_default(self):
491
# If the value was not changed from MM2.1's default, don't import it.
492
default_msg_footer = (
493
'_______________________________________________\n'
494
'%(real_name)s mailing list\n'
495
'%(real_name)s@%(host_name)s\n'
496
'%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s'
498
for oldvar in ('msg_footer', 'digest_footer'):
499
newvar = self._conf_mapping[oldvar]
500
self._pckdict[str(oldvar)] = str(default_msg_footer)
501
old_value = getattr(self._mlist, newvar)
502
import_config_pck(self._mlist, self._pckdict)
503
new_value = getattr(self._mlist, newvar)
504
self.assertEqual(old_value, new_value,
505
'Default value was not preserved for %s' % newvar)
507
def test_keep_default_if_fqdn_changed(self):
508
# Use case: importing the old a@ex.com into b@ex.com. We can't check
509
# if it changed from the default so don't import. We may do more harm
510
# than good and it's easy to change if needed.
511
test_value = b'TEST-VALUE'
512
for oldvar, newvar in self._conf_mapping.iteritems():
513
self._mlist.mail_host = 'example.com'
514
self._pckdict[b'mail_host'] = b'test.example.com'
515
self._pckdict[str(oldvar)] = test_value
516
old_value = getattr(self._mlist, newvar)
517
import_config_pck(self._mlist, self._pckdict)
518
new_value = getattr(self._mlist, newvar)
519
self.assertEqual(old_value, new_value,
520
'Default value was not preserved for %s' % newvar)
522
def test_unicode(self):
523
# non-ascii templates
524
for oldvar in self._conf_mapping:
525
self._pckdict[str(oldvar)] = b'Ol\xe1!'
526
import_config_pck(self._mlist, self._pckdict)
527
for oldvar, newvar in self._conf_mapping.iteritems():
528
newattr = getattr(self._mlist, newvar)
529
text = decorate(self._mlist, newattr)
530
expected = u'Ol\ufffd!'
531
self.assertEqual(text, expected)
533
def test_unicode_in_default(self):
534
# What if the default template is already in UTF-8? For example, if
535
# you import it twice.
536
footer = b'\xe4\xb8\xad $listinfo_uri'
537
footer_path = os.path.join(
538
config.VAR_DIR, 'templates', 'lists',
539
'blank@example.com', 'en', 'footer-generic.txt')
540
makedirs(os.path.dirname(footer_path))
541
with open(footer_path, 'wb') as fp:
543
self._pckdict[b'msg_footer'] = b'NEW-VALUE'
544
import_config_pck(self._mlist, self._pckdict)
545
text = decorate(self._mlist, self._mlist.footer_uri)
546
self.assertEqual(text, 'NEW-VALUE')
549
class TestRosterImport(unittest.TestCase):
550
"""Test that rosters are imported correctly."""
555
self._mlist = create_list('blank@example.com')
558
'anne@example.com': 0,
559
'bob@example.com': b'bob@ExampLe.Com',
562
'cindy@example.com': 0,
563
'dave@example.com': b'dave@ExampLe.Com',
566
'anne@example.com' : b'annepass',
567
'bob@example.com' : b'bobpass',
568
'cindy@example.com': b'cindypass',
569
'dave@example.com' : b'davepass',
572
'anne@example.com' : b'fr',
573
'bob@example.com' : b'de',
574
'cindy@example.com': b'es',
575
'dave@example.com' : b'it',
577
'usernames': { # Usernames are unicode strings in the pickle
578
'anne@example.com' : 'Anne',
579
'bob@example.com' : 'Bob',
580
'cindy@example.com': 'Cindy',
581
'dave@example.com' : 'Dave',
592
self._usermanager = getUtility(IUserManager)
593
language_manager = getUtility(ILanguageManager)
594
for code in self._pckdict['language'].values():
595
if code not in language_manager.codes:
596
language_manager.add(code, 'utf-8', code)
598
def test_member(self):
599
import_config_pck(self._mlist, self._pckdict)
600
for name in ('anne', 'bob', 'cindy', 'dave'):
601
addr = '%s@example.com' % name
603
[a.email for a in self._mlist.members.addresses],
604
'Address %s was not imported' % addr)
605
self.assertIn('anne@example.com',
606
[a.email for a in self._mlist.regular_members.addresses])
607
self.assertIn('bob@example.com',
608
[a.email for a in self._mlist.regular_members.addresses])
609
self.assertIn('cindy@example.com',
610
[a.email for a in self._mlist.digest_members.addresses])
611
self.assertIn('dave@example.com',
612
[a.email for a in self._mlist.digest_members.addresses])
614
def test_original_email(self):
615
import_config_pck(self._mlist, self._pckdict)
616
bob = self._usermanager.get_address('bob@example.com')
617
self.assertEqual(bob.original_email, 'bob@ExampLe.Com')
618
dave = self._usermanager.get_address('dave@example.com')
619
self.assertEqual(dave.original_email, 'dave@ExampLe.Com')
621
def test_language(self):
622
import_config_pck(self._mlist, self._pckdict)
623
for name in ('anne', 'bob', 'cindy', 'dave'):
624
addr = '%s@example.com' % name
625
member = self._mlist.members.get_member(addr)
626
self.assertIsNotNone(member, 'Address %s was not imported' % addr)
627
self.assertEqual(member.preferred_language.code,
628
self._pckdict['language'][addr])
630
def test_new_language(self):
631
self._pckdict[b'language']['anne@example.com'] = b'xx_XX'
633
import_config_pck(self._mlist, self._pckdict)
634
except Import21Error as error:
635
self.assertIn('[language.xx_XX]', str(error))
637
self.fail('Import21Error was not raised')
639
def test_username(self):
640
import_config_pck(self._mlist, self._pckdict)
641
for name in ('anne', 'bob', 'cindy', 'dave'):
642
addr = '%s@example.com' % name
643
user = self._usermanager.get_user(addr)
644
address = self._usermanager.get_address(addr)
645
self.assertIsNotNone(user, 'User %s was not imported' % addr)
646
self.assertIsNotNone(address, 'Address %s was not imported' % addr)
647
display_name = self._pckdict['usernames'][addr]
648
self.assertEqual(user.display_name, display_name,
649
'The display name was not set for User %s' % addr)
650
self.assertEqual(address.display_name, display_name,
651
'The display name was not set for Address %s' % addr)
653
def test_owner(self):
654
import_config_pck(self._mlist, self._pckdict)
655
for name in ('anne', 'emily'):
656
addr = '%s@example.com' % name
658
[a.email for a in self._mlist.owners.addresses],
659
'Address %s was not imported as owner' % addr)
662
[a.email for a in self._mlist.members.addresses],
663
'Address emily@ was wrongly added to the members list')
665
def test_moderator(self):
666
import_config_pck(self._mlist, self._pckdict)
667
for name in ('bob', 'fred'):
668
addr = '%s@example.com' % name
670
[a.email for a in self._mlist.moderators.addresses],
671
'Address %s was not imported as moderator' % addr)
672
self.assertNotIn('fred@example.com',
673
[a.email for a in self._mlist.members.addresses],
674
'Address fred@ was wrongly added to the members list')
676
def test_password(self):
677
#self.anne.password = config.password_context.encrypt('abc123')
678
import_config_pck(self._mlist, self._pckdict)
679
for name in ('anne', 'bob', 'cindy', 'dave'):
680
addr = '%s@example.com' % name
681
user = self._usermanager.get_user(addr)
682
self.assertIsNotNone(user, 'Address %s was not imported' % addr)
684
user.password, b'{plaintext}%spass' % name,
685
'Password for %s was not imported' % addr)
687
def test_same_user(self):
688
# Adding the address of an existing User must not create another user.
689
user = self._usermanager.create_user('anne@example.com', 'Anne')
690
user.register('bob@example.com') # secondary email
691
import_config_pck(self._mlist, self._pckdict)
692
member = self._mlist.members.get_member('bob@example.com')
693
self.assertEqual(member.user, user)
695
def test_owner_and_moderator_not_lowercase(self):
696
# In the v2.1 pickled dict, the owner and moderator lists are not
697
# necessarily lowercased already.
698
self._pckdict['owner'] = [b'Anne@example.com']
699
self._pckdict['moderator'] = [b'Anne@example.com']
700
import_config_pck(self._mlist, self._pckdict)
701
self.assertIn('anne@example.com',
702
[a.email for a in self._mlist.owners.addresses])
703
self.assertIn('anne@example.com',
704
[a.email for a in self._mlist.moderators.addresses])
706
def test_address_already_exists_but_no_user(self):
707
# An address already exists, but it is not linked to a user nor
709
anne_addr = self._usermanager.create_address(
710
'anne@example.com', 'Anne')
711
import_config_pck(self._mlist, self._pckdict)
712
anne = self._usermanager.get_user('anne@example.com')
713
self.assertTrue(anne.controls('anne@example.com'))
714
self.assertIn(anne_addr, self._mlist.regular_members.addresses)
716
def test_address_already_subscribed_but_no_user(self):
717
# An address is already subscribed, but it is not linked to a user.
718
anne_addr = self._usermanager.create_address(
719
'anne@example.com', 'Anne')
720
self._mlist.subscribe(anne_addr)
721
import_config_pck(self._mlist, self._pckdict)
722
anne = self._usermanager.get_user('anne@example.com')
723
self.assertTrue(anne.controls('anne@example.com'))
728
class TestPreferencesImport(unittest.TestCase):
729
"""Preferences get imported too."""
734
self._mlist = create_list('blank@example.com')
735
self._pckdict = dict(
736
members={'anne@example.com': 0},
738
delivery_status=dict(),
740
self._usermanager = getUtility(IUserManager)
742
def _do_test(self, oldvalue, expected):
743
self._pckdict['user_options']['anne@example.com'] = oldvalue
744
import_config_pck(self._mlist, self._pckdict)
745
user = self._usermanager.get_user('anne@example.com')
746
self.assertIsNotNone(user, 'User was not imported')
747
member = self._mlist.members.get_member('anne@example.com')
748
self.assertIsNotNone(member, 'Address was not subscribed')
749
for exp_name, exp_val in expected.iteritems():
751
currentval = getattr(member, exp_name)
752
except AttributeError:
753
# hide_address has no direct getter
754
currentval = getattr(member.preferences, exp_name)
757
'Preference %s was not imported' % exp_name)
758
# XXX: should I check that other params are still equal to
759
# mailman.core.constants.system_preferences?
761
def test_acknowledge_posts(self):
763
self._do_test(4, dict(acknowledge_posts=True))
765
def test_hide_address(self):
766
# ConcealSubscription
767
self._do_test(16, dict(hide_address=True))
769
def test_receive_own_postings(self):
770
# DontReceiveOwnPosts
771
self._do_test(2, dict(receive_own_postings=False))
773
def test_receive_list_copy(self):
774
# DontReceiveDuplicates
775
self._do_test(256, dict(receive_list_copy=False))
777
def test_digest_plain(self):
778
# Digests & DisableMime
779
self._pckdict['digest_members'] = self._pckdict['members'].copy()
780
self._pckdict['members'] = dict()
781
self._do_test(8, dict(delivery_mode=DeliveryMode.plaintext_digests))
783
def test_digest_mime(self):
784
# Digests & not DisableMime
785
self._pckdict['digest_members'] = self._pckdict['members'].copy()
786
self._pckdict['members'] = dict()
787
self._do_test(0, dict(delivery_mode=DeliveryMode.mime_digests))
789
def test_delivery_status(self):
790
# Look for the pckdict['delivery_status'] key which will look like
791
# (status, time) where status is among the following:
792
# ENABLED = 0 # enabled
793
# UNKNOWN = 1 # legacy disabled
794
# BYUSER = 2 # disabled by user choice
795
# BYADMIN = 3 # disabled by admin choice
796
# BYBOUNCE = 4 # disabled by bounces
797
for oldval, expected in enumerate((
798
DeliveryStatus.enabled,
799
DeliveryStatus.unknown, DeliveryStatus.by_user,
800
DeliveryStatus.by_moderator, DeliveryStatus.by_bounces)):
801
self._pckdict['delivery_status']['anne@example.com'] = (oldval, 0)
802
import_config_pck(self._mlist, self._pckdict)
803
member = self._mlist.members.get_member('anne@example.com')
804
self.assertIsNotNone(member, 'Address was not subscribed')
805
self.assertEqual(member.delivery_status, expected)
808
def test_moderate(self):
809
# Option flag Moderate is translated to
810
# member.moderation_action = Action.hold
811
self._do_test(128, dict(moderation_action=Action.hold))
813
def test_multiple_options(self):
814
# DontReceiveDuplicates & DisableMime & SuppressPasswordReminder
815
self._pckdict[b'digest_members'] = self._pckdict[b'members'].copy()
816
self._pckdict[b'members'] = dict()
817
self._do_test(296, dict(
818
receive_list_copy=False,
819
delivery_mode=DeliveryMode.plaintext_digests,