|
1 | | -from django.core.mail import get_connection |
| 1 | +from datetime import datetime |
| 2 | + |
| 3 | +from django.core.exceptions import ImproperlyConfigured |
| 4 | +from django.core.mail import get_connection, send_mail |
2 | 5 | from django.test import SimpleTestCase |
3 | 6 | from django.test.utils import override_settings |
| 7 | +from django.utils.timezone import utc |
| 8 | + |
| 9 | +from anymail.exceptions import AnymailConfigurationError, AnymailUnsupportedFeature |
| 10 | +from anymail.message import AnymailMessage |
4 | 11 |
|
5 | 12 | from .utils import AnymailTestMixin |
6 | 13 |
|
7 | 14 |
|
8 | | -class BackendSettingsTests(SimpleTestCase, AnymailTestMixin): |
| 15 | +recorded_send_params = [] |
| 16 | + |
| 17 | + |
| 18 | +@override_settings(EMAIL_BACKEND='anymail.backends.test.TestBackend', |
| 19 | + ANYMAIL_TEST_SAMPLE_SETTING='sample', # required TestBackend setting |
| 20 | + ANYMAIL_TEST_RECORDED_SEND_PARAMS=recorded_send_params) |
| 21 | +class TestBackendTestCase(SimpleTestCase, AnymailTestMixin): |
| 22 | + """Base TestCase using Anymail's TestBackend""" |
| 23 | + |
| 24 | + def setUp(self): |
| 25 | + super(TestBackendTestCase, self).setUp() |
| 26 | + del recorded_send_params[:] # empty the list from previous tests |
| 27 | + # Simple message useful for many tests |
| 28 | + self. message = AnymailMessage( 'Subject', 'Text Body', '[email protected]', [ '[email protected]']) |
| 29 | + |
| 30 | + @staticmethod |
| 31 | + def get_send_params(): |
| 32 | + return recorded_send_params[-1] |
| 33 | + |
| 34 | + |
| 35 | +@override_settings(EMAIL_BACKEND='anymail.backends.test.TestBackend') # but no ANYMAIL settings overrides |
| 36 | +class BackendSettingsTests(SimpleTestCase, AnymailTestMixin): # (so not TestBackendTestCase) |
9 | 37 | """Test settings initializations for Anymail EmailBackends""" |
10 | 38 |
|
11 | | - # We should add a "GenericBackend" or something basic for testing. |
12 | | - # For now, we just access real backends directly. |
| 39 | + @override_settings(ANYMAIL={'TEST_SAMPLE_SETTING': 'setting_from_anymail_settings'}) |
| 40 | + def test_anymail_setting(self): |
| 41 | + """ESP settings usually come from ANYMAIL settings dict""" |
| 42 | + backend = get_connection() |
| 43 | + self.assertEqual(backend.sample_setting, 'setting_from_anymail_settings') |
| 44 | + |
| 45 | + @override_settings(TEST_SAMPLE_SETTING='setting_from_bare_settings') |
| 46 | + def test_bare_setting(self): |
| 47 | + """ESP settings are also usually allowed at root of settings file""" |
| 48 | + backend = get_connection() |
| 49 | + self.assertEqual(backend.sample_setting, 'setting_from_bare_settings') |
13 | 50 |
|
14 | | - @override_settings(ANYMAIL={'MAILGUN_API_KEY': 'api_key_from_settings'}) |
| 51 | + @override_settings(ANYMAIL={'TEST_SAMPLE_SETTING': 'setting_from_settings'}) |
15 | 52 | def test_connection_kwargs_overrides_settings(self): |
16 | | - connection = get_connection('anymail.backends.mailgun.MailgunBackend') |
17 | | - self.assertEqual(connection.api_key, 'api_key_from_settings') |
| 53 | + """Can override settings file in get_connection""" |
| 54 | + backend = get_connection() |
| 55 | + self.assertEqual(backend.sample_setting, 'setting_from_settings') |
18 | 56 |
|
19 | | - connection = get_connection('anymail.backends.mailgun.MailgunBackend', |
20 | | - api_key='api_key_from_kwargs') |
21 | | - self.assertEqual(connection.api_key, 'api_key_from_kwargs') |
| 57 | + backend = get_connection(sample_setting='setting_from_kwargs') |
| 58 | + self.assertEqual(backend.sample_setting, 'setting_from_kwargs') |
| 59 | + |
| 60 | + def test_missing_setting(self): |
| 61 | + """Settings without defaults must be provided""" |
| 62 | + with self.assertRaises(AnymailConfigurationError) as cm: |
| 63 | + get_connection() |
| 64 | + self.assertIsInstance(cm.exception, ImproperlyConfigured) # Django consistency |
| 65 | + errmsg = str(cm.exception) |
| 66 | + self.assertRegex(errmsg, r'\bTEST_SAMPLE_SETTING\b') |
| 67 | + self.assertRegex(errmsg, r'\bANYMAIL_TEST_SAMPLE_SETTING\b') |
22 | 68 |
|
23 | 69 | @override_settings(ANYMAIL={'SENDGRID_USERNAME': 'username_from_settings', |
24 | 70 | 'SENDGRID_PASSWORD': 'password_from_settings'}) |
25 | 71 | def test_username_password_kwargs_overrides(self): |
26 | | - # Additional checks for username and password, which are special-cased |
27 | | - # because of Django core mail function defaults. |
28 | | - connection = get_connection('anymail.backends.sendgrid.SendGridBackend') |
29 | | - self.assertEqual(connection.username, 'username_from_settings') |
30 | | - self.assertEqual(connection.password, 'password_from_settings') |
31 | | - |
32 | | - connection = get_connection('anymail.backends.sendgrid.SendGridBackend', |
33 | | - username='username_from_kwargs', password='password_from_kwargs') |
34 | | - self.assertEqual(connection.username, 'username_from_kwargs') |
35 | | - self.assertEqual(connection.password, 'password_from_kwargs') |
| 72 | + """Overrides for 'username' and 'password' should work like other overrides""" |
| 73 | + # These are special-cased because of default args in Django core mail functions. |
| 74 | + # (Use the SendGrid backend, which has settings named 'username' and 'password'.) |
| 75 | + backend = get_connection('anymail.backends.sendgrid.SendGridBackend') |
| 76 | + self.assertEqual(backend.username, 'username_from_settings') |
| 77 | + self.assertEqual(backend.password, 'password_from_settings') |
| 78 | + |
| 79 | + backend = get_connection('anymail.backends.sendgrid.SendGridBackend', |
| 80 | + username='username_from_kwargs', password='password_from_kwargs') |
| 81 | + self.assertEqual(backend.username, 'username_from_kwargs') |
| 82 | + self.assertEqual(backend.password, 'password_from_kwargs') |
| 83 | + |
| 84 | + |
| 85 | +class UnsupportedFeatureTests(TestBackendTestCase): |
| 86 | + """Tests mail features not supported by backend are handled properly""" |
| 87 | + |
| 88 | + def test_unsupported_feature(self): |
| 89 | + """Unsupported features raise AnymailUnsupportedFeature""" |
| 90 | + # TestBackend doesn't support non-HTML alternative parts |
| 91 | + self.message.attach_alternative(b'FAKE_MP3_DATA', 'audio/mpeg') |
| 92 | + with self.assertRaises(AnymailUnsupportedFeature): |
| 93 | + self.message.send() |
| 94 | + |
| 95 | + @override_settings(ANYMAIL={ |
| 96 | + 'IGNORE_UNSUPPORTED_FEATURES': True |
| 97 | + }) |
| 98 | + def test_ignore_unsupported_features(self): |
| 99 | + """Setting prevents exception""" |
| 100 | + self.message.attach_alternative(b'FAKE_MP3_DATA', 'audio/mpeg') |
| 101 | + self.message.send() # should not raise exception |
| 102 | + |
| 103 | + |
| 104 | +class SendDefaultsTests(TestBackendTestCase): |
| 105 | + """Tests backend support for global SEND_DEFAULTS and <ESP>_SEND_DEFAULTS""" |
| 106 | + |
| 107 | + @override_settings(ANYMAIL={ |
| 108 | + 'SEND_DEFAULTS': { |
| 109 | + # This isn't an exhaustive list of Anymail message attrs; just one of each type |
| 110 | + 'metadata': {'global': 'globalvalue'}, |
| 111 | + 'send_at': datetime(2016, 5, 12, 4, 17, 0, tzinfo=utc), |
| 112 | + 'tags': ['globaltag'], |
| 113 | + 'template_id': 'my-template', |
| 114 | + 'track_clicks': True, |
| 115 | + 'esp_extra': {'globalextra': 'globalsetting'}, |
| 116 | + } |
| 117 | + }) |
| 118 | + def test_send_defaults(self): |
| 119 | + """Test that (non-esp-specific) send defaults are applied""" |
| 120 | + self.message.send() |
| 121 | + params = self.get_send_params() |
| 122 | + # All these values came from ANYMAIL_SEND_DEFAULTS: |
| 123 | + self.assertEqual(params['metadata'], {'global': 'globalvalue'}) |
| 124 | + self.assertEqual(params['send_at'], datetime(2016, 5, 12, 4, 17, 0, tzinfo=utc)) |
| 125 | + self.assertEqual(params['tags'], ['globaltag']) |
| 126 | + self.assertEqual(params['template_id'], 'my-template') |
| 127 | + self.assertEqual(params['track_clicks'], True) |
| 128 | + self.assertEqual(params['globalextra'], 'globalsetting') # TestBackend merges esp_extra into params |
| 129 | + |
| 130 | + @override_settings(ANYMAIL={ |
| 131 | + 'TEST_SEND_DEFAULTS': { # "TEST" is the name of the TestBackend's ESP |
| 132 | + 'metadata': {'global': 'espvalue'}, |
| 133 | + 'tags': ['esptag'], |
| 134 | + 'track_opens': False, |
| 135 | + 'esp_extra': {'globalextra': 'espsetting'}, |
| 136 | + } |
| 137 | + }) |
| 138 | + def test_esp_send_defaults(self): |
| 139 | + """Test that esp-specific send defaults are applied""" |
| 140 | + self.message.send() |
| 141 | + params = self.get_send_params() |
| 142 | + self.assertEqual(params['metadata'], {'global': 'espvalue'}) |
| 143 | + self.assertEqual(params['tags'], ['esptag']) |
| 144 | + self.assertEqual(params['track_opens'], False) |
| 145 | + self.assertEqual(params['globalextra'], 'espsetting') # TestBackend merges esp_extra into params |
| 146 | + |
| 147 | + @override_settings(ANYMAIL={ |
| 148 | + 'SEND_DEFAULTS': { |
| 149 | + 'metadata': {'global': 'globalvalue', 'other': 'othervalue'}, |
| 150 | + 'tags': ['globaltag'], |
| 151 | + 'track_clicks': True, |
| 152 | + 'track_opens': False, |
| 153 | + 'esp_extra': {'globalextra': 'globalsetting'}, |
| 154 | + } |
| 155 | + }) |
| 156 | + def test_send_defaults_combine_with_message(self): |
| 157 | + """Individual message settings are *merged into* the global send defaults""" |
| 158 | + self.message.metadata = {'message': 'messagevalue', 'other': 'override'} |
| 159 | + self.message.tags = ['messagetag'] |
| 160 | + self.message.track_clicks = False |
| 161 | + self.message.esp_extra = {'messageextra': 'messagesetting'} |
| 162 | + |
| 163 | + self.message.send() |
| 164 | + params = self.get_send_params() |
| 165 | + self.assertEqual(params['metadata'], { # metadata merged |
| 166 | + 'global': 'globalvalue', # global default preserved |
| 167 | + 'message': 'messagevalue', # message setting added |
| 168 | + 'other': 'override'}) # message setting overrides global default |
| 169 | + self.assertEqual(params['tags'], ['globaltag', 'messagetag']) # tags concatenated |
| 170 | + self.assertEqual(params['track_clicks'], False) # message overrides |
| 171 | + self.assertEqual(params['track_opens'], False) # (no message setting) |
| 172 | + self.assertEqual(params['globalextra'], 'globalsetting') |
| 173 | + self.assertEqual(params['messageextra'], 'messagesetting') |
| 174 | + |
| 175 | + # Send another message to make sure original SEND_DEFAULTS unchanged |
| 176 | + send_mail( 'subject', 'body', '[email protected]', [ '[email protected]']) |
| 177 | + params = self.get_send_params() |
| 178 | + self.assertEqual(params['metadata'], {'global': 'globalvalue', 'other': 'othervalue'}) |
| 179 | + self.assertEqual(params['tags'], ['globaltag']) |
| 180 | + self.assertEqual(params['track_clicks'], True) |
| 181 | + self.assertEqual(params['track_opens'], False) |
| 182 | + self.assertEqual(params['globalextra'], 'globalsetting') |
| 183 | + |
| 184 | + @override_settings(ANYMAIL={ |
| 185 | + 'SEND_DEFAULTS': { |
| 186 | + # This isn't an exhaustive list of Anymail message attrs; just one of each type |
| 187 | + 'metadata': {'global': 'globalvalue'}, |
| 188 | + 'tags': ['globaltag'], |
| 189 | + 'template_id': 'global-template', |
| 190 | + 'esp_extra': {'globalextra': 'globalsetting'}, |
| 191 | + }, |
| 192 | + 'TEST_SEND_DEFAULTS': { # "TEST" is the name of the TestBackend's ESP |
| 193 | + 'merge_global_data': {'esp': 'espmerge'}, |
| 194 | + 'metadata': {'esp': 'espvalue'}, |
| 195 | + 'tags': ['esptag'], |
| 196 | + 'esp_extra': {'espextra': 'espsetting'}, |
| 197 | + } |
| 198 | + }) |
| 199 | + def test_esp_send_defaults_override_globals(self): |
| 200 | + """ESP-specific send defaults override *individual* global defaults""" |
| 201 | + self.message.send() |
| 202 | + params = self.get_send_params() |
| 203 | + self.assertEqual(params['merge_global_data'], {'esp': 'espmerge'}) # esp-defaults only |
| 204 | + self.assertEqual(params['metadata'], {'esp': 'espvalue'}) |
| 205 | + self.assertEqual(params['tags'], ['esptag']) |
| 206 | + self.assertEqual(params['template_id'], 'global-template') # global-defaults only |
| 207 | + self.assertEqual(params['espextra'], 'espsetting') |
| 208 | + self.assertNotIn('globalextra', params) # entire esp_extra is overriden by esp-send-defaults |
0 commit comments