Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
ffe7970
add vagrant config for easy local testing
thenewguy Nov 10, 2019
6dadec9
clean this up
thenewguy Nov 10, 2019
ad1995f
boilerplate
thenewguy Nov 10, 2019
80d5da8
make migration
thenewguy Nov 10, 2019
83bcbb2
run a simple test
thenewguy Nov 10, 2019
587777e
confirm working celery setup
thenewguy Nov 10, 2019
10a2922
add test checking result state properties
thenewguy Nov 11, 2019
d799397
test on py35,6,7
thenewguy Nov 11, 2019
adff143
config for travis
thenewguy Nov 11, 2019
d83b488
cleanup better
thenewguy Nov 11, 2019
8807f8b
be verbose
thenewguy Nov 11, 2019
3f6743c
add missing __enter__()
thenewguy Nov 11, 2019
916fdf5
skip purge - all pass without it
thenewguy Nov 11, 2019
b2558ad
shorten worker name
thenewguy Nov 11, 2019
1dd2351
use worker.ensure_started() instead of ping() - multiple successes
thenewguy Nov 11, 2019
81446e3
confirm sleep fixes travis problems b4 delving into signals listeners
thenewguy Nov 11, 2019
ec63607
Merge remote-tracking branch 'upstream/master' into test
thenewguy May 22, 2020
ed4fd03
install specific version fo django
thenewguy May 22, 2020
2d356cb
Revert "install specific version fo django"
thenewguy May 22, 2020
c8c439e
pin to django 3.0
thenewguy May 22, 2020
3aa8370
test against py38,37,36 per django 3.0
thenewguy May 22, 2020
9b7b245
fixed missing import
thenewguy May 22, 2020
b4f6e19
support more common case first
thenewguy May 22, 2020
ddad402
removed duplicate import
thenewguy May 22, 2020
2dd915c
removed py35 tests per keyring==21.1.0 (from -r dev-requirements.txt)
thenewguy May 22, 2020
33b0424
Merge branch 'test' into fixed-upstream-issue-14
thenewguy May 22, 2020
5969e95
simplify as compat changes were less than anticipated
thenewguy May 22, 2020
edc6c20
removed whitespace change
thenewguy May 22, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
language: python
python:
- "2.7"
- "3.6"
- "pypy"
- "pypy3"
# command to install dependencies
cache: pip
matrix:
include:
- env: TOX_ENV=py36
python: 3.6
- env: TOX_ENV=py37
python: 3.7
dist: bionic
sudo: true
- env: TOX_ENV=py38
python: 3.8

install:
- "pip install -r requirements.txt"
- "pip install -r requirements.txt -r dev-requirements.txt tox tox-docker"
- "pip install ."
# command to run tests
script:
- "python -m compileall ."

script: tox -vv -e $TOX_ENV
3 changes: 2 additions & 1 deletion dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
astroid==2.3.3
bleach==3.1.0
certifi==2019.11.28
celery[redis]
chardet==3.0.4
docutils==0.16
idna==2.8
Expand All @@ -14,9 +15,9 @@ pkginfo==1.5.0.1
pygments==2.5.2
pylint==2.4.4
readme-renderer==24.0
redis
requests-toolbelt==0.9.1
requests==2.22.0
six==1.14.0
tqdm==4.42.1
twine==3.1.1
typed-ast==1.4.1 ; implementation_name == 'cpython' and python_version < '3.8'
Expand Down
6 changes: 5 additions & 1 deletion djcelery_model/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
from django.db.models import Q
from django.db.models.query import QuerySet
from django.contrib.contenttypes.models import ContentType
from django.utils.encoding import python_2_unicode_compatible

try:
from six import python_2_unicode_compatible
except ImportError:
from django.utils.encoding import python_2_unicode_compatible

try:
# Django >= 1.7
Expand Down
7 changes: 7 additions & 0 deletions djcelery_model/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from __future__ import absolute_import, unicode_literals

# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app

__all__ = ('celery_app',)
19 changes: 19 additions & 0 deletions djcelery_model/tests/celery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery

# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djcelery_model.tests.settings')

app = Celery('project')

# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')

# Load task modules from all registered Django app configs.
app.autodiscover_tasks()

from celery.contrib.testing.tasks import ping
70 changes: 70 additions & 0 deletions djcelery_model/tests/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# -*- coding: utf-8
from __future__ import unicode_literals, absolute_import
import os

DEBUG = True
USE_TZ = True

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sites',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',

'djcelery_model',
'djcelery_model.tests.testapp',
]

SITE_ID = 1

MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
]

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(os.path.dirname(__file__), 'templates'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

ROOT_DIR = os.path.dirname(__file__)
STATIC_ROOT = os.path.join(ROOT_DIR, 'test-static')
MEDIA_ROOT = os.path.join(ROOT_DIR, 'test-media')
MEDIA_URL = '/media/'
STATIC_URL = '/static/'

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
}
}

REDIS_PORT = os.getenv('REDIS_6379_TCP_PORT', 'port-missing-from-env')

CELERY_BROKER_URL = 'redis://localhost:%s/0' % REDIS_PORT
CELERY_RESULT_BACKEND = 'redis://localhost:%s/2' % REDIS_PORT
CELERY_TASK_TRACK_STARTED = True
CELERY_TASK_SEND_SENT_EVENT = True
CELERY_SEND_EVENTS = True
Empty file.
25 changes: 25 additions & 0 deletions djcelery_model/tests/testapp/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by Django 2.2.7 on 2019-11-10 23:21

from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
]

operations = [
migrations.CreateModel(
name='JPEGFile',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('file', models.FileField(upload_to='')),
('etag', models.CharField(blank=True, max_length=255)),
],
options={
'abstract': False,
},
),
]
Empty file.
6 changes: 6 additions & 0 deletions djcelery_model/tests/testapp/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.db import models
from djcelery_model.models import TaskMixin

class JPEGFile(TaskMixin, models.Model):
file = models.FileField()
etag = models.CharField(max_length=255, blank=True)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions djcelery_model/tests/testapp/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from __future__ import absolute_import, unicode_literals
from hashlib import sha1
from time import sleep
from celery import shared_task

from .models import JPEGFile


@shared_task
def calculate_etag(pk):
jpeg = JPEGFile.objects.get(pk=pk)
jpeg.etag = sha1(jpeg.file.read()).hexdigest()
sleep(5)
jpeg.save()
64 changes: 64 additions & 0 deletions djcelery_model/tests/testapp/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from time import sleep
from celery.contrib.testing.tasks import ping
from celery.contrib.testing.worker import start_worker
from django.contrib.staticfiles import finders
from django.core.files import File
from django.test import TestCase, TransactionTestCase

from djcelery_model.models import TaskMixin
from djcelery_model.tests import celery_app

from .models import JPEGFile
from .tasks import calculate_etag


class CeleryTestCase(TransactionTestCase):
def setUp(self):
self.worker_context = start_worker(celery_app, perform_ping_check=False)
self.worker = self.worker_context.__enter__()
self.worker.ensure_started()

def tearDown(self):
self.worker_context.__exit__(None, None, None)


class TestAppIntegrationTests(TestCase):
def test_model_is_taskmixin(self):
self.assertIsInstance(JPEGFile(), TaskMixin)


class TestAppCeleryTests(CeleryTestCase):
def test_worker(self):
result = ping.delay()
pong = result.get(timeout=10)
self.assertEqual(pong, 'pong')

def test_state_properties(self):
jpeg = JPEGFile.objects.create(
file=File(open(finders.find('testapp/flower.jpg'), 'rb'), name='flower.jpg')
)

self.assertFalse(jpeg.has_running_task)
self.assertFalse(jpeg.has_ready_task)

result = jpeg.apply_async(calculate_etag, [jpeg.pk])
self.assertTrue(jpeg.has_running_task)
self.assertFalse(jpeg.has_ready_task)
self.assertFalse(result.ready())

result.get(timeout=10)
self.assertTrue(result.ready())

# not the greatest way to wait for async stuff to happen, but we need
# the signals to complete before testing for side effects
sleep(3)

self.assertEqual(jpeg.etag, '')
self.assertFalse(jpeg.has_running_task)
self.assertTrue(jpeg.has_ready_task)

jpeg.refresh_from_db()

self.assertEqual(jpeg.etag, '80b098e6cd95b9901fa29799d48731433dfaeab0')
self.assertFalse(jpeg.has_running_task)
self.assertTrue(jpeg.has_ready_task)
12 changes: 12 additions & 0 deletions manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, absolute_import

import os
import sys

if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djcelery_model.tests.settings")
from django.core.management import execute_from_command_line

execute_from_command_line(sys.argv)
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
django>=1.11
django>=3,<3.1
celery>=4.2
six>=1.9
30 changes: 30 additions & 0 deletions runtests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env python

import os
import shutil
import sys
import warnings

from django.core.management import execute_from_command_line

os.environ['DJANGO_SETTINGS_MODULE'] = 'djcelery_model.tests.settings'


def runtests():
# Don't ignore DeprecationWarnings
only_djcelery_model = r'^djcelery_model(\.|$)'
warnings.filterwarnings('default', category=DeprecationWarning, module=only_djcelery_model)
warnings.filterwarnings('default', category=PendingDeprecationWarning, module=only_djcelery_model)

args = sys.argv[1:]
argv = sys.argv[:1] + ['test'] + args
try:
execute_from_command_line(argv)
finally:
from djcelery_model.tests.settings import STATIC_ROOT, MEDIA_ROOT
shutil.rmtree(STATIC_ROOT, ignore_errors=True)
shutil.rmtree(MEDIA_ROOT, ignore_errors=True)


if __name__ == '__main__':
runtests()
32 changes: 32 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[tox]
envlist =
{py36,py37,py38}


[testenv]
setenv =
PYTHONPATH = {toxinidir}:{toxinidir}

commands =
python runtests.py --noinput {posargs}

deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/dev-requirements.txt

basepython =
py38: python3.8
py37: python3.7
py36: python3.6

docker =
redis:5.0



[docker:redis:5.0]
healthcheck_cmd = redis-cli ping | grep -q PONG
healthcheck_interval = 3
healthcheck_timeout = 3
healthcheck_retries = 30
healthcheck_start_period = 5
1 change: 1 addition & 0 deletions vagrant/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vagrant/
23 changes: 23 additions & 0 deletions vagrant/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
CREATES A VAGRANT ENVIRONMENT TO FACILITATE LOCAL TESTING

========
USAGE:
========
To run tests:
cd to this directory and then issue the following commands:
vagrant up
vagrant ssh
bash /vagrant/vagrant/runtox.sh

to run with verbose output:
bash /vagrant/vagrant/runtox.sh -vv -- -v 2

to run a specific test:
bash /vagrant/vagrant/runtox.sh -vv -- -v 2 path.to.test


To clean after tests run:
rm -R /tmp/vagrant

To make migrations (after running tests to create tox environment):
/tmp/vagrant/.tox/py35/bin/python /vagrant/manage.py makemigrations
11 changes: 11 additions & 0 deletions vagrant/Vagrantfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/bionic64"

config.vm.provider "virtualbox" do |v|
v.name = "django-celery-model"
end

config.vm.provision :shell, path: "provision.sh"
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.synced_folder "../", "/vagrant"
end
Loading