Skip to content

Commit

Permalink
Merge branch 'feature/travis' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
saxix committed Oct 7, 2013
2 parents b2bd64c + 7004621 commit 755d925
Show file tree
Hide file tree
Showing 19 changed files with 78 additions and 118 deletions.
18 changes: 5 additions & 13 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,26 @@ services:
- PostgreSQL
python:
- 2.7

env:
- DJANGO="1.4.x" DBENGINE=mysql
- DJANGO="1.4.x" DBENGINE=pg

- DJANGO="1.5.x" DBENGINE=mysql
- DJANGO="1.5.x" DBENGINE=pg

- DJANGO="1.6.x" DBENGINE=mysql
- DJANGO="1.6.x" DBENGINE=pg

- DJANGO="dev" DBENGINE=mysql
- DJANGO="dev" DBENGINE=pg


install:
- make install-deps
- sh -c "if [ '$DBENGINE' = 'pg' ]; then pip install -q psycopg2; fi"
- sh -c "if [ '$DBENGINE' = 'mysql' ]; then pip install -q MySQL-python; fi"


script:
- make ci

before_install:
- sh -c "if [ '$DBENGINE' = 'pg' ]; then psql -c 'DROP DATABASE IF EXISTS concurrency;' -U postgres; fi"
- sh -c "if [ '$DBENGINE' = 'mysql' ]; then mysql -e 'DROP DATABASE IF EXISTS concurrency;'; fi"

before_script:
- sh -c "if [ '$DBENGINE' = 'pg' ]; then psql -c 'CREATE DATABASE concurrency;' -U postgres; fi"
- sh -c "if [ '$DBENGINE' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS concurrency;'; fi"
- make init-db ci

matrix:
exclude:
Expand Down
33 changes: 18 additions & 15 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ DJANGO_15=django==1.5.4
DJANGO_16=https://www.djangoproject.com/m/releases/1.6/Django-1.6b4.tar.gz
DJANGO_DEV=git+git://github.com/django/django.git


mkbuilddir:
mkdir -p ${BUILDDIR}

Expand All @@ -29,28 +30,30 @@ test:


init-db:
sh -c "if [ '${DBENGINE}' = 'mysql' ]; then mysql -e 'DROP DATABASE IF EXISTS concurrency;'; fi"
sh -c "if [ '${DBENGINE}' = 'pg' ]; then psql -c 'DROP DATABASE IF EXISTS concurrency;' -U postgres; fi"

sh -c "if [ '${DBENGINE}' = 'mysql' ]; then pip install MySQL-python; fi"
sh -c "if [ '${DBENGINE}' = 'pg' ]; then pip install -q psycopg2; fi"
@sh -c "if [ '${DBENGINE}' = 'mysql' ]; then mysql -e 'DROP DATABASE IF EXISTS concurrency;'; fi"
@sh -c "if [ '${DBENGINE}' = 'mysql' ]; then pip install MySQL-python; fi"
@sh -c "if [ '${DBENGINE}' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS concurrency;'; fi"

sh -c "if [ '${DBENGINE}' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS concurrency;'; fi"
sh -c "if [ '${DBENGINE}' = 'pg' ]; then psql -c 'CREATE DATABASE concurrency;' -U postgres; fi"
@sh -c "if [ '${DBENGINE}' = 'pg' ]; then psql -c 'DROP DATABASE IF EXISTS concurrency;' -U postgres; fi"
@sh -c "if [ '${DBENGINE}' = 'pg' ]; then psql -c 'DROP DATABASE IF EXISTS test_concurrency;' -U postgres; fi"
@sh -c "if [ '${DBENGINE}' = 'pg' ]; then psql -c 'CREATE DATABASE concurrency;' -U postgres; fi"
@sh -c "if [ '${DBENGINE}' = 'pg' ]; then pip install -q psycopg2; fi"

ci:
sh -c "if [ '${DJANGO}' = '1.4.x' ]; then pip install ${DJANGO_14}; fi"
sh -c "if [ '${DJANGO}' = '1.5.x' ]; then pip install ${DJANGO_15}; fi"
sh -c "if [ '${DJANGO}' = '1.6.x' ]; then pip install ${DJANGO_16}; fi"
sh -c "if [ '${DJANGO}' = 'dev' ]; then pip install ${DJANGO_DEV}; fi"

@sh -c "if [ '${DJANGO}' = '1.4.x' ]; then pip install ${DJANGO_14}; fi"
@sh -c "if [ '${DJANGO}' = '1.5.x' ]; then pip install ${DJANGO_15}; fi"
@sh -c "if [ '${DJANGO}' = '1.6.x' ]; then pip install ${DJANGO_16}; fi"
@sh -c "if [ '${DJANGO}' = 'dev' ]; then pip install ${DJANGO_DEV}; fi"
@pip install coverage
@python -c "from __future__ import print_function;import django;print('Django version:', django.get_version())"
@echo "Database:" ${DBENGINE}

coverage run demo/manage.py test concurrency --noinput --settings=${DJANGO_SETTINGS_MODULE} --failfast
#demo/manage.py test concurrency --settings=${DJANGO_SETTINGS_MODULE} --noinput

coverage run demo/manage.py test concurrency --settings=${DJANGO_SETTINGS_MODULE}
coverage report

cov-html: coverage mkbuilddir
coverage: mkbuilddir
coverage report
coverage html

clean:
Expand Down
1 change: 1 addition & 0 deletions concurrency/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ def save_model(self, request, obj, form, change):
super(ConcurrencyListEditableMixin, self).save_model(request, obj, form, change)
except RecordModifiedError:
self._add_conflict(request, obj)

# If policy is set to 'silent' the user will be informed using message_user
# raise Exception if not silent.
# NOTE:
Expand Down
13 changes: 2 additions & 11 deletions concurrency/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,8 @@ def _wrap_model_save(model, force=False):
logger.debug('Wrapping save method of %s' % model)
old_save = getattr(model, 'save')
setattr(model, 'save', _wrap_save(old_save))
from concurrency.api import get_version, get_object_with_version
#setattr(model._default_manager,
# 'get_object_with_version', get_object_with_version)
from concurrency.api import get_version

setattr(model, 'get_concurrency_version', get_version)

model._concurrencymeta._versioned_save = True
Expand All @@ -83,14 +82,6 @@ def inner(self, force_insert=False, force_update=False, using=None, **kwargs):
return update_wrapper(inner, func)


# def _versioned_save(self, force_insert=False, force_update=False, using=None):
# if force_insert and force_update:
# raise ValueError("Cannot force both insert and updating in model saving.")
# if not force_insert:
# _select_lock(self)
# self.save_base(using=using, force_insert=force_insert, force_update=force_update)
#

class ConcurrencyOptions:
_field = None
_versioned_save = False
Expand Down
2 changes: 0 additions & 2 deletions concurrency/forms.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
from __future__ import absolute_import, unicode_literals
import django
from django import forms
from django.core import validators
from django.core.exceptions import NON_FIELD_ERRORS, ImproperlyConfigured, ValidationError
from django.core.signing import Signer, BadSignature
from django.forms import ModelForm, HiddenInput
from django.utils import timezone
from django.utils.importlib import import_module
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _
Expand Down
23 changes: 0 additions & 23 deletions concurrency/models.py
Original file line number Diff line number Diff line change
@@ -1,23 +0,0 @@
from __future__ import absolute_import, unicode_literals
import logging
from django.db.models.signals import class_prepared
from concurrency.core import _wrap_model_save

logger = logging.getLogger(__name__)

__all__ = []

#
#def class_prepared_concurrency_handler(sender, **kwargs):
# if hasattr(sender, 'RevisionMetaInfo') and not (sender._concurrencymeta.manually):
# _wrap_model_save(sender)
# from concurrency.api import get_version, get_object_with_version
# setattr(sender._default_manager.__class__,
# 'get_object_with_version', get_object_with_version)
# setattr(sender, 'get_concurrency_version', get_version)
#
# else:
# logger.debug('Skipped concurrency for %s' % sender)
#
#
#class_prepared.connect(class_prepared_concurrency_handler, dispatch_uid='class_prepared_concurrency_handler')
32 changes: 18 additions & 14 deletions concurrency/tests/base.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import os
from django.test import TransactionTestCase
import django.core.management
from django.contrib.admin.options import ModelAdmin
from django.contrib.admin.sites import NotRegistered
import django.core.management
from django.contrib import admin
from django.conf import global_settings
from django.contrib.auth.models import User
from django.forms.models import modelform_factory
from django.test import TestCase
from django_webtest import WebTest

from django_webtest import WebTestMixin
from concurrency import forms
from concurrency.admin import ConcurrentModelAdmin
from concurrency.forms import ConcurrentForm, VersionWidget
Expand Down Expand Up @@ -76,7 +77,7 @@ def dummy_action(self, request, queryset):
el.save()


class AdminTestCase(WebTest):
class AdminTestCase(WebTestMixin, TransactionTestCase):
urls = 'concurrency.tests.urls'

def setUp(self):
Expand All @@ -86,31 +87,34 @@ def setUp(self):
is_active=True,
email='sax@example.com',
username='sax')
for i in range(1, 10):
ConcurrentModel.objects.get_or_create(id=i, version=0, dummy_char=str(i))
#for i in range(1, 10):
# ConcurrentModel.objects.get_or_create(id=i, defaults=dict(version=0, dummy_char=str(i)))

admin_register(ConcurrentModel, ActionsModelAdmin)
admin_register(ListEditableConcurrentModel, ListEditableModelAdmin)
admin_register(NoActionsConcurrentModel, NoActionsModelAdmin)
admin_register(TestModel1, TestModel1Admin)
admin_register(TestModel0, ModelAdmin)

def tearDown(self):
super(AdminTestCase, self).tearDown()


class DjangoAdminTestCase(TestCase):
class DjangoAdminTestCase(TransactionTestCase):
urls = 'concurrency.tests.urls'
MIDDLEWARE_CLASSES = global_settings.MIDDLEWARE_CLASSES
AUTHENTICATION_BACKENDS = global_settings.AUTHENTICATION_BACKENDS

def setUp(self):
super(DjangoAdminTestCase, self).setUp()
self.sett = self.settings(
#INSTALLED_APPS=INSTALLED_APPS,
MIDDLEWARE_CLASSES=self.MIDDLEWARE_CLASSES,
AUTHENTICATION_BACKENDS=self.AUTHENTICATION_BACKENDS,
PASSWORD_HASHERS=('django.contrib.auth.hashers.MD5PasswordHasher',), # fastest hasher
STATIC_URL='/static/',
SOUTH_TESTS_MIGRATE=False,
TEMPLATE_DIRS=(os.path.join(os.path.dirname(__file__), 'templates'),))
#INSTALLED_APPS=INSTALLED_APPS,
MIDDLEWARE_CLASSES=self.MIDDLEWARE_CLASSES,
AUTHENTICATION_BACKENDS=self.AUTHENTICATION_BACKENDS,
PASSWORD_HASHERS=('django.contrib.auth.hashers.MD5PasswordHasher',), # fastest hasher
STATIC_URL='/static/',
SOUTH_TESTS_MIGRATE=False,
TEMPLATE_DIRS=(os.path.join(os.path.dirname(__file__), 'templates'),))
self.sett.enable()
django.core.management._commands = None # reset commands cache
django.core.management.call_command('syncdb', verbosity=0)
Expand Down
3 changes: 3 additions & 0 deletions concurrency/tests/test_admin_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def _create_conflict(self, pk):
u.save()

def test_dummy_action(self):
ConcurrentModel.objects.get_or_create(id=1)
res = self.app.get('/admin/', user='sax')
res = res.click('^ConcurrentModels')
assert 'ConcurrentModel #1' in res # sanity check
Expand All @@ -27,6 +28,7 @@ def test_dummy_action(self):
self.assertNotIn('**action_update**', res)

def test_delete_allowed_if_no_updates(self):
ConcurrentModel.objects.get_or_create(id=1)
res = self.app.get('/admin/', user='sax')
res = res.click('^ConcurrentModels')
assert 'ConcurrentModel #1' in res # sanity check
Expand All @@ -42,6 +44,7 @@ def test_delete_allowed_if_no_updates(self):
self.assertNotIn('ConcurrentModel #1', res)

def test_delete_not_allowed_if_updates(self):
ConcurrentModel.objects.get_or_create(id=1)
res = self.app.get('/admin/', user='sax')
res = res.click('^ConcurrentModels')
assert 'ConcurrentModel #1' in res # sanity check
Expand Down
13 changes: 4 additions & 9 deletions concurrency/tests/test_admin_edit.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
from django.contrib.admin import site, ModelAdmin
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext as _
from concurrency.admin import ConcurrentModelAdmin
from concurrency.forms import VersionFieldSigner
from concurrency.tests.base import AdminTestCase, SENTINEL
from concurrency.tests.models import TestModel1, TestModel0, ConcurrentModel


class TestConcurrentModelAdmin(AdminTestCase):
def setUp(self):
super(TestConcurrentModelAdmin, self).setUp()
assert isinstance(site._registry[ConcurrentModel], ConcurrentModelAdmin)

def test_standard_update(self):
target, __ = ConcurrentModel.objects.get_or_create(dummy_char='aaa')
Expand Down Expand Up @@ -38,8 +33,8 @@ def test_conflict(self):
target, __ = ConcurrentModel.objects.get_or_create(dummy_char='aaa')
url = reverse('admin:concurrency_concurrentmodel_change', args=[target.pk])
res = self.app.get(url, user='sax')
form = res.form

form = res.form
target.save() # create conflict here

res = form.submit()
Expand All @@ -52,9 +47,9 @@ def test_conflict(self):


class TestAdminEdit(AdminTestCase):
def setUp(self):
super(TestAdminEdit, self).setUp()
assert isinstance(site._registry[TestModel1], ModelAdmin)
#def setUp(self):
# super(TestAdminEdit, self).setUp()
# assert isinstance(site._registry[TestModel1], ModelAdmin)

def _create_conflict(self, pk):
u = TestModel1.objects.get(pk=pk)
Expand Down
19 changes: 15 additions & 4 deletions concurrency/tests/test_admin_list_editable.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
from django.db import transaction
from django.contrib.admin.models import LogEntry
from django.contrib.contenttypes.models import ContentType
from django.utils.encoding import force_text
Expand All @@ -17,6 +18,7 @@ def _create_conflict(self, pk):
u.save()

def test_normal_add(self):
#self.TARGET.objects.get_or_create(pk=1)
res = self.app.get('/admin/', user='sax')
res = res.click(self.TARGET._meta.verbose_name_plural)
res = res.click('Add')
Expand All @@ -25,6 +27,7 @@ def test_normal_add(self):
res = form.submit().follow()

def test_normal_update(self):
self.TARGET.objects.get_or_create(pk=1)
res = self.app.get('/admin/', user='sax')
res = res.click(self.TARGET._meta.verbose_name_plural)
form = res.forms['changelist-form']
Expand All @@ -33,10 +36,11 @@ def test_normal_update(self):
self.assertTrue(self.TARGET.objects.filter(dummy_char='CHAR').exists())

def test_concurrency(self):
self.TARGET.objects.get_or_create(pk=8)

res = self.app.get('/admin/', user='sax')
res = res.click(self.TARGET._meta.verbose_name_plural)

self._create_conflict(1)
self._create_conflict(8)

form = res.forms['changelist-form']
form['form-0-dummy_char'] = 'CHAR'
Expand All @@ -45,6 +49,8 @@ def test_concurrency(self):
self.assertFalse(self.TARGET.objects.filter(dummy_char='CHAR').exists())

def test_message_user(self):
self.TARGET.objects.get_or_create(pk=1)
self.TARGET.objects.get_or_create(pk=2)
res = self.app.get('/admin/', user='sax')
res = res.click(self.TARGET._meta.verbose_name_plural)

Expand All @@ -63,10 +69,12 @@ def test_message_user(self):
messages)

def test_message_user_no_changes(self):
self.TARGET.objects.get_or_create(pk=5)

res = self.app.get('/admin/', user='sax')
res = res.click(self.TARGET._meta.verbose_name_plural)

self._create_conflict(1)
self._create_conflict(5)

form = res.forms['changelist-form']
form['form-0-dummy_char'] = 'CHAR1'
Expand All @@ -79,20 +87,23 @@ def test_message_user_no_changes(self):
self.assertEqual(len(messages), 1)

def test_log_change(self):
self.TARGET.objects.get_or_create(pk=10)

res = self.app.get('/admin/', user='sax')
res = res.click(self.TARGET._meta.verbose_name_plural)
log_filter = dict(user__username='sax',
content_type=ContentType.objects.get_for_model(self.TARGET))

logs = list(LogEntry.objects.filter(**log_filter).values_list('pk', flat=True))

self._create_conflict(1)
self._create_conflict(10)

form = res.forms['changelist-form']
form['form-0-dummy_char'] = 'CHAR1'
res = form.submit('_save').follow()
new_logs = LogEntry.objects.filter(**log_filter).exclude(id__in=logs).exists()
self.assertFalse(new_logs, "LogEntry created even if conflict error")
transaction.rollback()


class TestListEditableWithNoActions(TestListEditable):
Expand Down
3 changes: 0 additions & 3 deletions concurrency/tests/test_api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from unittest import skipIf
import django
from django.test import TestCase
from concurrency.api import (is_changed, get_revision_of_object,
get_version, get_object_with_version, disable_sanity_check)
Expand All @@ -26,7 +24,6 @@ def test_get_object_version(self):
o1 = TestModel0.objects.create()
self.assertEqual(get_object_with_version(TestModel0.objects, o1.pk, o1.version), o1)


def test_patched_get_version(self):
o1 = TestModel0.objects.create()
self.assertEqual(o1.get_concurrency_version(o1.version), o1)
Expand Down
Loading

0 comments on commit 755d925

Please sign in to comment.