1 # Copyright (C) 2015-2023 by the Free Software Foundation, Inc.
3 # This file is part of GNU Mailman.
5 # GNU Mailman is free software: you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free
7 # Software Foundation, either version 3 of the License, or (at your option)
10 # GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 # You should have received a copy of the GNU General Public License along with
16 # GNU Mailman. If not, see <https://www.gnu.org/licenses/>.
18 """Test REST validators."""
22 from lazr
.config
import as_boolean
23 from mailman
.app
.lifecycle
import create_list
24 from mailman
.core
.api
import API30
, API31
25 from mailman
.database
.transaction
import transaction
26 from mailman
.interfaces
.action
import Action
27 from mailman
.interfaces
.usermanager
import IUserManager
28 from mailman
.rest
import helpers
29 from mailman
.rest
.validator
import (
30 email_or_regexp_validator
,
33 integer_ge_zero_validator
,
34 list_of_emails_or_regexp_or_atlist_validator
,
35 list_of_emails_or_regexp_validator
,
36 list_of_emails_validator
,
37 list_of_strings_validator
,
42 from mailman
.testing
.layers
import RESTLayer
43 from zope
.component
import getUtility
46 class TestValidators(unittest
.TestCase
):
49 def test_list_of_strings_validator_single(self
):
50 # This validator should turn a single key into a list of keys.
51 self
.assertEqual(list_of_strings_validator('ant'), ['ant'])
53 def test_list_of_strings_validator_multiple(self
):
54 # This validator should turn a single key into a list of keys.
56 list_of_strings_validator(['ant', 'bee', 'cat']),
57 ['ant', 'bee', 'cat'])
59 def test_list_of_strings_validator_empty_list(self
):
60 # This validator should return an empty list for an empty string input.
61 self
.assertEqual(list_of_strings_validator(''), [])
63 def test_list_of_emails_or_regexp_validator_empty_list(self
):
64 # This validator should return an empty list for an empty string input.
65 self
.assertEqual(list_of_emails_or_regexp_validator(''), [])
67 def test_integer_ge_zero_validator_invalid(self
):
68 self
.assertRaises(ValueError, integer_ge_zero_validator
, 'foo')
69 self
.assertRaises(ValueError, integer_ge_zero_validator
, '-1')
71 def test_integer_ge_zero_validator_valid(self
):
72 self
.assertEqual(integer_ge_zero_validator('0'), 0)
73 self
.assertEqual(integer_ge_zero_validator('100'), 100)
75 def test_list_of_strings_validator_invalid(self
):
76 # Strings are required.
77 self
.assertRaises(ValueError, list_of_strings_validator
, 7)
78 self
.assertRaises(ValueError, list_of_strings_validator
, ['ant', 7])
80 def test_subscriber_validator_int_uuid(self
):
81 # Convert from an existing user id to a UUID.
82 anne
= getUtility(IUserManager
).make_user('anne@example.com')
83 uuid
= subscriber_validator(API30
)(str(anne
.user_id
.int))
84 self
.assertEqual(anne
.user_id
, uuid
)
86 def test_subscriber_validator_hex_uuid(self
):
87 # Convert from an existing user id to a UUID.
88 anne
= getUtility(IUserManager
).make_user('anne@example.com')
89 uuid
= subscriber_validator(API31
)(anne
.user_id
.hex)
90 self
.assertEqual(anne
.user_id
, uuid
)
92 def test_subscriber_validator_no_int_uuid(self
):
93 # API 3.1 does not accept ints as subscriber id's.
94 anne
= getUtility(IUserManager
).make_user('anne@example.com')
95 self
.assertRaises(ValueError,
96 subscriber_validator(API31
), str(anne
.user_id
.int))
98 def test_subscriber_validator_bad_int_uuid(self
):
99 # In API 3.0, UUIDs are ints.
100 self
.assertRaises(ValueError,
101 subscriber_validator(API30
), 'not-a-thing')
103 def test_subscriber_validator_bad_int_hex(self
):
104 # In API 3.1, UUIDs are hexes.
105 self
.assertRaises(ValueError,
106 subscriber_validator(API31
), 'not-a-thing')
108 def test_subscriber_validator_email_address_API30(self
):
109 self
.assertEqual(subscriber_validator(API30
)('anne@example.com'),
112 def test_subscriber_validator_email_address_API31(self
):
113 self
.assertEqual(subscriber_validator(API31
)('anne@example.com'),
116 def test_enum_validator_valid(self
):
117 self
.assertEqual(enum_validator(Action
)('hold'), Action
.hold
)
119 def test_enum_validator_invalid(self
):
120 self
.assertRaises(ValueError,
121 enum_validator(Action
), 'not-a-thing')
123 def test_enum_validator_blank(self
):
124 self
.assertEqual(enum_validator(Action
, allow_blank
=True)(''), None)
126 def test_list_of_emails_validator_valid(self
):
128 list_of_emails_validator(['foo@example.com', 'bar@example.com']),
129 ['foo@example.com', 'bar@example.com'])
131 list_of_emails_validator('bar@example.com'),
134 def test_list_of_emails_validator_invalid(self
):
136 ValueError, list_of_emails_validator
, 'foo.example.com')
139 list_of_emails_validator
,
140 ['foo@example.com', 'bar.example.com'])
142 def test_email_or_regexp_validator_valid(self
):
144 email_or_regexp_validator('foo@example.com'),
147 email_or_regexp_validator('^[^@]+'),
150 def test_email_or_regexp_validator_invalid(self
):
152 ValueError, email_or_regexp_validator
, 'foo.example.com')
154 ValueError, email_or_regexp_validator
, '^[^@]+(')
156 ValueError, email_or_regexp_validator
, '')
158 def test_list_of_emails_or_regexp_validator_valid(self
):
160 list_of_emails_or_regexp_validator(
161 ['foo@example.com', '^.*@example.com']),
162 ['foo@example.com', '^.*@example.com'])
164 list_of_emails_or_regexp_validator([]), [])
166 def test_list_of_emails_or_regexp_validator_invalid(self
):
168 ValueError, list_of_emails_or_regexp_validator
, 'foo.example.com')
170 ValueError, list_of_emails_or_regexp_validator
,
171 ['foo.example.com', '^.*@example.com'])
173 ValueError, list_of_emails_or_regexp_validator
,
174 ['foo@example.com', '^*@example.com'])
176 def test_list_of_emails_or_regexp_or_atlist_validator_valid(self
):
178 list_of_emails_or_regexp_or_atlist_validator(
179 ['foo@example.com', '^.*@example.com', '@bar@example.com']),
180 ['foo@example.com', '^.*@example.com', '@bar@example.com'])
182 list_of_emails_or_regexp_or_atlist_validator([]), [])
184 list_of_emails_or_regexp_or_atlist_validator(''), [])
186 def test_list_of_emails_or_regexp_or_atlist_validator_invalid(self
):
188 ValueError, list_of_emails_or_regexp_or_atlist_validator
,
191 ValueError, list_of_emails_or_regexp_or_atlist_validator
,
192 ['foo@example.com', '^*@example.com'])
194 ValueError, list_of_emails_or_regexp_or_atlist_validator
,
195 ['foo@example.com', '^.*@example.com', '@bar.example.com'])
197 ValueError, list_of_emails_or_regexp_or_atlist_validator
, None)
199 def test_email_validator(self
):
200 self
.assertRaises(ValueError,
201 email_validator
, 'foo.example.com')
202 self
.assertEqual('foo@example.com', email_validator('foo@example.com'))
204 def test_validator_class_boolean_as_bool(self
):
207 params
= dict(key
=True)
208 content_type
= 'application/x-www-form-urlencoded'
211 params
= dict(key
=False)
212 content_type
= 'application/x-www-form-urlencoded'
214 validator
= Validator(key
=as_boolean
)
215 self
.assertTrue(validator(RequestTrue
)['key'])
216 self
.assertFalse(validator(RequestFalse
)['key'])
218 def test_url_validator(self
):
220 url_validator('http://example.com/mailma3'),
221 'http://example.com/mailma3')
223 url_validator('https://example.com/postorius'),
224 'https://example.com/postorius')
225 # Missing /postorius or /mailman3 in the end.
229 'https://example.com')
234 'example.com/mailman3')
237 class TestGetterSetter(unittest
.TestCase
):
238 """Test the GeterSetter class"""
244 self
._mlist
= create_list('test@example.com')
245 self
.getset
= helpers
.GetterSetter(list_of_strings_validator
)
247 def test_get_mailinglist_attribute(self
):
248 self
.assertEqual(self
.getset
.get(self
._mlist
, 'pass_types'), [])
249 self
.assertEqual(self
.getset
.get(self
._mlist
, 'pass_extensions'), [])
251 def test_set_mailinglist_attribute(self
):
253 self
._mlist
, 'pass_types', ['application/octet-stream'])
255 self
._mlist
, 'pass_extensions', ['.pdf'])
256 self
.assertEqual(list(self
._mlist
.pass_types
),
257 ['application/octet-stream'])
258 self
.assertEqual(list(self
._mlist
.pass_extensions
),
261 def test_set_boolean_as_bool(self
):
262 # Non-pythonic POST data can contain JSON booleans. Ensure we can
264 getset
= helpers
.GetterSetter(as_boolean
)
265 self
.assertTrue(getset(True))
266 self
.assertFalse(getset(False))