-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added the check framework integration for remote api models and fields.
- Loading branch information
darius BERNARD
committed
Jan 6, 2017
1 parent
2b4982a
commit 9734dc3
Showing
17 changed files
with
363 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
# -*- coding: utf-8 -*- | ||
from __future__ import unicode_literals, absolute_import, print_function | ||
|
||
import logging | ||
from rest_models.checks import register_checks | ||
|
||
logger = logging.getLogger(__name__) | ||
register_checks() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
# -*- coding: utf-8 -*- | ||
from __future__ import absolute_import, print_function, unicode_literals | ||
|
||
import logging | ||
|
||
from django.apps import apps | ||
from django.core.checks import Error, Tags, register | ||
|
||
from rest_models.backend.compiler import get_resource_path | ||
from rest_models.router import RestModelRouter | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def api_struct_check(app_configs, **kwargs): | ||
errors = [] | ||
|
||
all_models = [] | ||
if app_configs is None: | ||
all_models.extend(apps.get_models()) | ||
else: | ||
for app_config in app_configs: | ||
all_models.extend(app_config.get_models()) | ||
router = RestModelRouter() | ||
models = ((router.get_api_connexion(model).cursor(), model) | ||
for model in all_models if router.is_api_model(model)) | ||
|
||
for db, rest_model in models: | ||
url = get_resource_path(rest_model) | ||
res = db.options(url) | ||
if res.status_code != 200: | ||
errors.append( | ||
Error( | ||
'the remote api does not respond to us. OPTIONS %s/%s => %s' % (db.url, url, res.status_code), | ||
hint='check the url for the remote api or the resource_path', | ||
obj=rest_model, | ||
id='rest_models.E001' | ||
) | ||
) | ||
continue | ||
options = res.json() | ||
missings = { | ||
'include[]', 'exclude[]', 'filter{}', 'page', 'per_page', 'sort[]' | ||
} - set(options.get("features", [])) | ||
if missings: | ||
errors.append( | ||
Error( | ||
'the remote api does not support the folowing features: %s' % missings, | ||
hint='is the api on %s/%s running with dynamic-rest ?' % (db.url, url), | ||
obj=rest_model, | ||
id='rest_models.E002' | ||
) | ||
) | ||
continue | ||
for field in rest_model._meta.get_fields(): | ||
if field.is_relation: | ||
if router.is_api_model(field.related_model): | ||
if field.name not in options['properties']: | ||
errors.append( | ||
Error( | ||
'the field %s.%s in not present on the remote serializer' % ( | ||
rest_model.__name__, field.name | ||
), | ||
obj="%s.%s" % (rest_model.__name__, field.name), | ||
hint='check if the serializer on %s/%s has a field "%s"' % (db.url, url, field.name), | ||
id='rest_models.E003' | ||
) | ||
) | ||
elif field.name not in options['properties']: | ||
errors.append( | ||
Error( | ||
'the field %s.%s in not present on the remote serializer' % (rest_model.__name__, field.name), | ||
hint='check if the serializer on %s/%s has a field "%s"' % (db.url, url, field.name), | ||
id='rest_models.E003' | ||
) | ||
) | ||
return errors | ||
|
||
|
||
def register_checks(): | ||
register(api_struct_check, Tags.models) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# -*- coding: utf-8 -*- | ||
from __future__ import absolute_import, print_function, unicode_literals | ||
|
||
import logging | ||
|
||
from django.core.management import call_command | ||
from django.core.management.base import SystemCheckError | ||
from django.db.utils import ProgrammingError | ||
from django.test.testcases import TestCase | ||
from django.test.utils import modify_settings, override_settings | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
@override_settings(ROOT_URLCONF='testapi.badapi.urls') | ||
@modify_settings(INSTALLED_APPS={ | ||
'append': ['testapi.badapi', 'testapp.badapp'], | ||
}) | ||
class SystemCheckTest(TestCase): | ||
|
||
fixtures = ['user.json'] | ||
|
||
@classmethod | ||
def setUpClass(cls): | ||
super(SystemCheckTest, cls).setUpClass() | ||
call_command( | ||
'migrate', | ||
verbosity=0, | ||
interactive=False, | ||
test_flush=True) | ||
|
||
def setUp(self): | ||
from testapp.badapp import models | ||
self.models = models | ||
|
||
def test_query_ok(self): | ||
self.assertEqual(0, self.models.AA.objects.filter(a__name='a').all().count()) | ||
|
||
def test_query_fail(self): | ||
with self.assertRaisesMessage(ProgrammingError, 'Invalid filter field: aa'): | ||
self.assertEqual(0, self.models.A.objects.filter(aa__name='a').all().count()) | ||
|
||
def test_check_all_error(self): | ||
with self.assertRaises(SystemCheckError) as ctx: | ||
call_command('check') | ||
msg = ctx.exception.args[0] | ||
self.assertIn('has a field "aa"', msg) | ||
self.assertIn('has a field "bb"', msg) | ||
self.assertIn('OPTIONS http://localapi/api/v1/c => 404', msg) | ||
|
||
def test_check_one_error(self): | ||
with self.assertRaises(SystemCheckError) as ctx: | ||
call_command('check', 'badapp') | ||
msg = ctx.exception.args[0] | ||
self.assertIn('has a field "aa"', msg) | ||
self.assertIn('has a field "bb"', msg) | ||
self.assertIn('OPTIONS http://localapi/api/v1/c => 404', msg) | ||
|
||
def test_check_one_ok(self): | ||
call_command('check', 'testapp') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
from __future__ import unicode_literals | ||
|
||
import doctest | ||
import os | ||
import tempfile | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +0,0 @@ | ||
# -*- coding: utf-8 -*- | ||
from __future__ import unicode_literals, absolute_import, print_function | ||
|
||
import logging | ||
|
||
logger = logging.getLogger(__name__) | ||
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# -*- coding: utf-8 -*- | ||
from __future__ import absolute_import, print_function, unicode_literals | ||
|
||
import datetime | ||
import logging | ||
|
||
from django.db import models | ||
from django.utils import timezone | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def auto_now_plus_5d(): | ||
return timezone.now() + datetime.timedelta(days=5) | ||
|
||
|
||
class A(models.Model): | ||
name = models.CharField(max_length=135) | ||
|
||
def __str__(self): | ||
return self.name # pragma: no cover | ||
|
||
|
||
class B(models.Model): | ||
name = models.CharField(max_length=135) | ||
|
||
def __str__(self): | ||
return self.name # pragma: no cover | ||
|
||
|
||
class C(models.Model): | ||
name = models.CharField(max_length=135) | ||
|
||
def __str__(self): | ||
return self.name # pragma: no cover | ||
|
||
|
||
class AA(models.Model): | ||
name = models.CharField(max_length=135) | ||
a = models.ForeignKey(A, related_name='aa') | ||
|
||
def __str__(self): | ||
return self.name # pragma: no cover | ||
|
||
|
||
class BB(models.Model): | ||
name = models.CharField(max_length=135) | ||
b = models.ManyToManyField(B, related_name='bb') | ||
|
||
def __str__(self): | ||
return self.name # pragma: no cover |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# -*- coding: utf-8 -*- | ||
from __future__ import absolute_import, print_function, unicode_literals | ||
|
||
from dynamic_rest.fields.fields import DynamicRelationField | ||
from dynamic_rest.serializers import DynamicModelSerializer | ||
|
||
from testapi.badapi.models import AA, BB, A, B | ||
|
||
|
||
class ASerializer(DynamicModelSerializer): | ||
class Meta: | ||
model = A | ||
name = 'a' | ||
fields = ('id', 'name') | ||
|
||
|
||
class BSerializer(DynamicModelSerializer): | ||
class Meta: | ||
model = B | ||
name = 'b' | ||
fields = ('id', 'name') | ||
|
||
|
||
class AASerializer(DynamicModelSerializer): | ||
a = DynamicRelationField(ASerializer, many=False) | ||
|
||
class Meta: | ||
model = AA | ||
name = 'aa' | ||
fields = ('id', 'name', 'a') | ||
|
||
|
||
class BBSerializer(DynamicModelSerializer): | ||
b = DynamicRelationField(BSerializer, many=True) | ||
|
||
class Meta: | ||
model = BB | ||
name = 'bb' | ||
fields = ('id', 'name', 'b') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# -*- coding: utf-8 -*- | ||
from __future__ import absolute_import, print_function, unicode_literals | ||
|
||
from django.conf.urls import include, url | ||
from dynamic_rest.routers import DynamicRouter | ||
|
||
from .viewset import AAViewSet, AViewSet, BBViewSet, BViewSet | ||
|
||
router = DynamicRouter() | ||
router.register('/a', AViewSet) | ||
router.register('/aa', AAViewSet) | ||
router.register('/b', BViewSet) | ||
|
||
router.register('/bb', BBViewSet) | ||
|
||
urlpatterns = [ | ||
url(r'^api/v1', include(router.urls)), | ||
url(r'', include('testapi.urls')), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# -*- coding: utf-8 -*- | ||
from __future__ import absolute_import, print_function, unicode_literals | ||
|
||
from dynamic_rest.viewsets import DynamicModelViewSet | ||
|
||
from .models import AA, BB, A, B | ||
from .serializers import AASerializer, ASerializer, BBSerializer, BSerializer | ||
|
||
|
||
class AViewSet(DynamicModelViewSet): | ||
serializer_class = ASerializer | ||
queryset = A.objects.all() | ||
|
||
|
||
class AAViewSet(DynamicModelViewSet): | ||
serializer_class = AASerializer | ||
queryset = AA.objects.all() | ||
|
||
|
||
class BViewSet(DynamicModelViewSet): | ||
serializer_class = BSerializer | ||
queryset = B.objects.all() | ||
|
||
|
||
class BBViewSet(DynamicModelViewSet): | ||
serializer_class = BBSerializer | ||
queryset = BB.objects.all() |
Empty file.
Oops, something went wrong.