Skip to content

Commit

Permalink
Merge pull request #528 from uktrade/release/vodka
Browse files Browse the repository at this point in the history
Release vodka
  • Loading branch information
marcofucci authored Oct 10, 2017
2 parents 892ed88 + 8dac17f commit 2ff7e07
Show file tree
Hide file tree
Showing 47 changed files with 1,547 additions and 571 deletions.
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ jobs:
docker:
- image: python:3.6

- image: elasticsearch:2.3
- image: elasticsearch:5.5

- image: postgres:9.5
environment:
Expand All @@ -17,7 +17,7 @@ jobs:
DJANGO_SECRET_KEY: changeme
DJANGO_SETTINGS_MODULE: config.settings.local
ES_INDEX: test_index
ES_URL: http://localhost:9200
ES5_URL: http://localhost:9200
CDMS_AUTH_URL: http://example.com
AWS_DEFAULT_REGION: eu-west-2
AWS_ACCESS_KEY_ID: foo
Expand Down
5 changes: 3 additions & 2 deletions config/settings/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'DIRS': [(ROOT_DIR - 1)('templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
Expand Down Expand Up @@ -149,6 +149,7 @@
# https://docs.djangoproject.com/en/1.9/topics/i18n/

LANGUAGE_CODE = 'en-gb'
USE_L10N = True
PUBLIC_ROOT = str(ROOT_DIR('public'))
STATIC_ROOT = str(ROOT_DIR('staticfiles'))
STATIC_URL = '/static/'
Expand Down Expand Up @@ -180,7 +181,7 @@
APPEND_SLASH = False

# Leeloo stuff
ES_URL = env('ES_URL')
ES_URL = env('ES5_URL')
ES_VERIFY_CERTS = env.bool('ES_VERIFY_CERTS', True)
ES_INDEX = env('ES_INDEX')
ES_INDEX_SETTINGS = {
Expand Down
2 changes: 1 addition & 1 deletion config/settings/sample.env
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
DJANGO_SECRET_KEY=dev
DEBUG=True
DATABASE_URL=postgres://localhost/datahub
ES_URL=http://localhost:9200
ES5_URL=http://localhost:9200
ES_INDEX=test
DATAHUB_SECRET=secret
CDMS_AUTH_URL=http://example.com
Expand Down
4 changes: 2 additions & 2 deletions datahub/company/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
Advisor, CompaniesHouseCompany, Company, Contact
)
from datahub.core.serializers import NestedRelatedField
from datahub.core.validate_utils import RequiredUnlessAlreadyBlank
from datahub.core.validators import RequiredUnlessAlreadyBlankValidator
from datahub.interaction.models import Interaction
from datahub.metadata import models as meta_models

Expand Down Expand Up @@ -301,4 +301,4 @@ class Meta: # noqa: D101
'archived_on': {'read_only': True},
'archived_reason': {'read_only': True}
}
validators = [RequiredUnlessAlreadyBlank('sector', 'business_type')]
validators = [RequiredUnlessAlreadyBlankValidator('sector', 'business_type')]
23 changes: 23 additions & 0 deletions datahub/core/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,29 @@
from django.contrib import admin
from reversion.admin import VersionAdmin


class DisabledOnFilter(admin.SimpleListFilter):
"""This filter allows us to filter values that have disabled_on value."""

title = 'Is disabled'
parameter_name = 'disabled_on'

def lookups(self, request, model_admin):
"""Returns parameters."""
return (
('yes', 'Yes'),
('no', 'No'),
)

def queryset(self, request, queryset):
"""Modify query according to filter parameter."""
value = self.value()
if value is not None:
is_disabled = True if value == 'yes' else False
return queryset.filter(disabled_on__isnull=(not is_disabled))
return queryset


class ConfigurableVersionAdmin(VersionAdmin):
"""
Subclass of VersionAdmin that allows the excluded model fields for django-reversion
Expand Down
79 changes: 1 addition & 78 deletions datahub/core/test/test_validate_utils.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,8 @@
from types import SimpleNamespace
from unittest.mock import MagicMock, Mock

import pytest
from rest_framework.exceptions import ValidationError

from datahub.core.validate_utils import (
AnyOfValidator, DataCombiner, is_blank, RequiredUnlessAlreadyBlank
)


def test_any_of_none():
"""Tests that validation fails if no any-of fields provided."""
instance = SimpleNamespace(field_a=None, field_b=None)
validator = AnyOfValidator('field_a', 'field_b')
validator.set_context(Mock(instance=instance))
with pytest.raises(ValidationError):
validator({})


def test_any_of_some():
"""Tests that validation passes if some any-of fields provided."""
instance = SimpleNamespace(field_a=None, field_b=None)
validator = AnyOfValidator('field_a', 'field_b')
validator.set_context(Mock(instance=instance))
validator({'field_a': Mock()})


def test_any_of_all():
"""Tests that validation passes if all any-of fields provided."""
instance = SimpleNamespace(field_a=None, field_b=None)
validator = AnyOfValidator('field_a', 'field_b')
validator.set_context(Mock(instance=instance))
validator({'field_a': Mock(), 'field_b': Mock()})
from datahub.core.validate_utils import DataCombiner, is_blank


@pytest.mark.parametrize('value,blank', (
Expand Down Expand Up @@ -96,51 +67,3 @@ def test_get_value_id_value(self):
instance = Mock(field1=subinstance)
data_combiner = DataCombiner(instance, {'field1': new_subinstance})
assert data_combiner.get_value_id('field1') == str(new_subinstance.id)


class TestRequiredUnlessAlreadyBlank:
"""RequiredUnlessAlreadyBlank tests."""

@pytest.mark.parametrize('create_data,update_data,partial,should_raise', (
({'field1': None}, {'field1': None}, False, False),
({'field1': None}, {'field1': None}, True, False),
({'field1': None}, {'field1': 'blah'}, False, False),
({'field1': None}, {'field1': 'blah'}, True, False),
({'field1': None}, {}, False, False),
({'field1': None}, {}, True, False),
({'field1': 'blah'}, {'field1': None}, False, True),
({'field1': 'blah'}, {'field1': None}, True, True),
({'field1': 'blah'}, {'field1': 'blah'}, False, False),
({'field1': 'blah'}, {'field1': 'blah'}, True, False),
({'field1': 'blah'}, {}, False, True),
({'field1': 'blah'}, {}, True, False),
))
def test_update(self, create_data, update_data, partial, should_raise):
"""Tests validation during updates."""
instance = Mock(**create_data)
serializer = Mock(instance=instance, partial=partial)
validator = RequiredUnlessAlreadyBlank('field1')
validator.set_context(serializer)
if should_raise:
with pytest.raises(ValidationError) as excinfo:
validator(update_data)
assert excinfo.value.detail['field1'] == validator.required_message
else:
validator(update_data)

@pytest.mark.parametrize('create_data,should_raise', (
({}, True),
({'field1': None}, True),
({'field1': 'blah'}, False),
))
def test_create(self, create_data, should_raise):
"""Tests validation during instance creation."""
serializer = Mock(instance=None, partial=False)
validator = RequiredUnlessAlreadyBlank('field1')
validator.set_context(serializer)
if should_raise:
with pytest.raises(ValidationError) as excinfo:
validator(create_data)
assert excinfo.value.detail['field1'] == validator.required_message
else:
validator(create_data)
155 changes: 155 additions & 0 deletions datahub/core/test/test_validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
from operator import eq
from types import SimpleNamespace
from unittest.mock import Mock

import pytest
from rest_framework.exceptions import ValidationError

from datahub.core.validate_utils import DataCombiner
from datahub.core.validators import (
AnyOfValidator, Condition, RequiredUnlessAlreadyBlankValidator, RulesBasedValidator,
ValidationRule
)


def test_any_of_none():
"""Tests that validation fails if no any-of fields provided."""
instance = SimpleNamespace(field_a=None, field_b=None)
validator = AnyOfValidator('field_a', 'field_b')
validator.set_context(Mock(instance=instance))
with pytest.raises(ValidationError):
validator({})


def test_any_of_some():
"""Tests that validation passes if some any-of fields provided."""
instance = SimpleNamespace(field_a=None, field_b=None)
validator = AnyOfValidator('field_a', 'field_b')
validator.set_context(Mock(instance=instance))
validator({'field_a': Mock()})


def test_any_of_all():
"""Tests that validation passes if all any-of fields provided."""
instance = SimpleNamespace(field_a=None, field_b=None)
validator = AnyOfValidator('field_a', 'field_b')
validator.set_context(Mock(instance=instance))
validator({'field_a': Mock(), 'field_b': Mock()})


@pytest.mark.parametrize('data,field,op,args,res', (
({'colour': 'red'}, 'colour', eq, ('red',), True),
({'colour': 'red'}, 'colour', eq, ('blue',), False),
))
def test_validation_condition(data, field, op, args, res):
"""Tests ValidationCondition for various cases."""
combiner = Mock(spec_set=DataCombiner, get_value=lambda field_: data[field_])
condition = Condition(field, op, args)
assert condition(combiner) == res


@pytest.mark.parametrize('data,field,op,condition,res', (
({'colour': 'red', 'valid': True}, 'valid', bool, lambda x: True, True),
({'colour': 'red', 'valid': False}, 'valid', bool, lambda x: True, False),
({'colour': 'red', 'valid': True}, 'valid', bool, lambda x: False, True),
({'colour': 'red', 'valid': False}, 'valid', bool, lambda x: False, True),
))
def test_validation_rule(data, field, op, condition, res):
"""Tests ValidationRule for various cases."""
combiner = Mock(spec_set=DataCombiner, get_value=lambda field_: data[field_])
rule = ValidationRule(
'error_key', field, op, condition=condition
)
assert rule(combiner) == res


def _make_stub_rule(field, return_value):
return Mock(return_value=return_value, error_key='error', rule=Mock(field=field))


class TestRulesBasedValidator:
"""RulesBasedValidator tests."""

@pytest.mark.parametrize('rules', (
(_make_stub_rule('field1', True),),
(_make_stub_rule('field1', True), _make_stub_rule(True, 'field2')),
))
def test_validation_passes(self, rules):
"""Test that validation passes when the rules pass."""
instance = Mock()
serializer = Mock(instance=instance, error_messages={'error': 'test error'})
validator = RulesBasedValidator(*rules)
validator.set_context(serializer)
assert validator({}) is None

@pytest.mark.parametrize('rules,errors', (
(
(_make_stub_rule('field1', False),),
{'field1': 'test error'}
),
(
(_make_stub_rule('field1', False), _make_stub_rule('field2', False),),
{'field1': 'test error', 'field2': 'test error'}
),
(
(_make_stub_rule('field1', False), _make_stub_rule('field2', True),),
{'field1': 'test error'}
),
))
def test_validation_fails(self, rules, errors):
"""Test that validation fails when any rule fails."""
instance = Mock()
serializer = Mock(instance=instance, error_messages={'error': 'test error'})
validator = RulesBasedValidator(*rules)
validator.set_context(serializer)
with pytest.raises(ValidationError) as excinfo:
validator({})
assert excinfo.value.detail == errors


class TestRequiredUnlessAlreadyBlankValidator:
"""RequiredUnlessAlreadyBlank tests."""

@pytest.mark.parametrize('create_data,update_data,partial,should_raise', (
({'field1': None}, {'field1': None}, False, False),
({'field1': None}, {'field1': None}, True, False),
({'field1': None}, {'field1': 'blah'}, False, False),
({'field1': None}, {'field1': 'blah'}, True, False),
({'field1': None}, {}, False, False),
({'field1': None}, {}, True, False),
({'field1': 'blah'}, {'field1': None}, False, True),
({'field1': 'blah'}, {'field1': None}, True, True),
({'field1': 'blah'}, {'field1': 'blah'}, False, False),
({'field1': 'blah'}, {'field1': 'blah'}, True, False),
({'field1': 'blah'}, {}, False, True),
({'field1': 'blah'}, {}, True, False),
))
def test_update(self, create_data, update_data, partial, should_raise):
"""Tests validation during updates."""
instance = Mock(**create_data)
serializer = Mock(instance=instance, partial=partial)
validator = RequiredUnlessAlreadyBlankValidator('field1')
validator.set_context(serializer)
if should_raise:
with pytest.raises(ValidationError) as excinfo:
validator(update_data)
assert excinfo.value.detail['field1'] == validator.required_message
else:
validator(update_data)

@pytest.mark.parametrize('create_data,should_raise', (
({}, True),
({'field1': None}, True),
({'field1': 'blah'}, False),
))
def test_create(self, create_data, should_raise):
"""Tests validation during instance creation."""
serializer = Mock(instance=None, partial=False)
validator = RequiredUnlessAlreadyBlankValidator('field1')
validator.set_context(serializer)
if should_raise:
with pytest.raises(ValidationError) as excinfo:
validator(create_data)
assert excinfo.value.detail['field1'] == validator.required_message
else:
validator(create_data)
40 changes: 40 additions & 0 deletions datahub/core/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import pytest
from django.contrib.auth import get_user_model
from django.test.client import Client
from django.utils.timezone import now
from oauth2_provider.models import AccessToken, Application
from rest_framework.test import APIClient
Expand All @@ -27,6 +28,45 @@ def get_test_user():
return test_user


def get_admin_user(password=None):
"""Return the test admin user."""
email = '[email protected]'
user_model = get_user_model()
try:
admin_user = user_model.objects.get(email=email)
except user_model.DoesNotExist:
admin_user = user_model.objects.create_superuser(email=email, password=password)
return admin_user


class AdminTestMixin:
"""All the tests using the DB and accessing admin endpoints should use this class."""

pytestmark = pytest.mark.django_db # use db

PASSWORD = 'password'

@property
def user(self):
"""Returns admin user."""
if not hasattr(self, '_user'):
self._user = get_admin_user(self.PASSWORD)
return self._user

@property
def client(self):
"""Returns an authenticated admin client."""
return self.create_client()

def create_client(self, user=None):
"""Creates a client with admin access."""
if not user:
user = self.user
client = Client()
client.login(username=user.email, password=self.PASSWORD)
return client


class APITestMixin:
"""All the tests using the DB and accessing end points behind auth should use this class."""

Expand Down
Loading

0 comments on commit 2ff7e07

Please sign in to comment.