Skip to content

Commit 34af81a

Browse files
committed
Tests: Simplify Django version compatibility
* Restructure runtests.py as suggested in https://docs.djangoproject.com/en/1.9/topics/testing/advanced/#using-the-django-test-runner-to-test-reusable-applications * Load version-specific Django settings modules (rather than trying to make a single settings.configure() work with all supported versions). * Use `django-admin startproject` defaults for all settings modules. (Tests compatibility with typical apps, middleware, and other settings.) * Set up tests-specific url config; switch to literal urls in test cases. (Eliminates url `reverse` from tests.) * Make runtests.py executable Closes #18
1 parent 296f6ca commit 34af81a

File tree

10 files changed

+437
-108
lines changed

10 files changed

+437
-108
lines changed

runtests.py

100644100755
Lines changed: 24 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,33 @@
1+
#!/usr/bin/env python
2+
13
# python setup.py test
24
# or
3-
# python runtests.py [anymail.tests.test_x anymail.tests.test_y.SomeTestCase ...]
5+
# runtests.py [tests.test_x tests.test_y.SomeTestCase ...]
46

57
import sys
6-
import warnings
78

8-
from django import setup
9+
import django
10+
import os
11+
import warnings
912
from django.conf import settings
10-
from django.test.runner import DiscoverRunner as TestRunner
11-
12-
warnings.simplefilter('default') # show DeprecationWarning and other default-ignored warnings
13-
14-
APP = 'anymail'
15-
16-
settings.configure(
17-
DEBUG=True,
18-
DATABASES={
19-
'default': {
20-
'ENGINE': 'django.db.backends.sqlite3',
21-
}
22-
},
23-
ROOT_URLCONF=APP+'.urls',
24-
INSTALLED_APPS=(
25-
'django.contrib.auth',
26-
'django.contrib.contenttypes',
27-
'django.contrib.sessions',
28-
'django.contrib.admin',
29-
APP,
30-
),
31-
MIDDLEWARE_CLASSES=(
32-
'django.middleware.common.CommonMiddleware',
33-
'django.contrib.sessions.middleware.SessionMiddleware',
34-
'django.middleware.csrf.CsrfViewMiddleware',
35-
'django.contrib.auth.middleware.AuthenticationMiddleware',
36-
),
37-
TEMPLATES=[
38-
# Anymail doesn't have any templates, but tests need a TEMPLATES
39-
# setting to avoid warnings from the Django 1.8+ test client.
40-
{
41-
'BACKEND': 'django.template.backends.django.DjangoTemplates',
42-
},
43-
],
44-
)
45-
46-
# Initialize Django app registry
47-
setup()
48-
49-
50-
def runtests(*args):
13+
from django.test.utils import get_runner
14+
15+
16+
def runtests(test_labels=None):
17+
"""Discover and run project tests. Returns number of failures."""
18+
test_labels = test_labels or ['tests']
19+
20+
# noinspection PyStringFormat
21+
os.environ['DJANGO_SETTINGS_MODULE'] = \
22+
'tests.test_settings.settings_%d_%d' % django.VERSION[:2]
23+
django.setup()
24+
25+
TestRunner = get_runner(settings)
5126
test_runner = TestRunner(verbosity=1)
52-
test_labels = args if len(args) > 0 else ['tests']
53-
failures = test_runner.run_tests(test_labels)
54-
sys.exit(failures)
27+
return test_runner.run_tests(test_labels)
28+
5529

5630
if __name__ == '__main__':
57-
runtests(*sys.argv[1:])
31+
warnings.simplefilter('default') # show DeprecationWarning and other default-ignored warnings
32+
failures = runtests(test_labels=sys.argv[1:])
33+
sys.exit(bool(failures))

tests/test_mailgun_webhooks.py

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import hashlib
55
import hmac
66
from django.core.exceptions import ImproperlyConfigured
7-
from django.core.urlresolvers import reverse
87
from django.test import override_settings
98
from django.utils.timezone import utc
109
from mock import ANY
@@ -42,35 +41,34 @@ def querydict_to_postdict(qd):
4241

4342
class MailgunWebhookSettingsTestCase(WebhookTestCase):
4443
def test_requires_api_key(self):
45-
webhook = reverse('mailgun_tracking_webhook')
4644
with self.assertRaises(ImproperlyConfigured):
47-
self.client.post(webhook, data=mailgun_sign({'event': 'delivered'}))
45+
self.client.post('/anymail/mailgun/tracking/',
46+
data=mailgun_sign({'event': 'delivered'}))
4847

4948

5049
@override_settings(ANYMAIL_MAILGUN_API_KEY=TEST_API_KEY)
5150
class MailgunWebhookSecurityTestCase(WebhookTestCase, WebhookBasicAuthTestsMixin):
5251
should_warn_if_no_auth = False # because we check webhook signature
5352

5453
def call_webhook(self):
55-
webhook = reverse('mailgun_tracking_webhook')
56-
return self.client.post(webhook, data=mailgun_sign({'event': 'delivered'}))
54+
return self.client.post('/anymail/mailgun/tracking/',
55+
data=mailgun_sign({'event': 'delivered'}))
5756

5857
# Additional tests are in WebhookBasicAuthTestsMixin
5958

6059
def test_verifies_correct_signature(self):
61-
webhook = reverse('mailgun_tracking_webhook')
62-
response = self.client.post(webhook, data=mailgun_sign({'event': 'delivered'}))
60+
response = self.client.post('/anymail/mailgun/tracking/',
61+
data=mailgun_sign({'event': 'delivered'}))
6362
self.assertEqual(response.status_code, 200)
6463

6564
def test_verifies_missing_signature(self):
66-
webhook = reverse('mailgun_tracking_webhook')
67-
response = self.client.post(webhook, data={'event': 'delivered'})
65+
response = self.client.post('/anymail/mailgun/tracking/',
66+
data={'event': 'delivered'})
6867
self.assertEqual(response.status_code, 400)
6968

7069
def test_verifies_bad_signature(self):
71-
webhook = reverse('mailgun_tracking_webhook')
7270
data = mailgun_sign({'event': 'delivered'}, api_key="wrong API key")
73-
response = self.client.post(webhook, data=data)
71+
response = self.client.post('/anymail/mailgun/tracking/', data=data)
7472
self.assertEqual(response.status_code, 400)
7573

7674

@@ -99,8 +97,7 @@ def test_delivered_event(self):
9997
'recipient': '[email protected]',
10098
'event': 'delivered',
10199
})
102-
webhook = reverse('mailgun_tracking_webhook')
103-
response = self.client.post(webhook, data=raw_event)
100+
response = self.client.post('/anymail/mailgun/tracking/', data=raw_event)
104101
self.assertEqual(response.status_code, 200)
105102
kwargs = self.assert_handler_called_once_with(self.tracking_handler, sender=MailgunTrackingWebhookView,
106103
event=ANY, esp_name='Mailgun')
@@ -137,8 +134,7 @@ def test_dropped_bounce(self):
137134
'X-Mailgun-Sid': 'WyI3Y2VjMyIsICJib3VuY2VAZXhhbXBsZS5jb20iLCAiZjFjNzgyIl0=',
138135
'token': 'a3fe1fa1640349ac552b84ddde373014b4c41645830c8dd3fc',
139136
})
140-
webhook = reverse('mailgun_tracking_webhook')
141-
response = self.client.post(webhook, data=raw_event)
137+
response = self.client.post('/anymail/mailgun/tracking/', data=raw_event)
142138
self.assertEqual(response.status_code, 200)
143139
kwargs = self.assert_handler_called_once_with(self.tracking_handler, sender=MailgunTrackingWebhookView,
144140
event=ANY, esp_name='Mailgun')
@@ -162,8 +158,7 @@ def test_dropped_spam(self):
162158
'recipient': '[email protected]',
163159
# (omitting some fields that aren't relevant to the test)
164160
})
165-
webhook = reverse('mailgun_tracking_webhook')
166-
response = self.client.post(webhook, data=raw_event)
161+
response = self.client.post('/anymail/mailgun/tracking/', data=raw_event)
167162
self.assertEqual(response.status_code, 200)
168163
kwargs = self.assert_handler_called_once_with(self.tracking_handler, sender=MailgunTrackingWebhookView,
169164
event=ANY, esp_name='Mailgun')
@@ -181,8 +176,7 @@ def test_dropped_timed_out(self):
181176
'recipient': '[email protected]',
182177
# (omitting some fields that aren't relevant to the test)
183178
})
184-
webhook = reverse('mailgun_tracking_webhook')
185-
response = self.client.post(webhook, data=raw_event)
179+
response = self.client.post('/anymail/mailgun/tracking/', data=raw_event)
186180
self.assertEqual(response.status_code, 200)
187181
kwargs = self.assert_handler_called_once_with(self.tracking_handler, sender=MailgunTrackingWebhookView,
188182
event=ANY, esp_name='Mailgun')
@@ -201,8 +195,7 @@ def test_invalid_mailbox(self):
201195
'recipient': '[email protected]',
202196
# (omitting some fields that aren't relevant to the test)
203197
})
204-
webhook = reverse('mailgun_tracking_webhook')
205-
response = self.client.post(webhook, data=raw_event)
198+
response = self.client.post('/anymail/mailgun/tracking/', data=raw_event)
206199
self.assertEqual(response.status_code, 200)
207200
kwargs = self.assert_handler_called_once_with(self.tracking_handler, sender=MailgunTrackingWebhookView,
208201
event=ANY, esp_name='Mailgun')
@@ -221,7 +214,7 @@ def test_metadata(self):
221214
'custom1': 'value',
222215
'custom2': '{"key":"value"}', # you can store JSON, but you'll need to unpack it yourself
223216
})
224-
self.client.post(reverse('mailgun_tracking_webhook'), data=raw_event)
217+
self.client.post('/anymail/mailgun/tracking/', data=raw_event)
225218
kwargs = self.assert_handler_called_once_with(self.tracking_handler)
226219
event = kwargs['event']
227220
self.assertEqual(event.metadata, {"custom1": "value1", "custom2": '{"key":"value"}'})
@@ -232,7 +225,7 @@ def test_tags(self):
232225
'tag': ['tag1', 'tag2'], # Django TestClient encodes list as multiple field values
233226
'event': 'opened',
234227
})
235-
self.client.post(reverse('mailgun_tracking_webhook'), data=raw_event)
228+
self.client.post('/anymail/mailgun/tracking/', data=raw_event)
236229
kwargs = self.assert_handler_called_once_with(self.tracking_handler)
237230
event = kwargs['event']
238231
self.assertEqual(event.tags, ["tag1", "tag2"])
@@ -243,8 +236,7 @@ def test_x_tags(self):
243236
'X-Mailgun-Tag': ['tag1', 'tag2'],
244237
'event': 'delivered',
245238
})
246-
self.client.post(reverse('mailgun_tracking_webhook'), data=raw_event)
247-
kwargs = self.assert_handler_called_once_with(self.tracking_handler)
239+
self.client.post('/anymail/mailgun/tracking/', data=raw_event)
248240
kwargs = self.assert_handler_called_once_with(self.tracking_handler)
249241
event = kwargs['event']
250242
self.assertEqual(event.tags, ["tag1", "tag2"])

tests/test_mandrill_webhooks.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import hmac
88
from base64 import b64encode
99
from django.core.exceptions import ImproperlyConfigured
10-
from django.core.urlresolvers import reverse
1110
from django.test import override_settings
1211
from django.utils.timezone import utc
1312
from mock import ANY
@@ -20,14 +19,14 @@
2019
TEST_WEBHOOK_KEY = 'TEST_WEBHOOK_KEY'
2120

2221

23-
def mandrill_args(events=None, urlname='mandrill_tracking_webhook', key=TEST_WEBHOOK_KEY):
22+
def mandrill_args(events=None, url='/anymail/mandrill/tracking/', key=TEST_WEBHOOK_KEY):
2423
"""Returns TestClient.post kwargs for Mandrill webhook call with events
2524
2625
Computes correct signature.
2726
"""
2827
if events is None:
2928
events = []
30-
url = urljoin('http://testserver/', reverse(urlname))
29+
url = urljoin('http://testserver/', url)
3130
mandrill_events = json.dumps(events)
3231
signed_data = url + 'mandrill_events' + mandrill_events
3332
signature = b64encode(hmac.new(key=key.encode('ascii'),
@@ -42,9 +41,9 @@ def mandrill_args(events=None, urlname='mandrill_tracking_webhook', key=TEST_WEB
4241

4342
class MandrillWebhookSettingsTestCase(WebhookTestCase):
4443
def test_requires_webhook_key(self):
45-
webhook = reverse('mandrill_tracking_webhook')
4644
with self.assertRaises(ImproperlyConfigured):
47-
self.client.post(webhook, data={'mandrill_events': '[]'})
45+
self.client.post('/anymail/mandrill/tracking/',
46+
data={'mandrill_events': '[]'})
4847

4948

5049
@override_settings(ANYMAIL_MANDRILL_WEBHOOK_KEY=TEST_WEBHOOK_KEY)
@@ -63,8 +62,8 @@ def test_verifies_correct_signature(self):
6362
self.assertEqual(response.status_code, 200)
6463

6564
def test_verifies_missing_signature(self):
66-
webhook = reverse('mandrill_tracking_webhook')
67-
response = self.client.post(webhook, data={'mandrill_events': '[{"event":"send"}]'})
65+
response = self.client.post('/anymail/mandrill/tracking/',
66+
data={'mandrill_events': '[{"event":"send"}]'})
6867
self.assertEqual(response.status_code, 400)
6968

7069
def test_verifies_bad_signature(self):
@@ -78,8 +77,7 @@ class MandrillTrackingTestCase(WebhookTestCase):
7877

7978
def test_head_request(self):
8079
# Mandrill verifies webhooks at config time with a HEAD request
81-
webhook = reverse('mandrill_tracking_webhook')
82-
response = self.client.head(webhook)
80+
response = self.client.head('/anymail/mandrill/tracking/')
8381
self.assertEqual(response.status_code, 200)
8482

8583
def test_post_request_invalid_json(self):

tests/test_postmark_webhooks.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import json
22
from datetime import datetime
33

4-
from django.core.urlresolvers import reverse
54
from django.utils.timezone import get_fixed_timezone
65
from mock import ANY
76

@@ -12,8 +11,8 @@
1211

1312
class PostmarkWebhookSecurityTestCase(WebhookTestCase, WebhookBasicAuthTestsMixin):
1413
def call_webhook(self):
15-
webhook = reverse('postmark_tracking_webhook')
16-
return self.client.post(webhook, content_type='application/json', data=json.dumps({}))
14+
return self.client.post('/anymail/postmark/tracking/',
15+
content_type='application/json', data=json.dumps({}))
1716

1817
# Actual tests are in WebhookBasicAuthTestsMixin
1918

@@ -36,8 +35,8 @@ def test_bounce_event(self):
3635
"Subject": "Postmark event test",
3736
"Content": "..."
3837
}
39-
webhook = reverse('postmark_tracking_webhook')
40-
response = self.client.post(webhook, content_type='application/json', data=json.dumps(raw_event))
38+
response = self.client.post('/anymail/postmark/tracking/',
39+
content_type='application/json', data=json.dumps(raw_event))
4140
self.assertEqual(response.status_code, 200)
4241
kwargs = self.assert_handler_called_once_with(self.tracking_handler, sender=PostmarkTrackingWebhookView,
4342
event=ANY, esp_name='Postmark')
@@ -69,8 +68,8 @@ def test_open_event(self):
6968
"ReceivedAt": "2016-04-27T16:21:41.2493688-04:00",
7069
"Recipient": "[email protected]"
7170
}
72-
webhook = reverse('postmark_tracking_webhook')
73-
response = self.client.post(webhook, content_type='application/json', data=json.dumps(raw_event))
71+
response = self.client.post('/anymail/postmark/tracking/',
72+
content_type='application/json', data=json.dumps(raw_event))
7473
self.assertEqual(response.status_code, 200)
7574
kwargs = self.assert_handler_called_once_with(self.tracking_handler, sender=PostmarkTrackingWebhookView,
7675
event=ANY, esp_name='Postmark')

0 commit comments

Comments
 (0)