Coverage for tests/utils/test_email.py: 100%

52 statements  

« prev     ^ index     » next       coverage.py v7.10.2, created at 2025-08-08 22:07 +0000

1import unittest 

2from unittest.mock import patch, MagicMock 

3from webapp.utils.emailer import Emailer, SMTPConfig, EmailerError 

4 

5 

6class TestEmailer(unittest.TestCase): 

7 def setUp(self): 

8 self.smtp_config = SMTPConfig( 

9 host="smtp.test.com", 

10 port=587, 

11 username="testuser@canonical.com", 

12 password="testpass", 

13 domain="example.com", 

14 ) 

15 self.emailer = Emailer(self.smtp_config) 

16 

17 @patch("smtplib.SMTP") 

18 def test_send_email_success(self, mock_smtp): 

19 subject = "Test subject" 

20 body = "Test body" 

21 to_email = "recipient@test.com" 

22 

23 mock_server = MagicMock() 

24 mock_smtp.return_value.__enter__.return_value = mock_server 

25 

26 self.emailer.send_email(subject, body, to_email) 

27 

28 mock_smtp.assert_called_once_with( 

29 self.smtp_config.host, self.smtp_config.port 

30 ) 

31 mock_server.starttls.assert_called_once() 

32 mock_server.login.assert_called_with( 

33 self.smtp_config.username, self.smtp_config.password 

34 ) 

35 

36 @patch("smtplib.SMTP") 

37 def test_send_email_template_success(self, mock_smtp): 

38 with patch("webapp.utils.emailer.render_template") as mock_render: 

39 mock_render.return_value = "<h1>Hello</h1>" 

40 mock_server = MagicMock() 

41 mock_smtp.return_value.__enter__.return_value = mock_server 

42 

43 self.emailer.send_email_template( 

44 to_email="recipient@test.com", 

45 subject="Test Template", 

46 template_path="template.html", 

47 context={"name": "Test"}, 

48 ) 

49 

50 mock_render.assert_called_once_with( 

51 "template.html", **{"name": "Test"} 

52 ) 

53 mock_server.send_message.assert_called() 

54 

55 def test_validate_config_missing_fields(self): 

56 incomplete_config = SMTPConfig( 

57 host=None, 

58 port=587, 

59 username=None, 

60 password=None, 

61 domain="example.com", 

62 ) 

63 emailer = Emailer(incomplete_config) 

64 self.assertFalse(emailer.is_configured) 

65 

66 @patch("smtplib.SMTP") 

67 def test_send_raises_smtp_exception(self, mock_smtp): 

68 mock_smtp.side_effect = Exception("SMTP failure") 

69 subject = "Test" 

70 body = "Body" 

71 to_email = "to@example.com" 

72 

73 with self.assertRaises(EmailerError): 

74 self.emailer._send(subject, body, to_email) 

75 

76 def test_create_message_addresses(self): 

77 message = self.emailer._create_message( 

78 subject="Subject", 

79 body="Body", 

80 to_email=["a@test.com", "b@test.com"], 

81 ) 

82 self.assertIn("From", message) 

83 self.assertIn("To", message) 

84 self.assertEqual(message["From"], "testuser@canonical.com") 

85 

86 emailer2 = Emailer( 

87 SMTPConfig( 

88 host="host", 

89 port=587, 

90 username="simpleuser", 

91 password="pass", 

92 domain="example.com", 

93 ) 

94 ) 

95 message2 = emailer2._create_message( 

96 "Sub", "Body", "someone@example.com" 

97 ) 

98 self.assertTrue(message2["From"].startswith("noreply+")) 

99 

100 def test_send_email_no_configuration(self): 

101 no_config = SMTPConfig( 

102 host=None, 

103 port=587, 

104 username=None, 

105 password=None, 

106 domain="example.com", 

107 ) 

108 emailer = Emailer(no_config) 

109 emailer.send_email("subject", "body", "to@example.com") 

110 self.assertFalse(emailer.is_configured)