1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
5 Tests for L{twisted.mail.tap}.
8 from twisted.trial.unittest import TestCase
10 from twisted.python.usage import UsageError
11 from twisted.mail import protocols
12 from twisted.mail.tap import Options, makeService
13 from twisted.python import deprecate, versions
14 from twisted.python.filepath import FilePath
15 from twisted.internet import endpoints, defer
18 class OptionsTestCase(TestCase):
20 Tests for the command line option parser used for I{twistd mail}.
23 self.aliasFilename = self.mktemp()
24 aliasFile = file(self.aliasFilename, 'w')
25 aliasFile.write('someuser:\tdifferentuser\n')
29 def testAliasesWithoutDomain(self):
31 Test that adding an aliases(5) file before adding a domain raises a
36 Options().parseOptions,
37 ['--aliases', self.aliasFilename])
40 def testAliases(self):
42 Test that adding an aliases(5) file to an IAliasableDomain at least
43 doesn't raise an unhandled exception.
45 Options().parseOptions([
46 '--maildirdbmdomain', 'example.com=example.com',
47 '--aliases', self.aliasFilename])
50 def testPasswordfileDeprecation(self):
52 Test that the --passwordfile option will emit a correct warning.
54 passwd = FilePath(self.mktemp())
57 options.opt_passwordfile(passwd.path)
58 warnings = self.flushWarnings([self.testPasswordfileDeprecation])
59 self.assertEqual(warnings[0]['category'], DeprecationWarning)
60 self.assertEqual(len(warnings), 1)
61 msg = deprecate.getDeprecationWarningString(options.opt_passwordfile,
62 versions.Version('twisted.mail', 11, 0, 0))
63 self.assertEqual(warnings[0]['message'], msg)
66 def test_barePort(self):
68 A bare port passed to I{--pop3} results in deprecation warning in
69 addition to a TCP4ServerEndpoint.
72 options.parseOptions(['--pop3', '8110'])
73 self.assertEqual(len(options['pop3']), 1)
74 self.assertIsInstance(
75 options['pop3'][0], endpoints.TCP4ServerEndpoint)
76 warnings = self.flushWarnings([options.opt_pop3])
77 self.assertEqual(len(warnings), 1)
78 self.assertEqual(warnings[0]['category'], DeprecationWarning)
80 warnings[0]['message'],
81 "Specifying plain ports and/or a certificate is deprecated since "
82 "Twisted 11.0; use endpoint descriptions instead.")
85 def _endpointTest(self, service):
87 Use L{Options} to parse a single service configuration parameter and
88 verify that an endpoint of the correct type is added to the list for
92 options.parseOptions(['--' + service, 'tcp:1234'])
93 self.assertEqual(len(options[service]), 1)
94 self.assertIsInstance(
95 options[service][0], endpoints.TCP4ServerEndpoint)
98 def test_endpointSMTP(self):
100 When I{--smtp} is given a TCP endpoint description as an argument, a
101 TCPServerEndpoint is added to the list of SMTP endpoints.
103 self._endpointTest('smtp')
106 def test_endpointPOP3(self):
108 When I{--pop3} is given a TCP endpoint description as an argument, a
109 TCPServerEndpoint is added to the list of POP3 endpoints.
111 self._endpointTest('pop3')
114 def test_protoDefaults(self):
116 POP3 and SMTP each listen on a TCP4ServerEndpoint by default.
119 options.parseOptions([])
121 self.assertEqual(len(options['pop3']), 1)
122 self.assertIsInstance(
123 options['pop3'][0], endpoints.TCP4ServerEndpoint)
125 self.assertEqual(len(options['smtp']), 1)
126 self.assertIsInstance(
127 options['smtp'][0], endpoints.TCP4ServerEndpoint)
130 def test_protoDisable(self):
132 The I{--no-pop3} and I{--no-smtp} options disable POP3 and SMTP
136 options.parseOptions(['--no-pop3'])
137 self.assertEqual(options._getEndpoints(None, 'pop3'), [])
138 self.assertNotEquals(options._getEndpoints(None, 'smtp'), [])
141 options.parseOptions(['--no-smtp'])
142 self.assertNotEquals(options._getEndpoints(None, 'pop3'), [])
143 self.assertEqual(options._getEndpoints(None, 'smtp'), [])
146 def test_allProtosDisabledError(self):
148 If all protocols are disabled, L{UsageError} is raised.
152 UsageError, options.parseOptions, (['--no-pop3', '--no-smtp']))
155 def test_pop3sBackwardCompatibility(self):
157 The deprecated I{--pop3s} and I{--certificate} options set up a POP3 SSL
160 cert = FilePath(self.mktemp())
163 options.parseOptions(['--pop3s', '8995',
164 '--certificate', cert.path])
165 self.assertEqual(len(options['pop3']), 2)
166 self.assertIsInstance(
167 options['pop3'][0], endpoints.SSL4ServerEndpoint)
168 self.assertIsInstance(
169 options['pop3'][1], endpoints.TCP4ServerEndpoint)
171 warnings = self.flushWarnings([options.postOptions])
172 self.assertEqual(len(warnings), 1)
173 self.assertEqual(warnings[0]['category'], DeprecationWarning)
175 warnings[0]['message'],
176 "Specifying plain ports and/or a certificate is deprecated since "
177 "Twisted 11.0; use endpoint descriptions instead.")
180 def test_esmtpWithoutHostname(self):
182 If I{--esmtp} is given without I{--hostname}, L{Options.parseOptions}
183 raises L{UsageError}.
186 exc = self.assertRaises(UsageError, options.parseOptions, ['--esmtp'])
187 self.assertEqual("--esmtp requires --hostname", str(exc))
192 Tests that the --auth option registers a checker.
195 options.parseOptions(['--auth', 'memory:admin:admin:bob:password'])
196 self.assertEqual(len(options['credCheckers']), 1)
197 checker = options['credCheckers'][0]
198 interfaces = checker.credentialInterfaces
199 registered_checkers = options.service.smtpPortal.checkers
200 for iface in interfaces:
201 self.assertEqual(checker, registered_checkers[iface])
205 class SpyEndpoint(object):
207 SpyEndpoint remembers what factory it is told to listen with.
210 def listen(self, factory):
211 self.listeningWith = factory
212 return defer.succeed(None)
216 class MakeServiceTests(TestCase):
218 Tests for L{twisted.mail.tap.makeService}
220 def _endpointServerTest(self, key, factoryClass):
222 Configure a service with two endpoints for the protocol associated with
223 C{key} and verify that when the service is started a factory of type
224 C{factoryClass} is used to listen on each of them.
226 cleartext = SpyEndpoint()
227 secure = SpyEndpoint()
229 config[key] = [cleartext, secure]
230 service = makeService(config)
231 service.privilegedStartService()
232 service.startService()
233 self.addCleanup(service.stopService)
234 self.assertIsInstance(cleartext.listeningWith, factoryClass)
235 self.assertIsInstance(secure.listeningWith, factoryClass)
240 If one or more endpoints is included in the configuration passed to
241 L{makeService} for the C{"pop3"} key, a service for starting a POP3
242 server is constructed for each of them and attached to the returned
245 self._endpointServerTest("pop3", protocols.POP3Factory)
250 If one or more endpoints is included in the configuration passed to
251 L{makeService} for the C{"smtp"} key, a service for starting an SMTP
252 server is constructed for each of them and attached to the returned
255 self._endpointServerTest("smtp", protocols.SMTPFactory)