Example #1
0
 def test_smtp_utf8(self):
     controller = Controller(Sink())
     controller.start()
     self.addCleanup(controller.stop)
     with SMTP(controller.hostname, controller.port) as client:
         code, response = client.ehlo('example.com')
     self.assertEqual(code, 250)
     self.assertIn(b'SMTPUTF8', response.splitlines())
Example #2
0
 def test_unexpected_errors_unhandled(self):
     handler = Sink()
     handler.error = None
     controller = ErrorController(handler)
     controller.start()
     self.addCleanup(controller.stop)
     with ExitStack() as resources:
         # Suppress logging to the console during the tests.  Depending on
         # timing, the exception may or may not be logged.
         resources.enter_context(patch('aiosmtpd.smtp.log.exception'))
         client = resources.enter_context(
             SMTP(controller.hostname, controller.port))
         code, response = client.helo('example.com')
     self.assertEqual(code, 500)
     self.assertEqual(response, b'Error: (ValueError) test')
     # handler.error did not change because the handler does not have a
     # handle_exception() method.
     self.assertIsNone(handler.error)
Example #3
0
 def test_normal_situation(self):
     cont = Controller(Sink())
     try:
         cont.start()
         catchup_delay()
         assert cont.smtpd is not None
         assert cont._thread_exception is None
     finally:
         cont.stop()
Example #4
0
 def test_mail_with_unrequited_smtputf8(self):
     controller = Controller(Sink())
     controller.start()
     self.addCleanup(controller.stop)
     with SMTP(controller.hostname, controller.port) as client:
         client.ehlo('example.com')
         code, response = client.docmd('MAIL FROM: <*****@*****.**>')
         self.assertEqual(code, 250)
         self.assertEqual(response, b'OK')
Example #5
0
 def test_server_attribute(self):
     controller = UTF8Controller(Sink())
     self.assertIsNone(controller.server)
     try:
         controller.start()
         self.assertIsNotNone(controller.server)
     finally:
         controller.stop()
         self.assertIsNone(controller.server)
Example #6
0
 def test_nocertreq_chkhost_warn(self, caplog, ssl_context_server):
     context = ssl_context_server
     context.verify_mode = ssl.CERT_OPTIONAL
     context.check_hostname = True
     _ = Server(Sink(), tls_context=context)
     assert context.verify_mode == ssl.CERT_OPTIONAL
     logmsg = caplog.record_tuples[0][-1]
     assert "tls_context.check_hostname == True" in logmsg
     assert "might cause client connection problems" in logmsg
Example #7
0
 def test_unexpected_errors_unhandled(self):
     handler = Sink()
     handler.error = None
     controller = ErrorController(handler)
     controller.start()
     self.addCleanup(controller.stop)
     with ExitStack() as resources:
         # Suppress logging to the console during the tests.  Depending on
         # timing, the exception may or may not be logged.
         resources.enter_context(patch('aiosmtpd.smtp.log.exception'))
         client = resources.enter_context(
             SMTP(controller.hostname, controller.port))
         code, response = client.helo('example.com')
     self.assertEqual(code, 500)
     self.assertEqual(response, b'Error: (ValueError) test')
     # handler.error did not change because the handler does not have a
     # handle_exception() method.
     self.assertIsNone(handler.error)
async def no_auth(request):
    class PseudoController(Controller):
        def factory(self):
            return AuthSMTP(self.handler)

    controller = PseudoController(Sink(), hostname="127.0.0.1", port="8025")
    request.addfinalizer(controller.stop)
    controller.start()
    return controller
Example #9
0
 def test_testconn_raises(self, mocker: MockFixture):
     mocker.patch("socket.socket.recv",
                  side_effect=RuntimeError("MockError"))
     cont = Controller(Sink(), hostname="")
     try:
         with pytest.raises(RuntimeError, match="MockError"):
             cont.start()
     finally:
         cont.stop()
Example #10
0
 def test_socket_error_dupe(self, plain_controller, client):
     contr2 = Controller(Sink(),
                         hostname=Global.SrvAddr.host,
                         port=Global.SrvAddr.port)
     try:
         with pytest.raises(socket.error):
             contr2.start()
     finally:
         contr2.stop()
Example #11
0
 def test_server_attribute(self):
     controller = Controller(Sink())
     assert controller.server is None
     try:
         controller.start()
         assert controller.server is not None
     finally:
         controller.stop()
     assert controller.server is None
Example #12
0
 def test_custom_greeting(self):
     controller = CustomIdentController(Sink())
     controller.start()
     self.addCleanup(controller.stop)
     with SMTP() as client:
         code, msg = client.connect(controller.hostname, controller.port)
         self.assertEqual(code, 220)
         # The hostname prefix is unpredictable.
         self.assertEqual(msg[-22:], b'Identifying SMTP v2112')
Example #13
0
 def test_help_after_starttls(self):
     controller = TLSController(Sink())
     controller.start()
     self.addCleanup(controller.stop)
     with SMTP(controller.hostname, controller.port) as client:
         # Don't get tricked by smtplib processing of the response.
         code, response = client.docmd('HELP')
         self.assertEqual(code, 250)
         self.assertEqual(response, SUPPORTED_COMMANDS_TLS)
Example #14
0
 def test_esmtp_no_size_limit(self):
     controller = SizedController(Sink(), size=None)
     controller.start()
     self.addCleanup(controller.stop)
     with SMTP(controller.hostname, controller.port) as client:
         code, response = client.ehlo('example.com')
         self.assertEqual(code, 250)
         for line in response.splitlines():
             self.assertNotEqual(line[:4], b'SIZE')
Example #15
0
 def test_default_greeting(self):
     controller = Controller(Sink())
     controller.start()
     self.addCleanup(controller.stop)
     with SMTP() as client:
         code, msg = client.connect(controller.hostname, controller.port)
         self.assertEqual(code, 220)
         # The hostname prefix is unpredictable.
         self.assertEqual(msg[-len(GREETING):], bytes(GREETING, 'utf-8'))
Example #16
0
 def test_mail_with_incompatible_smtputf8(self):
     controller = Controller(Sink())
     controller.start()
     self.addCleanup(controller.stop)
     with SMTP(controller.hostname, controller.port) as client:
         client.ehlo('example.com')
         code, response = client.docmd(
             'MAIL FROM: <*****@*****.**> SMTPUTF8=YES')
         self.assertEqual(code, 501)
         self.assertEqual(response, b'Error: SMTPUTF8 takes no arguments')
Example #17
0
 def test_ready_timeout(self):
     cont = SlowStartController(Sink())
     expectre = ("SMTP server failed to start within allotted time. "
                 "This might happen if the system is too busy. "
                 "Try increasing the `ready_timeout` parameter.")
     try:
         with pytest.raises(TimeoutError, match=expectre):
             cont.start()
     finally:
         cont.stop()
Example #18
0
 def test_socket_error_dupe(self, plain_controller, client):
     contr2 = Controller(Sink(),
                         hostname=Global.SrvAddr.host,
                         port=Global.SrvAddr.port)
     expectedre = r"error while attempting to bind on address"
     try:
         with pytest.raises(socket.error, match=expectedre):
             contr2.start()
     finally:
         contr2.stop()
Example #19
0
 def test_factory_timeout(self):
     cont = SlowFactoryController(Sink())
     expectre = (
         r"SMTP server started, but not responding within allotted time. "
         r"This might happen if the system is too busy. "
         r"Try increasing the `ready_timeout` parameter.")
     try:
         with pytest.raises(TimeoutError, match=expectre):
             cont.start()
     finally:
         cont.stop()
Example #20
0
 def test_unknown_args_direct(self, silence_event_loop_closed):
     unknown = "this_is_an_unknown_kwarg"
     cont = Controller(Sink(), ready_timeout=0.3, **{unknown: True})
     expectedre = r"__init__.. got an unexpected keyword argument '" + unknown + r"'"
     try:
         with pytest.raises(TypeError, match=expectedre):
             cont.start()
         assert cont.smtpd is None
         assert isinstance(cont._thread_exception, TypeError)
     finally:
         cont.stop()
Example #21
0
 def test_rset_hook_deprecation(self):
     controller = DeprecatedHookController(Sink())
     controller.start()
     self.addCleanup(controller.stop)
     with SMTP(controller.hostname, controller.port) as client:
         client.rset()
     self.assertEqual(len(controller.smtpd.warnings), 1)
     self.assertEqual(
         controller.smtpd.warnings[0],
         call('Use handler.handle_RSET() instead of .rset_hook()',
              DeprecationWarning))
Example #22
0
 def test_mail_invalid_body(self):
     controller = Controller(Sink())
     controller.start()
     self.addCleanup(controller.stop)
     with SMTP(controller.hostname, controller.port) as client:
         client.ehlo('example.com')
         code, response = client.docmd(
             'MAIL FROM: <*****@*****.**> BODY 9BIT')
         self.assertEqual(code, 501)
         self.assertEqual(response,
                          b'Error: BODY can only be one of 7BIT, 8BITMIME')
Example #23
0
 def test_help_after_starttls(self):
     controller = TLSController(Sink())
     controller.start()
     self.addCleanup(controller.stop)
     with SMTP(controller.hostname, controller.port) as client:
         # Don't get tricked by smtplib processing of the response.
         code, response = client.docmd('HELP')
         self.assertEqual(code, 250)
         self.assertEqual(
             response, b'Supported commands: DATA EHLO HELO HELP MAIL '
             b'NOOP QUIT RCPT RSET STARTTLS VRFY')
Example #24
0
 def test_serverhostname_arg(self):
     contsink = partial(Controller, Sink())
     controller = contsink()
     assert "hostname" not in controller.SMTP_kwargs
     controller = contsink(server_hostname="testhost1")
     assert controller.SMTP_kwargs["hostname"] == "testhost1"
     kwargs = dict(hostname="testhost2")
     controller = contsink(server_kwargs=kwargs)
     assert controller.SMTP_kwargs["hostname"] == "testhost2"
     controller = contsink(server_hostname="testhost3",
                           server_kwargs=kwargs)
     assert controller.SMTP_kwargs["hostname"] == "testhost3"
Example #25
0
 def test_mail_with_size_too_large(self):
     controller = SizedController(Sink(), 9999)
     controller.start()
     self.addCleanup(controller.stop)
     with SMTP(controller.hostname, controller.port) as client:
         client.ehlo('example.com')
         code, response = client.docmd(
             'MAIL FROM: <*****@*****.**> SIZE=10000')
         self.assertEqual(code, 552)
         self.assertEqual(
             response,
             b'Error: message size exceeds fixed maximum message size')
Example #26
0
 def test_server_creation_ssl(self, safe_socket_dir, ssl_context_server):
     self.sockfile = safe_socket_dir / "smtp"
     cont = UnixSocketController(Sink(),
                                 unix_socket=self.sockfile,
                                 ssl_context=ssl_context_server)
     try:
         cont.start()
         # Allow additional time for SSL to kick in
         time.sleep(0.1)
         self._assert_good_server(ssl_context_server)
     finally:
         cont.stop()
Example #27
0
 def test_unknown_args_inkwargs(self, silence_event_loop_closed: bool):
     unknown = "this_is_an_unknown_kwarg"
     cont = Controller(Sink(),
                       ready_timeout=0.3,
                       server_kwargs={unknown: True})
     expectedre = r"__init__.. got an unexpected keyword argument '" + unknown + r"'"
     try:
         with pytest.raises(TypeError, match=expectedre):
             cont.start()
         assert cont.smtpd is None
     finally:
         cont.stop()
Example #28
0
 def test_server_creation_ssl(self, safe_socket_dir, ssl_context_server):
     sockfile = safe_socket_dir / "smtp"
     cont = UnixSocketController(Sink(),
                                 unix_socket=sockfile,
                                 ssl_context=ssl_context_server)
     try:
         cont.start()
         # Allow additional time for SSL to kick in
         catchup_delay()
         assert_smtp_socket(cont)
     finally:
         cont.stop()
Example #29
0
 def test_too_long_message_body(self):
     controller = SizedController(Sink(), size=100)
     controller.start()
     self.addCleanup(controller.stop)
     with SMTP(controller.hostname, controller.port) as client:
         client.helo('example.com')
         mail = '\r\n'.join(['z' * 20] * 10)
         with self.assertRaises(SMTPResponseException) as cm:
             client.sendmail('*****@*****.**', ['*****@*****.**'], mail)
         self.assertEqual(cm.exception.smtp_code, 552)
         self.assertEqual(cm.exception.smtp_error,
                          b'Error: Too much mail data')
Example #30
0
 def test_factory_none(self, mocker: MockFixture,
                       silence_event_loop_closed):
     # Hypothetical situation where factory() did not raise an Exception
     # but returned None instead
     mocker.patch("aiosmtpd.controller.SMTP", return_value=None)
     cont = Controller(Sink(), ready_timeout=0.3)
     expectedre = r"factory\(\) returned None"
     try:
         with pytest.raises(RuntimeError, match=expectedre):
             cont.start()
         assert cont.smtpd is None
     finally:
         cont.stop()
Example #31
0
 def test_inet_contstop(self, temp_event_loop, runner):
     """
     Verify behavior when the controller is stopped before loop is stopped
     """
     cont = UnthreadedController(Sink(), loop=temp_event_loop)
     cont.begin()
     # Make sure event loop is not running (will be started in thread)
     assert temp_event_loop.is_running() is False
     runner(temp_event_loop)
     # Make sure event loop is up and running
     assert temp_event_loop.is_running() is True
     try:
         # Check that we can connect
         with SMTPClient(cont.hostname, cont.port,
                         timeout=AUTOSTOP_DELAY) as client:
             code, _ = client.helo("example.org")
             assert code == 250
             client.quit()
         catchup_delay()
         temp_event_loop.call_soon_threadsafe(cont.end)
         for _ in range(10):  # 10 is arbitrary
             catchup_delay(
             )  # effectively yield to other threads/event loop
             if cont.ended.wait(1.0):
                 break
         assert temp_event_loop.is_running() is True
         # Because we've called .end() there, the server listener should've gone
         # away, so we should end up with a socket.timeout or ConnectionError or
         # SMTPServerDisconnected (depending on lotsa factors)
         expect_errs = (socket.timeout, ConnectionError,
                        SMTPServerDisconnected)
         # noinspection PyTypeChecker
         with pytest.raises(expect_errs):
             SMTPClient(cont.hostname, cont.port, timeout=0.1)
     finally:
         # Wrap up, or else we'll hang
         temp_event_loop.call_soon_threadsafe(cont.cancel_tasks)
         catchup_delay()
         runner.join()
     assert runner.is_alive() is False
     assert temp_event_loop.is_running() is False
     assert temp_event_loop.is_closed() is False
Example #32
0
 def test_sink_cli_no_args(self):
     handler = Sink.from_cli(self.parser)
     self.assertIsNone(self.parser.message)
     self.assertIsInstance(handler, Sink)