Merge branch 'admins' into 'master'
[mailman.git] / src / mailman / rest / tests / test_validator.py
blob8341f5f1e55b831a8262a86f5938f9471fd9acff
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)
8 # any later version.
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
13 # more details.
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."""
20 import unittest
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,
31 email_validator,
32 enum_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,
38 subscriber_validator,
39 url_validator,
40 Validator,
42 from mailman.testing.layers import RESTLayer
43 from zope.component import getUtility
46 class TestValidators(unittest.TestCase):
47 layer = RESTLayer
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.
55 self.assertEqual(
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'),
110 'anne@example.com')
112 def test_subscriber_validator_email_address_API31(self):
113 self.assertEqual(subscriber_validator(API31)('anne@example.com'),
114 '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):
127 self.assertEqual(
128 list_of_emails_validator(['foo@example.com', 'bar@example.com']),
129 ['foo@example.com', 'bar@example.com'])
130 self.assertEqual(
131 list_of_emails_validator('bar@example.com'),
132 ['bar@example.com'])
134 def test_list_of_emails_validator_invalid(self):
135 self.assertRaises(
136 ValueError, list_of_emails_validator, 'foo.example.com')
137 self.assertRaises(
138 ValueError,
139 list_of_emails_validator,
140 ['foo@example.com', 'bar.example.com'])
142 def test_email_or_regexp_validator_valid(self):
143 self.assertEqual(
144 email_or_regexp_validator('foo@example.com'),
145 'foo@example.com')
146 self.assertEqual(
147 email_or_regexp_validator('^[^@]+'),
148 '^[^@]+')
150 def test_email_or_regexp_validator_invalid(self):
151 self.assertRaises(
152 ValueError, email_or_regexp_validator, 'foo.example.com')
153 self.assertRaises(
154 ValueError, email_or_regexp_validator, '^[^@]+(')
155 self.assertRaises(
156 ValueError, email_or_regexp_validator, '')
158 def test_list_of_emails_or_regexp_validator_valid(self):
159 self.assertEqual(
160 list_of_emails_or_regexp_validator(
161 ['foo@example.com', '^.*@example.com']),
162 ['foo@example.com', '^.*@example.com'])
163 self.assertEqual(
164 list_of_emails_or_regexp_validator([]), [])
166 def test_list_of_emails_or_regexp_validator_invalid(self):
167 self.assertRaises(
168 ValueError, list_of_emails_or_regexp_validator, 'foo.example.com')
169 self.assertRaises(
170 ValueError, list_of_emails_or_regexp_validator,
171 ['foo.example.com', '^.*@example.com'])
172 self.assertRaises(
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):
177 self.assertEqual(
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'])
181 self.assertEqual(
182 list_of_emails_or_regexp_or_atlist_validator([]), [])
183 self.assertEqual(
184 list_of_emails_or_regexp_or_atlist_validator(''), [])
186 def test_list_of_emails_or_regexp_or_atlist_validator_invalid(self):
187 self.assertRaises(
188 ValueError, list_of_emails_or_regexp_or_atlist_validator,
189 'foo.example.com')
190 self.assertRaises(
191 ValueError, list_of_emails_or_regexp_or_atlist_validator,
192 ['foo@example.com', '^*@example.com'])
193 self.assertRaises(
194 ValueError, list_of_emails_or_regexp_or_atlist_validator,
195 ['foo@example.com', '^.*@example.com', '@bar.example.com'])
196 self.assertRaises(
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):
206 class RequestTrue:
207 params = dict(key=True)
208 content_type = 'application/x-www-form-urlencoded'
210 class RequestFalse:
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):
219 self.assertEqual(
220 url_validator('http://example.com/mailma3'),
221 'http://example.com/mailma3')
222 self.assertEqual(
223 url_validator('https://example.com/postorius'),
224 'https://example.com/postorius')
225 # Missing /postorius or /mailman3 in the end.
226 self.assertRaises(
227 ValueError,
228 url_validator,
229 'https://example.com')
230 # missing scheme.
231 self.assertRaises(
232 ValueError,
233 url_validator,
234 'example.com/mailman3')
237 class TestGetterSetter(unittest.TestCase):
238 """Test the GeterSetter class"""
240 layer = RESTLayer
242 def setUp(self):
243 with transaction():
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):
252 self.getset.put(
253 self._mlist, 'pass_types', ['application/octet-stream'])
254 self.getset.put(
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),
259 ['.pdf'])
261 def test_set_boolean_as_bool(self):
262 # Non-pythonic POST data can contain JSON booleans. Ensure we can
263 # handle that.
264 getset = helpers.GetterSetter(as_boolean)
265 self.assertTrue(getset(True))
266 self.assertFalse(getset(False))