Move CI testing to GitHub Actions

Related changes:
* remove Travis-CI config; stop running tests on Travis
* rename live integration test environment variables
  to all start with `ANYMAIL_TEST_` (simplifies tox config)
This commit is contained in:
Mike Edmunds
2020-11-28 18:08:01 -08:00
committed by GitHub
parent 8c1749c6f3
commit 5cbaa24002
16 changed files with 181 additions and 152 deletions

102
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,102 @@
name: test
on:
push:
schedule:
# Weekly build (on branch main) every Thursday at 12:00 UTC.
# (Used to monitor compatibility with ESP APIs and other dependencies.)
- cron: '0 12 * * 4'
jobs:
test:
name: ${{ matrix.config.tox }} ${{ matrix.config.options }}
runs-on: ubuntu-18.04
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
config:
- { tox: "lint,docs", python: 3.8 }
# Anymail supports the same Python versions as Django, plus PyPy.
# https://docs.djangoproject.com/en/dev/faq/install/#what-python-version-can-i-use-with-django
# Live API integration tests are only run on a few, representative Python/Django version
# combinations, to avoid rapidly consuming the testing accounts' entire send allotments.
# Django 2.0: Python 3.5+
- { tox: django20-py35-all, python: 3.5 }
- { tox: django20-py36-all, python: 3.6 }
- { tox: django20-pypy3-all, python: pypy3 }
# Django 2.1: Python 3.5, 3.6, or 3.7
- { tox: django21-py35-all, python: 3.5 }
- { tox: django21-py36-all, python: 3.6 }
- { tox: django21-py37-all, python: 3.7 }
- { tox: django21-pypy3-all, python: pypy3 }
# Django 2.2: Python 3.5, 3.6, or 3.7
- { tox: django22-py35-all, python: 3.5 }
- { tox: django22-py36-all, python: 3.6 }
- { tox: django22-py37-all, python: 3.7 }
- { tox: django22-pypy3-all, python: pypy3 }
# Django 3.0: Python 3.6, 3.7, or 3.8
- { tox: django30-py36-all, python: 3.6 }
- { tox: django30-py37-all, python: 3.7 }
- { tox: django30-py38-all, python: 3.8 }
- { tox: django30-pypy3-all, python: pypy3 }
# Django 3.1: Python 3.6, 3.7, or 3.8
- { tox: django31-py36-all, python: 3.6 }
- { tox: django31-py37-all, python: 3.7 }
- { tox: django31-py38-all, python: 3.8, options: run-live-tests }
- { tox: django31-pypy3-all, python: pypy3 }
# Django current development (direct from GitHub source)
- { tox: djangoDev-py37-all, python: 3.7, options: allow-failures }
# Install without optional extras (don't need to cover entire matrix)
- { tox: django31-py37-none, python: 3.7 }
- { tox: django31-py37-amazon_ses, python: 3.7 }
# Test some specific older package versions
- { tox: django22-py37-all-old_urllib3, python: 3.7 }
steps:
- name: Get code
uses: actions/checkout@v2
- name: Setup Python ${{ matrix.config.python }}
# Ensure matrix Python version is installed and available for tox
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.config.python }}
- name: Setup default Python
# Change default Python version back to something consistent
# for installing/running tox
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Install tox
run: |
set -x
python --version
pip install tox
tox --version
- name: Test ${{ matrix.config.tox }}
run: |
tox --version
tox -e ${{ matrix.config.tox }}
continue-on-error: ${{ contains( matrix.config.options, 'allow-failures' ) }}
env:
CONTINUOUS_INTEGRATION: true
TOX_FORCE_IGNORE_OUTCOME: false
ANYMAIL_RUN_LIVE_TESTS: ${{ contains( matrix.config.options, 'run-live-tests' ) }}
ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID: ${{ secrets.ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID }}
ANYMAIL_TEST_AMAZON_SES_REGION_NAME: ${{ secrets.ANYMAIL_TEST_AMAZON_SES_REGION_NAME }}
ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY: ${{ secrets.ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY }}
ANYMAIL_TEST_MAILGUN_API_KEY: ${{ secrets.ANYMAIL_TEST_MAILGUN_API_KEY }}
ANYMAIL_TEST_MAILGUN_DOMAIN: ${{ secrets.ANYMAIL_TEST_MAILGUN_DOMAIN }}
ANYMAIL_TEST_MAILJET_API_KEY: ${{ secrets.ANYMAIL_TEST_MAILJET_API_KEY }}
ANYMAIL_TEST_MAILJET_SECRET_KEY: ${{ secrets.ANYMAIL_TEST_MAILJET_SECRET_KEY }}
ANYMAIL_TEST_MANDRILL_API_KEY: ${{ secrets.ANYMAIL_TEST_MANDRILL_API_KEY }}
ANYMAIL_TEST_POSTMARK_SERVER_TOKEN: ${{ secrets.ANYMAIL_TEST_POSTMARK_SERVER_TOKEN }}
ANYMAIL_TEST_POSTMARK_TEMPLATE_ID: ${{ secrets.ANYMAIL_TEST_POSTMARK_TEMPLATE_ID }}
ANYMAIL_TEST_SENDGRID_API_KEY: ${{ secrets.ANYMAIL_TEST_SENDGRID_API_KEY }}
ANYMAIL_TEST_SENDGRID_TEMPLATE_ID: ${{ secrets.ANYMAIL_TEST_SENDGRID_TEMPLATE_ID }}
ANYMAIL_TEST_SENDINBLUE_API_KEY: ${{ secrets.ANYMAIL_TEST_SENDINBLUE_API_KEY }}
ANYMAIL_TEST_SPARKPOST_API_KEY: ${{ secrets.ANYMAIL_TEST_SPARKPOST_API_KEY }}

View File

@@ -1,71 +0,0 @@
language: python
os: linux
dist: xenial
branches:
# Only run builds on release branches.
# (Builds will *also* still run on pull requests;
# this avoids duplicate builds on the PR *branches*, too.)
only:
- main
- /^v\d+\.\d+(\.(\d|x)+)?(-\S*)?$/
env:
global:
# Let Travis report failures that tox.ini would normally ignore:
- TOX_FORCE_IGNORE_OUTCOME=false
jobs:
include:
- python: 3.8
env: TOXENV="lint,docs"
# Anymail supports the same Python versions as Django, plus PyPy.
# https://docs.djangoproject.com/en/dev/faq/install/#what-python-version-can-i-use-with-django
# Live API integration tests are only run on a few, representative Python/Django version
# combinations, to avoid rapidly consuming the testing accounts' entire send allotments.
# Django 2.0: Python 3.5+
- { env: TOXENV=django20-py35-all, python: 3.5 }
- { env: TOXENV=django20-py36-all, python: 3.6 }
- { env: TOXENV=django20-pypy3-all, python: pypy3 }
# Django 2.1: Python 3.5, 3.6, or 3.7
- { env: TOXENV=django21-py35-all, python: 3.5 }
- { env: TOXENV=django21-py36-all, python: 3.6 }
- { env: TOXENV=django21-py37-all, python: 3.7 }
- { env: TOXENV=django21-pypy3-all, python: pypy3 }
# Django 2.2: Python 3.5, 3.6, or 3.7
- { env: TOXENV=django22-py35-all, python: 3.5 }
- { env: TOXENV=django22-py36-all, python: 3.6 }
- { env: TOXENV=django22-py37-all, python: 3.7 }
- { env: TOXENV=django22-pypy3-all, python: pypy3 }
# Django 3.0: Python 3.6, 3.7, or 3.8
- { env: TOXENV=django30-py36-all, python: 3.6 }
- { env: TOXENV=django30-py37-all, python: 3.7 }
- { env: TOXENV=django30-py38-all, python: 3.8 }
- { env: TOXENV=django30-pypy3-all, python: pypy3 }
# Django 3.1: Python 3.6, 3.7, or 3.8
- { env: TOXENV=django31-py36-all, python: 3.6 }
- { env: TOXENV=django31-py37-all, python: 3.7 }
- { env: TOXENV=django31-py38-all RUN_LIVE_TESTS=true, python: 3.8 }
- { env: TOXENV=django31-pypy3-all, python: pypy3 }
# Django current development (direct from GitHub source main branch):
- { env: TOXENV=djangoDev-py37-all, python: 3.7 }
# Install without optional extras (don't need to cover entire matrix)
- { env: TOXENV=django31-py37-none, python: 3.7 }
- { env: TOXENV=django31-py37-amazon_ses, python: 3.7 }
# Test some specific older package versions
- { env: TOXENV=django22-py37-all-old_urllib3, python: 3.7 }
allow_failures:
- env: TOXENV=djangoDev-py37-all
python: 3.7
cache: pip
install:
- pip install tox
script:
- tox

View File

@@ -37,6 +37,11 @@ Fixes
started issuing a cryptic "No sending domain specified" error for this case; with started issuing a cryptic "No sending domain specified" error for this case; with
this fix, Anymail will now treat it as an unsupported feature. this fix, Anymail will now treat it as an unsupported feature.
Other
~~~~~
* Move CI testing to GitHub Actions (and stop using Travis-CI).
v8.1 v8.1

View File

@@ -51,9 +51,9 @@ The package is released under the BSD license.
.. END shared-intro .. END shared-intro
.. image:: https://travis-ci.org/anymail/django-anymail.svg?branch=main .. image:: https://github.com/anymail/django-anymail/workflows/test/badge.svg?branch=main
:target: https://travis-ci.org/anymail/django-anymail :target: https://github.com/anymail/django-anymail/actions?query=workflow:test+branch:main
:alt: build status on Travis-CI :alt: build status in GitHub Actions
.. image:: https://readthedocs.org/projects/anymail/badge/?version=stable .. image:: https://readthedocs.org/projects/anymail/badge/?version=stable
:target: https://anymail.readthedocs.io/en/stable/ :target: https://anymail.readthedocs.io/en/stable/

View File

@@ -66,7 +66,7 @@ Pull requests are always welcome to fix bugs and improve support for ESP and Dja
Testing Testing
------- -------
Anymail is `tested on Travis CI`_ against several combinations of Django Anymail is `tested via GitHub Actions`_ against several combinations of Django
and Python versions. Tests are run at least once a week, to check whether ESP APIs and Python versions. Tests are run at least once a week, to check whether ESP APIs
and other dependencies have changed out from under Anymail. and other dependencies have changed out from under Anymail.
@@ -119,8 +119,8 @@ API keys or other settings. For example:
.. code-block:: console .. code-block:: console
$ export MAILGUN_TEST_API_KEY='your-Mailgun-API-key' $ export ANYMAIL_TEST_MAILGUN_API_KEY='your-Mailgun-API-key'
$ export MAILGUN_TEST_DOMAIN='mail.example.com' # sending domain for that API key $ export ANYMAIL_TEST_MAILGUN_DOMAIN='mail.example.com' # sending domain for that API key
$ tox -e django31-py38-all tests.test_mailgun_integration $ tox -e django31-py38-all tests.test_mailgun_integration
Check the ``*_integration_tests.py`` files in the `tests source`_ to see which variables Check the ``*_integration_tests.py`` files in the `tests source`_ to see which variables
@@ -132,7 +132,7 @@ for all 20+ supported combinations of Python and Django, sending hundreds of mes
.. _pyenv: https://github.com/pyenv/pyenv .. _pyenv: https://github.com/pyenv/pyenv
.. _tested on Travis CI: https://travis-ci.org/anymail/django-anymail .. _tested via GitHub Actions: https://github.com/anymail/django-anymail/actions?query=workflow:test
.. _tests source: https://github.com/anymail/django-anymail/blob/main/tests .. _tests source: https://github.com/anymail/django-anymail/blob/main/tests
.. _.travis.yml: https://github.com/anymail/django-anymail/blob/main/.travis.yml .. _.travis.yml: https://github.com/anymail/django-anymail/blob/main/.travis.yml

View File

@@ -22,7 +22,7 @@ def setup_and_run_tests(test_labels=None):
exclude_tags = envlist('ANYMAIL_SKIP_TESTS') exclude_tags = envlist('ANYMAIL_SKIP_TESTS')
# In automated testing, don't run live tests unless specifically requested # In automated testing, don't run live tests unless specifically requested
if envbool('CONTINUOUS_INTEGRATION') and not envbool('RUN_LIVE_TESTS'): if envbool('CONTINUOUS_INTEGRATION') and not envbool('ANYMAIL_RUN_LIVE_TESTS'):
exclude_tags.append('live') exclude_tags.append('live')
if tags: if tags:
@@ -49,13 +49,13 @@ def runtests(test_labels=None):
def envbool(var, default=False): def envbool(var, default=False):
"""Returns value of environment variable var as a bool, or default if not set. """Returns value of environment variable var as a bool, or default if not set/empty.
Converts `'true'` to `True`, and `'false'` to `False`. Converts `'true'` to `True`, and `'false'` to `False`.
See :func:`~distutils.util.strtobool` for full list of allowable values. See :func:`~distutils.util.strtobool` for full list of allowable values.
""" """
val = os.getenv(var, None) val = os.getenv(var, '')
if val is None: if val == '':
return default return default
else: else:
return strtobool(val) return strtobool(val)

View File

@@ -19,7 +19,7 @@ with open(path.join(here, "anymail/_version.py"), encoding='utf-8') as f:
def long_description_from_readme(rst): def long_description_from_readme(rst):
# Freeze external links (on PyPI) to refer to this X.Y or X.Y.Z tag. # Freeze external links (on PyPI) to refer to this X.Y or X.Y.Z tag.
# (This relies on tagging releases with 'vX.Y' or 'vX.Y.Z' in GitHub.) # (This relies on tagging releases with 'vX.Y' or 'vX.Y.Z' in GitHub.)
rst = re.sub(r'(?<=branch=)main' # Travis build status: branch=main --> branch=vX.Y.Z rst = re.sub(r'(?<=branch[=:])main' # GitHub Actions build status: branch=main --> branch=vX.Y.Z
r'|(?<=/)stable' # ReadTheDocs links: /stable --> /vX.Y.Z r'|(?<=/)stable' # ReadTheDocs links: /stable --> /vX.Y.Z
r'|(?<=version=)stable', # ReadTheDocs badge: version=stable --> version=vX.Y.Z r'|(?<=version=)stable', # ReadTheDocs badge: version=stable --> version=vX.Y.Z
release_tag, rst) # (?<=...) is "positive lookbehind": must be there, but won't get replaced release_tag, rst) # (?<=...) is "positive lookbehind": must be there, but won't get replaced

View File

@@ -10,13 +10,13 @@ from anymail.message import AnymailMessage
from .utils import AnymailTestMixin, sample_image_path from .utils import AnymailTestMixin, sample_image_path
AMAZON_SES_TEST_ACCESS_KEY_ID = os.getenv("AMAZON_SES_TEST_ACCESS_KEY_ID") ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID = os.getenv("ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID")
AMAZON_SES_TEST_SECRET_ACCESS_KEY = os.getenv("AMAZON_SES_TEST_SECRET_ACCESS_KEY") ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY = os.getenv("ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY")
AMAZON_SES_TEST_REGION_NAME = os.getenv("AMAZON_SES_TEST_REGION_NAME", "us-east-1") ANYMAIL_TEST_AMAZON_SES_REGION_NAME = os.getenv("ANYMAIL_TEST_AMAZON_SES_REGION_NAME", "us-east-1")
@unittest.skipUnless(AMAZON_SES_TEST_ACCESS_KEY_ID and AMAZON_SES_TEST_SECRET_ACCESS_KEY, @unittest.skipUnless(ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID and ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY,
"Set AMAZON_SES_TEST_ACCESS_KEY_ID and AMAZON_SES_TEST_SECRET_ACCESS_KEY " "Set ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID and ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY "
"environment variables to run Amazon SES integration tests") "environment variables to run Amazon SES integration tests")
@override_settings( @override_settings(
EMAIL_BACKEND="anymail.backends.amazon_ses.EmailBackend", EMAIL_BACKEND="anymail.backends.amazon_ses.EmailBackend",
@@ -25,9 +25,9 @@ AMAZON_SES_TEST_REGION_NAME = os.getenv("AMAZON_SES_TEST_REGION_NAME", "us-east-
# This setting provides Anymail-specific AWS credentials to boto3.client(), # This setting provides Anymail-specific AWS credentials to boto3.client(),
# overriding any credentials in the environment or boto config. It's often # overriding any credentials in the environment or boto config. It's often
# *not* the best approach -- see the Anymail and boto3 docs for other options. # *not* the best approach -- see the Anymail and boto3 docs for other options.
"aws_access_key_id": AMAZON_SES_TEST_ACCESS_KEY_ID, "aws_access_key_id": ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID,
"aws_secret_access_key": AMAZON_SES_TEST_SECRET_ACCESS_KEY, "aws_secret_access_key": ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY,
"region_name": AMAZON_SES_TEST_REGION_NAME, "region_name": ANYMAIL_TEST_AMAZON_SES_REGION_NAME,
# Can supply any other boto3.client params, including botocore.config.Config as dict # Can supply any other boto3.client params, including botocore.config.Config as dict
"config": {"retries": {"max_attempts": 2}}, "config": {"retries": {"max_attempts": 2}},
}, },
@@ -38,9 +38,9 @@ class AmazonSESBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
"""Amazon SES API integration tests """Amazon SES API integration tests
These tests run against the **live** Amazon SES API, using the environment These tests run against the **live** Amazon SES API, using the environment
variables `AMAZON_SES_TEST_ACCESS_KEY_ID` and `AMAZON_SES_TEST_SECRET_ACCESS_KEY` variables `ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID` and `ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY`
as AWS credentials. If those variables are not set, these tests won't run. as AWS credentials. If those variables are not set, these tests won't run.
(You can also set the environment variable `AMAZON_SES_TEST_REGION_NAME` (You can also set the environment variable `ANYMAIL_TEST_AMAZON_SES_REGION_NAME`
to test SES using a region other than the default "us-east-1".) to test SES using a region other than the default "us-east-1".)
Amazon SES doesn't offer a test mode -- it tries to send everything you ask. Amazon SES doesn't offer a test mode -- it tries to send everything you ask.
@@ -142,7 +142,7 @@ class AmazonSESBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
"AMAZON_SES_CLIENT_PARAMS": { "AMAZON_SES_CLIENT_PARAMS": {
"aws_access_key_id": "test-invalid-access-key-id", "aws_access_key_id": "test-invalid-access-key-id",
"aws_secret_access_key": "test-invalid-secret-access-key", "aws_secret_access_key": "test-invalid-secret-access-key",
"region_name": AMAZON_SES_TEST_REGION_NAME, "region_name": ANYMAIL_TEST_AMAZON_SES_REGION_NAME,
} }
}) })
def test_invalid_aws_credentials(self): def test_invalid_aws_credentials(self):

View File

@@ -12,24 +12,24 @@ from anymail.message import AnymailMessage
from .utils import AnymailTestMixin, sample_image_path from .utils import AnymailTestMixin, sample_image_path
MAILGUN_TEST_API_KEY = os.getenv('MAILGUN_TEST_API_KEY') ANYMAIL_TEST_MAILGUN_API_KEY = os.getenv('ANYMAIL_TEST_MAILGUN_API_KEY')
MAILGUN_TEST_DOMAIN = os.getenv('MAILGUN_TEST_DOMAIN') ANYMAIL_TEST_MAILGUN_DOMAIN = os.getenv('ANYMAIL_TEST_MAILGUN_DOMAIN')
@tag('mailgun', 'live') @tag('mailgun', 'live')
@unittest.skipUnless(MAILGUN_TEST_API_KEY and MAILGUN_TEST_DOMAIN, @unittest.skipUnless(ANYMAIL_TEST_MAILGUN_API_KEY and ANYMAIL_TEST_MAILGUN_DOMAIN,
"Set MAILGUN_TEST_API_KEY and MAILGUN_TEST_DOMAIN environment variables " "Set ANYMAIL_TEST_MAILGUN_API_KEY and ANYMAIL_TEST_MAILGUN_DOMAIN environment variables "
"to run Mailgun integration tests") "to run Mailgun integration tests")
@override_settings(ANYMAIL={'MAILGUN_API_KEY': MAILGUN_TEST_API_KEY, @override_settings(ANYMAIL={'MAILGUN_API_KEY': ANYMAIL_TEST_MAILGUN_API_KEY,
'MAILGUN_SENDER_DOMAIN': MAILGUN_TEST_DOMAIN, 'MAILGUN_SENDER_DOMAIN': ANYMAIL_TEST_MAILGUN_DOMAIN,
'MAILGUN_SEND_DEFAULTS': {'esp_extra': {'o:testmode': 'yes'}}}, 'MAILGUN_SEND_DEFAULTS': {'esp_extra': {'o:testmode': 'yes'}}},
EMAIL_BACKEND="anymail.backends.mailgun.EmailBackend") EMAIL_BACKEND="anymail.backends.mailgun.EmailBackend")
class MailgunBackendIntegrationTests(AnymailTestMixin, SimpleTestCase): class MailgunBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
"""Mailgun API integration tests """Mailgun API integration tests
These tests run against the **live** Mailgun API, using the These tests run against the **live** Mailgun API, using the
environment variable `MAILGUN_TEST_API_KEY` as the API key environment variable `ANYMAIL_TEST_MAILGUN_API_KEY` as the API key
and `MAILGUN_TEST_DOMAIN` as the sender domain. and `ANYMAIL_TEST_MAILGUN_DOMAIN` as the sender domain.
If those variables are not set, these tests won't run. If those variables are not set, these tests won't run.
""" """
@@ -43,8 +43,8 @@ class MailgunBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
def fetch_mailgun_events(self, message_id, event=None, def fetch_mailgun_events(self, message_id, event=None,
initial_delay=2, retry_delay=2, max_retries=5): initial_delay=2, retry_delay=2, max_retries=5):
"""Return list of Mailgun events related to message_id""" """Return list of Mailgun events related to message_id"""
url = "https://api.mailgun.net/v3/%s/events" % MAILGUN_TEST_DOMAIN url = "https://api.mailgun.net/v3/%s/events" % ANYMAIL_TEST_MAILGUN_DOMAIN
auth = ("api", MAILGUN_TEST_API_KEY) auth = ("api", ANYMAIL_TEST_MAILGUN_API_KEY)
# Despite the docs, Mailgun's events API actually expects the message-id # Despite the docs, Mailgun's events API actually expects the message-id
# without the <...> brackets (so, not exactly "as returned by the messages API") # without the <...> brackets (so, not exactly "as returned by the messages API")
@@ -116,7 +116,7 @@ class MailgunBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
) )
message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain") message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
message.attach("vedhæftet fil.csv", "ID,Name\n1,3", "text/csv") message.attach("vedhæftet fil.csv", "ID,Name\n1,3", "text/csv")
cid = message.attach_inline_image_file(sample_image_path(), domain=MAILGUN_TEST_DOMAIN) cid = message.attach_inline_image_file(sample_image_path(), domain=ANYMAIL_TEST_MAILGUN_DOMAIN)
message.attach_alternative( message.attach_alternative(
"<div>This is the <i>html</i> body <img src='cid:%s'></div>" % cid, "<div>This is the <i>html</i> body <img src='cid:%s'></div>" % cid,
"text/html") "text/html")
@@ -195,7 +195,7 @@ class MailgunBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
# self.assertIn("'from' parameter is not a valid address", str(err)) # self.assertIn("'from' parameter is not a valid address", str(err))
@override_settings(ANYMAIL={'MAILGUN_API_KEY': "Hey, that's not an API key", @override_settings(ANYMAIL={'MAILGUN_API_KEY': "Hey, that's not an API key",
'MAILGUN_SENDER_DOMAIN': MAILGUN_TEST_DOMAIN, 'MAILGUN_SENDER_DOMAIN': ANYMAIL_TEST_MAILGUN_DOMAIN,
'MAILGUN_SEND_DEFAULTS': {'esp_extra': {'o:testmode': 'yes'}}}) 'MAILGUN_SEND_DEFAULTS': {'esp_extra': {'o:testmode': 'yes'}}})
def test_invalid_api_key(self): def test_invalid_api_key(self):
with self.assertRaises(AnymailAPIError) as cm: with self.assertRaises(AnymailAPIError) as cm:

View File

@@ -8,16 +8,16 @@ from anymail.message import AnymailMessage
from .utils import AnymailTestMixin, sample_image_path from .utils import AnymailTestMixin, sample_image_path
MAILJET_TEST_API_KEY = os.getenv('MAILJET_TEST_API_KEY') ANYMAIL_TEST_MAILJET_API_KEY = os.getenv('ANYMAIL_TEST_MAILJET_API_KEY')
MAILJET_TEST_SECRET_KEY = os.getenv('MAILJET_TEST_SECRET_KEY') ANYMAIL_TEST_MAILJET_SECRET_KEY = os.getenv('ANYMAIL_TEST_MAILJET_SECRET_KEY')
@tag('mailjet', 'live') @tag('mailjet', 'live')
@unittest.skipUnless(MAILJET_TEST_API_KEY and MAILJET_TEST_SECRET_KEY, @unittest.skipUnless(ANYMAIL_TEST_MAILJET_API_KEY and ANYMAIL_TEST_MAILJET_SECRET_KEY,
"Set MAILJET_TEST_API_KEY and MAILJET_TEST_SECRET_KEY " "Set ANYMAIL_TEST_MAILJET_API_KEY and ANYMAIL_TEST_MAILJET_SECRET_KEY "
"environment variables to run Mailjet integration tests") "environment variables to run Mailjet integration tests")
@override_settings(ANYMAIL={"MAILJET_API_KEY": MAILJET_TEST_API_KEY, @override_settings(ANYMAIL={"MAILJET_API_KEY": ANYMAIL_TEST_MAILJET_API_KEY,
"MAILJET_SECRET_KEY": MAILJET_TEST_SECRET_KEY, "MAILJET_SECRET_KEY": ANYMAIL_TEST_MAILJET_SECRET_KEY,
"MAILJET_SEND_DEFAULTS": {"esp_extra": {"SandboxMode": True}}, # don't actually send mail "MAILJET_SEND_DEFAULTS": {"esp_extra": {"SandboxMode": True}}, # don't actually send mail
}, },
EMAIL_BACKEND="anymail.backends.mailjet.EmailBackend") EMAIL_BACKEND="anymail.backends.mailjet.EmailBackend")
@@ -25,7 +25,7 @@ class MailjetBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
"""Mailjet API integration tests """Mailjet API integration tests
These tests run against the **live** Mailjet API, using the These tests run against the **live** Mailjet API, using the
environment variables `MAILJET_TEST_API_KEY` and `MAILJET_TEST_SECRET_KEY` environment variables `ANYMAIL_TEST_MAILJET_API_KEY` and `ANYMAIL_TEST_MAILJET_SECRET_KEY`
as the API key and API secret key, respectively. as the API key and API secret key, respectively.
If those variables are not set, these tests won't run. If those variables are not set, these tests won't run.

View File

@@ -9,19 +9,19 @@ from anymail.message import AnymailMessage
from .utils import AnymailTestMixin, sample_image_path from .utils import AnymailTestMixin, sample_image_path
MANDRILL_TEST_API_KEY = os.getenv('MANDRILL_TEST_API_KEY') ANYMAIL_TEST_MANDRILL_API_KEY = os.getenv('ANYMAIL_TEST_MANDRILL_API_KEY')
@tag('mandrill', 'live') @tag('mandrill', 'live')
@unittest.skipUnless(MANDRILL_TEST_API_KEY, @unittest.skipUnless(ANYMAIL_TEST_MANDRILL_API_KEY,
"Set MANDRILL_TEST_API_KEY environment variable to run integration tests") "Set ANYMAIL_TEST_MANDRILL_API_KEY environment variable to run integration tests")
@override_settings(MANDRILL_API_KEY=MANDRILL_TEST_API_KEY, @override_settings(MANDRILL_API_KEY=ANYMAIL_TEST_MANDRILL_API_KEY,
EMAIL_BACKEND="anymail.backends.mandrill.EmailBackend") EMAIL_BACKEND="anymail.backends.mandrill.EmailBackend")
class MandrillBackendIntegrationTests(AnymailTestMixin, SimpleTestCase): class MandrillBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
"""Mandrill API integration tests """Mandrill API integration tests
These tests run against the **live** Mandrill API, using the These tests run against the **live** Mandrill API, using the
environment variable `MANDRILL_TEST_API_KEY` as the API key. environment variable `ANYMAIL_TEST_MANDRILL_API_KEY` as the API key.
If that variable is not set, these tests won't run. If that variable is not set, these tests won't run.
See https://mandrill.zendesk.com/hc/en-us/articles/205582447 See https://mandrill.zendesk.com/hc/en-us/articles/205582447

View File

@@ -11,8 +11,8 @@ from .utils import AnymailTestMixin, sample_image_path
# For most integration tests, Postmark's sandboxed "POSTMARK_API_TEST" token is used. # For most integration tests, Postmark's sandboxed "POSTMARK_API_TEST" token is used.
# But to test template sends, a real Postmark server token and template id are needed: # But to test template sends, a real Postmark server token and template id are needed:
POSTMARK_TEST_SERVER_TOKEN = os.getenv('POSTMARK_TEST_SERVER_TOKEN') ANYMAIL_TEST_POSTMARK_SERVER_TOKEN = os.getenv('ANYMAIL_TEST_POSTMARK_SERVER_TOKEN')
POSTMARK_TEST_TEMPLATE_ID = os.getenv('POSTMARK_TEST_TEMPLATE_ID') ANYMAIL_TEST_POSTMARK_TEMPLATE_ID = os.getenv('ANYMAIL_TEST_POSTMARK_TEMPLATE_ID')
@tag('postmark', 'live') @tag('postmark', 'live')
@@ -88,15 +88,15 @@ class PostmarkBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
self.assertEqual(err.status_code, 422) self.assertEqual(err.status_code, 422)
self.assertIn("Invalid 'From' address", str(err)) self.assertIn("Invalid 'From' address", str(err))
@unittest.skipUnless(POSTMARK_TEST_SERVER_TOKEN and POSTMARK_TEST_TEMPLATE_ID, @unittest.skipUnless(ANYMAIL_TEST_POSTMARK_SERVER_TOKEN and ANYMAIL_TEST_POSTMARK_TEMPLATE_ID,
"Set POSTMARK_TEST_SERVER_TOKEN and POSTMARK_TEST_TEMPLATE_ID " "Set ANYMAIL_TEST_POSTMARK_SERVER_TOKEN and ANYMAIL_TEST_POSTMARK_TEMPLATE_ID "
"environment variables to run Postmark template integration tests") "environment variables to run Postmark template integration tests")
@override_settings(ANYMAIL_POSTMARK_SERVER_TOKEN=POSTMARK_TEST_SERVER_TOKEN) @override_settings(ANYMAIL_POSTMARK_SERVER_TOKEN=ANYMAIL_TEST_POSTMARK_SERVER_TOKEN)
def test_template(self): def test_template(self):
message = AnymailMessage( message = AnymailMessage(
from_email="from@test-pm.anymail.info", from_email="from@test-pm.anymail.info",
to=["test+to1@anymail.info", "Second Recipient <test+to2@anymail.info>"], to=["test+to1@anymail.info", "Second Recipient <test+to2@anymail.info>"],
template_id=POSTMARK_TEST_TEMPLATE_ID, template_id=ANYMAIL_TEST_POSTMARK_TEMPLATE_ID,
merge_data={ merge_data={
"test+to1@anymail.info": {"name": "Recipient 1", "order_no": "12345"}, "test+to1@anymail.info": {"name": "Recipient 1", "order_no": "12345"},
"test+to2@anymail.info": {"order_no": "6789"}, "test+to2@anymail.info": {"order_no": "6789"},

View File

@@ -9,15 +9,15 @@ from anymail.message import AnymailMessage
from .utils import AnymailTestMixin, sample_image_path from .utils import AnymailTestMixin, sample_image_path
SENDGRID_TEST_API_KEY = os.getenv('SENDGRID_TEST_API_KEY') ANYMAIL_TEST_SENDGRID_API_KEY = os.getenv('ANYMAIL_TEST_SENDGRID_API_KEY')
SENDGRID_TEST_TEMPLATE_ID = os.getenv('SENDGRID_TEST_TEMPLATE_ID') ANYMAIL_TEST_SENDGRID_TEMPLATE_ID = os.getenv('ANYMAIL_TEST_SENDGRID_TEMPLATE_ID')
@tag('sendgrid', 'live') @tag('sendgrid', 'live')
@unittest.skipUnless(SENDGRID_TEST_API_KEY, @unittest.skipUnless(ANYMAIL_TEST_SENDGRID_API_KEY,
"Set SENDGRID_TEST_API_KEY environment variable " "Set ANYMAIL_TEST_SENDGRID_API_KEY environment variable "
"to run SendGrid integration tests") "to run SendGrid integration tests")
@override_settings(ANYMAIL_SENDGRID_API_KEY=SENDGRID_TEST_API_KEY, @override_settings(ANYMAIL_SENDGRID_API_KEY=ANYMAIL_TEST_SENDGRID_API_KEY,
ANYMAIL_SENDGRID_SEND_DEFAULTS={"esp_extra": { ANYMAIL_SENDGRID_SEND_DEFAULTS={"esp_extra": {
"mail_settings": {"sandbox_mode": {"enable": True}}, "mail_settings": {"sandbox_mode": {"enable": True}},
}}, }},
@@ -26,7 +26,7 @@ class SendGridBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
"""SendGrid v3 API integration tests """SendGrid v3 API integration tests
These tests run against the **live** SendGrid API, using the These tests run against the **live** SendGrid API, using the
environment variable `SENDGRID_TEST_API_KEY` as the API key environment variable `ANYMAIL_TEST_SENDGRID_API_KEY` as the API key
If those variables are not set, these tests won't run. If those variables are not set, these tests won't run.
The SEND_DEFAULTS above force SendGrid's v3 sandbox mode, which avoids sending mail. The SEND_DEFAULTS above force SendGrid's v3 sandbox mode, which avoids sending mail.
@@ -107,15 +107,15 @@ class SendGridBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
self.assertEqual(recipient_status['to1@sink.sendgrid.net'].status, 'queued') self.assertEqual(recipient_status['to1@sink.sendgrid.net'].status, 'queued')
self.assertEqual(recipient_status['to2@sink.sendgrid.net'].status, 'queued') self.assertEqual(recipient_status['to2@sink.sendgrid.net'].status, 'queued')
@unittest.skipUnless(SENDGRID_TEST_TEMPLATE_ID, @unittest.skipUnless(ANYMAIL_TEST_SENDGRID_TEMPLATE_ID,
"Set the SENDGRID_TEST_TEMPLATE_ID environment variable " "Set the ANYMAIL_TEST_SENDGRID_TEMPLATE_ID environment variable "
"to a template in your SendGrid account to test stored templates") "to a template in your SendGrid account to test stored templates")
def test_stored_template(self): def test_stored_template(self):
message = AnymailMessage( message = AnymailMessage(
from_email="Test From <from@example.com>", from_email="Test From <from@example.com>",
to=["to@sink.sendgrid.net"], to=["to@sink.sendgrid.net"],
# Anymail's live test template has merge fields "name", "order_no", and "dept"... # Anymail's live test template has merge fields "name", "order_no", and "dept"...
template_id=SENDGRID_TEST_TEMPLATE_ID, template_id=ANYMAIL_TEST_SENDGRID_TEMPLATE_ID,
merge_data={ merge_data={
'to@sink.sendgrid.net': { 'to@sink.sendgrid.net': {
'name': "Test Recipient", 'name': "Test Recipient",

View File

@@ -8,14 +8,14 @@ from anymail.message import AnymailMessage
from .utils import AnymailTestMixin from .utils import AnymailTestMixin
SENDINBLUE_TEST_API_KEY = os.getenv('SENDINBLUE_TEST_API_KEY') ANYMAIL_TEST_SENDINBLUE_API_KEY = os.getenv('ANYMAIL_TEST_SENDINBLUE_API_KEY')
@tag('sendinblue', 'live') @tag('sendinblue', 'live')
@unittest.skipUnless(SENDINBLUE_TEST_API_KEY, @unittest.skipUnless(ANYMAIL_TEST_SENDINBLUE_API_KEY,
"Set SENDINBLUE_TEST_API_KEY environment variable " "Set ANYMAIL_TEST_SENDINBLUE_API_KEY environment variable "
"to run SendinBlue integration tests") "to run SendinBlue integration tests")
@override_settings(ANYMAIL_SENDINBLUE_API_KEY=SENDINBLUE_TEST_API_KEY, @override_settings(ANYMAIL_SENDINBLUE_API_KEY=ANYMAIL_TEST_SENDINBLUE_API_KEY,
ANYMAIL_SENDINBLUE_SEND_DEFAULTS=dict(), ANYMAIL_SENDINBLUE_SEND_DEFAULTS=dict(),
EMAIL_BACKEND="anymail.backends.sendinblue.EmailBackend") EMAIL_BACKEND="anymail.backends.sendinblue.EmailBackend")
class SendinBlueBackendIntegrationTests(AnymailTestMixin, SimpleTestCase): class SendinBlueBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
@@ -23,7 +23,7 @@ class SendinBlueBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
SendinBlue doesn't have sandbox so these tests run SendinBlue doesn't have sandbox so these tests run
against the **live** SendinBlue API, using the against the **live** SendinBlue API, using the
environment variable `SENDINBLUE_TEST_API_KEY` as the API key environment variable `ANYMAIL_TEST_SENDINBLUE_API_KEY` as the API key
If those variables are not set, these tests won't run. If those variables are not set, these tests won't run.
https://developers.sendinblue.com/docs/faq#section-how-can-i-test-the-api- https://developers.sendinblue.com/docs/faq#section-how-can-i-test-the-api-

View File

@@ -9,20 +9,20 @@ from anymail.message import AnymailMessage
from .utils import AnymailTestMixin, sample_image_path from .utils import AnymailTestMixin, sample_image_path
SPARKPOST_TEST_API_KEY = os.getenv('SPARKPOST_TEST_API_KEY') ANYMAIL_TEST_SPARKPOST_API_KEY = os.getenv('ANYMAIL_TEST_SPARKPOST_API_KEY')
@tag('sparkpost', 'live') @tag('sparkpost', 'live')
@unittest.skipUnless(SPARKPOST_TEST_API_KEY, @unittest.skipUnless(ANYMAIL_TEST_SPARKPOST_API_KEY,
"Set SPARKPOST_TEST_API_KEY environment variable " "Set ANYMAIL_TEST_SPARKPOST_API_KEY environment variable "
"to run SparkPost integration tests") "to run SparkPost integration tests")
@override_settings(ANYMAIL_SPARKPOST_API_KEY=SPARKPOST_TEST_API_KEY, @override_settings(ANYMAIL_SPARKPOST_API_KEY=ANYMAIL_TEST_SPARKPOST_API_KEY,
EMAIL_BACKEND="anymail.backends.sparkpost.EmailBackend") EMAIL_BACKEND="anymail.backends.sparkpost.EmailBackend")
class SparkPostBackendIntegrationTests(AnymailTestMixin, SimpleTestCase): class SparkPostBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
"""SparkPost API integration tests """SparkPost API integration tests
These tests run against the **live** SparkPost API, using the These tests run against the **live** SparkPost API, using the
environment variable `SPARKPOST_TEST_API_KEY` as the API key environment variable `ANYMAIL_TEST_SPARKPOST_API_KEY` as the API key
If that variable is not set, these tests won't run. If that variable is not set, these tests won't run.
SparkPost doesn't offer a test mode -- it tries to send everything SparkPost doesn't offer a test mode -- it tries to send everything

11
tox.ini
View File

@@ -47,16 +47,9 @@ commands =
passenv = passenv =
ANYMAIL_ONLY_TEST ANYMAIL_ONLY_TEST
ANYMAIL_SKIP_TESTS ANYMAIL_SKIP_TESTS
RUN_LIVE_TESTS ANYMAIL_RUN_LIVE_TESTS
CONTINUOUS_INTEGRATION CONTINUOUS_INTEGRATION
AMAZON_SES_TEST_* ANYMAIL_TEST_*
MAILGUN_TEST_*
MAILJET_TEST_*
MANDRILL_TEST_*
POSTMARK_TEST_*
SENDINBLUE_TEST_*
SENDGRID_TEST_*
SPARKPOST_TEST_*
[testenv:lint] [testenv:lint]
basepython = python3 basepython = python3