%PDF- %PDF-
Direktori : /lib/python3/dist-packages/twisted/mail/test/ |
Current File : //lib/python3/dist-packages/twisted/mail/test/test_mailmail.py |
# -*- test-case-name: twisted.mail.test.test_mailmail -*- # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ Tests for L{twisted.mail.scripts.mailmail}, the implementation of the command line program I{mailmail}. """ import os import sys from io import StringIO from unittest import skipIf from twisted.copyright import version from twisted.internet.defer import Deferred from twisted.internet.testing import MemoryReactor from twisted.mail import smtp from twisted.mail.scripts import mailmail from twisted.mail.scripts.mailmail import parseOptions from twisted.python.failure import Failure from twisted.python.runtime import platformType from twisted.trial.unittest import TestCase class OptionsTests(TestCase): """ Tests for L{parseOptions} which parses command line arguments and reads message text from stdin to produce an L{Options} instance which can be used to send a message. """ memoryReactor = MemoryReactor() def setUp(self): """ Override some things in mailmail, so that we capture C{stdout}, and do not call L{reactor.stop}. """ self.out = StringIO() # Override the mailmail logger, so we capture stderr output from twisted.logger import Logger, textFileLogObserver logObserver = textFileLogObserver(self.out) self.patch(mailmail, "_log", Logger(observer=logObserver)) self.host = None self.options = None self.ident = None # Override mailmail.sendmail, so we don't call reactor.stop() def sendmail(host, options, ident): self.host = host self.options = options self.ident = ident return smtp.sendmail( host, options.sender, options.to, options.body, reactor=self.memoryReactor, ) self.patch(mailmail, "sendmail", sendmail) def test_unspecifiedRecipients(self): """ If no recipients are given in the argument list and there is no recipient header in the message text, L{parseOptions} raises L{SystemExit} with a string describing the problem. """ self.patch(sys, "stdin", StringIO("Subject: foo\n" "\n" "Hello, goodbye.\n")) exc = self.assertRaises(SystemExit, parseOptions, []) self.assertEqual(exc.args, ("No recipients specified.",)) def test_listQueueInformation(self): """ The I{-bp} option for listing queue information is unsupported and if it is passed to L{parseOptions}, L{SystemExit} is raised. """ exc = self.assertRaises(SystemExit, parseOptions, ["-bp"]) self.assertEqual(exc.args, ("Unsupported option.",)) def test_stdioTransport(self): """ The I{-bs} option for using stdin and stdout as the SMTP transport is unsupported and if it is passed to L{parseOptions}, L{SystemExit} is raised. """ exc = self.assertRaises(SystemExit, parseOptions, ["-bs"]) self.assertEqual(exc.args, ("Unsupported option.",)) def test_ignoreFullStop(self): """ The I{-i} and I{-oi} options for ignoring C{"."} by itself on a line are unsupported and if either is passed to L{parseOptions}, L{SystemExit} is raised. """ exc = self.assertRaises(SystemExit, parseOptions, ["-i"]) self.assertEqual(exc.args, ("Unsupported option.",)) exc = self.assertRaises(SystemExit, parseOptions, ["-oi"]) self.assertEqual(exc.args, ("Unsupported option.",)) def test_copyAliasedSender(self): """ The I{-om} option for copying the sender if they appear in an alias expansion is unsupported and if it is passed to L{parseOptions}, L{SystemExit} is raised. """ exc = self.assertRaises(SystemExit, parseOptions, ["-om"]) self.assertEqual(exc.args, ("Unsupported option.",)) def test_version(self): """ The I{--version} option displays the version and raises L{SystemExit} with L{None} as the exit code. """ out = StringIO() self.patch(sys, "stdout", out) systemExitCode = self.assertRaises(SystemExit, parseOptions, "--version") # SystemExit.code is None on success self.assertEqual(systemExitCode.code, None) data = out.getvalue() self.assertEqual(data, f"mailmail version: {version}\n") def test_backgroundDelivery(self): """ The I{-odb} flag specifies background delivery. """ stdin = StringIO("\n") self.patch(sys, "stdin", stdin) o = parseOptions("-odb") self.assertTrue(o.background) def test_foregroundDelivery(self): """ The I{-odf} flags specifies foreground delivery. """ stdin = StringIO("\n") self.patch(sys, "stdin", stdin) o = parseOptions("-odf") self.assertFalse(o.background) def test_recipientsFromHeaders(self): """ The I{-t} flags specifies that recipients should be obtained from headers. """ stdin = StringIO( "To: Curly <invaliduser2@example.com>\n" "Cc: Larry <invaliduser1@example.com>\n" "Bcc: Moe <invaliduser3@example.com>\n" "\n" "Oh, a wise guy?\n" ) self.patch(sys, "stdin", stdin) o = parseOptions("-t") self.assertEqual(len(o.to), 3) def test_setFrom(self): """ When a message has no I{From:} header, a I{From:} value can be specified with the I{-F} flag. """ stdin = StringIO("To: invaliduser2@example.com\n" "Subject: A wise guy?\n\n") self.patch(sys, "stdin", stdin) o = parseOptions(["-F", "Larry <invaliduser1@example.com>", "-t"]) self.assertEqual(o.sender, "Larry <invaliduser1@example.com>") def test_overrideFromFlagByFromHeader(self): """ The I{-F} flag specifies the From: value. However, I{-F} flag is overriden by the value of From: in the e-mail header. """ stdin = StringIO( "To: Curly <invaliduser4@example.com>\n" "From: Shemp <invaliduser4@example.com>\n" ) self.patch(sys, "stdin", stdin) o = parseOptions(["-F", "Groucho <invaliduser5@example.com>", "-t"]) self.assertEqual(o.sender, "invaliduser4@example.com") @skipIf( platformType == "win32", "mailmail.run() does not work on win32 due to lack of support for" " getuid()", ) def test_runErrorsToStderr(self): """ Call L{mailmail.run}, and specify I{-oep} to print errors to stderr. The sender, to, and printErrors options should be set and there should be no failure. """ argv = ("test_mailmail.py", "invaliduser2@example.com", "-oep") stdin = StringIO("\n") self.patch(sys, "argv", argv) self.patch(sys, "stdin", stdin) mailmail.run() self.assertEqual(self.options.sender, mailmail.getlogin()) self.assertEqual(self.options.to, ["invaliduser2@example.com"]) # We should have printErrors set because we specified "-oep" self.assertTrue(self.options.printErrors) # We should not have any failures. self.assertIsNone(mailmail.failed) @skipIf( platformType == "win32", "mailmail.run() does not work on win32 due to lack of support for" " getuid()", ) def test_readInvalidConfig(self): """ Error messages for illegal UID value, illegal GID value, and illegal identity entry will be sent to stderr. """ stdin = StringIO("\n") self.patch(sys, "stdin", stdin) filename = self.mktemp() myUid = os.getuid() myGid = os.getgid() with open(filename, "w") as f: # Create a config file with some invalid values f.write( "[useraccess]\n" "allow=invaliduser2,invaliduser1\n" "deny=invaliduser3,invaliduser4,{}\n" "order=allow,deny\n" "[groupaccess]\n" "allow=invalidgid1,invalidgid2\n" "deny=invalidgid1,invalidgid2,{}\n" "order=deny,allow\n" "[identity]\n" "localhost=funny\n" "[addresses]\n" "smarthost=localhost\n" "default_domain=example.com\n".format(myUid, myGid) ) # The mailmail script looks in # the twisted.mail.scripts.GLOBAL_CFG variable # and then the twisted.mail.scripts.LOCAL_CFG # variable for the path to it's config file. # # Override twisted.mail.scripts.LOCAL_CFG with the file we just # created. self.patch(mailmail, "LOCAL_CFG", filename) argv = ("test_mailmail.py", "invaliduser2@example.com", "-oep") self.patch(sys, "argv", argv) mailmail.run() self.assertRegex( self.out.getvalue(), "Illegal UID in \\[useraccess\\] section: " "invaliduser1", ) self.assertRegex( self.out.getvalue(), "Illegal GID in \\[groupaccess\\] section: " "invalidgid1", ) self.assertRegex( self.out.getvalue(), "Illegal entry in \\[identity\\] section: funny" ) def getConfigFromFile(self, config): """ Read a mailmail configuration file. The mailmail script checks the twisted.mail.scripts.mailmail.GLOBAL_CFG variable and then the twisted.mail.scripts.mailmail.LOCAL_CFG variable for the path to its config file. @param config: path to config file @type config: L{str} @return: A parsed config. @rtype: L{twisted.mail.scripts.mailmail.Configuration} """ from twisted.mail.scripts.mailmail import loadConfig filename = self.mktemp() with open(filename, "w") as f: f.write(config) return loadConfig(filename) def test_loadConfig(self): """ L{twisted.mail.scripts.mailmail.loadConfig} parses the config file for mailmail. """ config = self.getConfigFromFile( """ [addresses] smarthost=localhost""" ) self.assertEqual(config.smarthost, "localhost") config = self.getConfigFromFile( """ [addresses] default_domain=example.com""" ) self.assertEqual(config.domain, "example.com") config = self.getConfigFromFile( """ [addresses] smarthost=localhost default_domain=example.com""" ) self.assertEqual(config.smarthost, "localhost") self.assertEqual(config.domain, "example.com") config = self.getConfigFromFile( """ [identity] host1=invalid host2=username:password""" ) self.assertNotIn("host1", config.identities) self.assertEqual(config.identities["host2"], ["username", "password"]) config = self.getConfigFromFile( """ [useraccess] allow=invalid1,35 order=allow""" ) self.assertEqual(config.allowUIDs, [35]) config = self.getConfigFromFile( """ [useraccess] deny=35,36 order=deny""" ) self.assertEqual(config.denyUIDs, [35, 36]) config = self.getConfigFromFile( """ [useraccess] allow=35,36 deny=37,38 order=deny""" ) self.assertEqual(config.allowUIDs, [35, 36]) self.assertEqual(config.denyUIDs, [37, 38]) config = self.getConfigFromFile( """ [groupaccess] allow=gid1,41 order=allow""" ) self.assertEqual(config.allowGIDs, [41]) config = self.getConfigFromFile( """ [groupaccess] deny=41 order=deny""" ) self.assertEqual(config.denyGIDs, [41]) config = self.getConfigFromFile( """ [groupaccess] allow=41,42 deny=43,44 order=allow,deny""" ) self.assertEqual(config.allowGIDs, [41, 42]) self.assertEqual(config.denyGIDs, [43, 44]) def test_senderror(self): """ L{twisted.mail.scripts.mailmail.senderror} sends mail back to the sender if an error occurs while sending mail to the recipient. """ def sendmail(host, sender, recipient, body): self.assertRegex(sender, "postmaster@") self.assertEqual(recipient, ["testsender"]) self.assertRegex(body.getvalue(), "ValueError") return Deferred() self.patch(smtp, "sendmail", sendmail) opts = mailmail.Options() opts.sender = "testsender" fail = Failure(ValueError()) mailmail.senderror(fail, opts)