Skip to content

Commit 888eb1c

Browse files
authored
Merge branch 'master' into stable/1.0.x
2 parents 02c8f0a + 3ae5865 commit 888eb1c

12 files changed

+520
-14
lines changed

requirements/base.in

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
Pillow
21
pip-tools
32
psycopg2-binary
43
python-dotenv
@@ -17,4 +16,4 @@ django-markup==1.3
1716
django_redis
1817

1918
djangorestframework
20-
vng-api-common<1.1.0
19+
vng-api-common

requirements/base.txt

+5-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ django-filter==2.1.0 # via vng-api-common
1919
django-ipware==2.1.0 # via django-axes
2020
django-markup==1.3
2121
django-redis==4.10.0
22+
django-rest-framework-condition==0.1.1 # via vng-api-common
2223
django-solo==1.1.3 # via vng-api-common
2324
django==2.2.8
2425
djangorestframework-camel-case==0.2.0 # via vng-api-common
@@ -38,7 +39,6 @@ markdown==3.1
3839
markupsafe==1.1.1 # via jinja2
3940
oyaml==0.7 # via vng-api-common
4041
packaging==19.0 # via sphinx
41-
pillow==5.2.0
4242
pip-tools==4.2.0
4343
psycopg2-binary==2.7.5
4444
pygments==2.3.1 # via sphinx
@@ -61,4 +61,7 @@ sqlparse==0.3.0 # via django
6161
unidecode==1.0.22 # via vng-api-common
6262
uritemplate==3.0.0 # via coreapi, drf-yasg
6363
urllib3==1.24.3 # via requests
64-
vng-api-common==1.0.34
64+
vng-api-common==1.4.4
65+
66+
# The following packages are considered to be unsafe in a requirements file:
67+
# setuptools==42.0.2 # via markdown, sphinx

requirements/jenkins.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ django-ipware==2.1.0
2222
django-jenkins==0.110.0
2323
django-markup==1.3
2424
django-redis==4.10.0
25+
django-rest-framework-condition==0.1.1
2526
django-solo==1.1.3
2627
django==2.2.8
2728
djangorestframework-camel-case==0.2.0
@@ -48,7 +49,6 @@ mccabe==0.6.1 # via pylint
4849
oyaml==0.7
4950
packaging==19.0
5051
pep8==1.7.1
51-
pillow==5.2.0
5252
pip-tools==4.2.0
5353
psycopg2-binary==2.7.5
5454
pygments==2.3.1
@@ -75,5 +75,5 @@ text-unidecode==1.2 # via faker
7575
unidecode==1.0.22
7676
uritemplate==3.0.0
7777
urllib3==1.24.3
78-
vng-api-common==1.0.34
78+
vng-api-common==1.4.4
7979
wrapt==1.10.11 # via astroid

src/brc/api/tests/test_besluit.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
from rest_framework.test import APITestCase
33
from vng_api_common.tests import JWTAuthMixin, get_operation_url, get_validation_errors
44

5-
from brc.datamodel.models import BesluitInformatieObject
6-
from brc.datamodel.tests.factories import BesluitFactory, BesluitInformatieObjectFactory
5+
from brc.datamodel.tests.factories import BesluitFactory
76

87
from .mixins import MockSyncMixin
98

src/brc/api/tests/test_caching.py

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
"""
2+
Test that the caching mechanisms are in place.
3+
"""
4+
from rest_framework import status
5+
from rest_framework.test import APITestCase, APITransactionTestCase
6+
from vng_api_common.tests import CacheMixin, JWTAuthMixin, generate_jwt_auth, reverse
7+
from vng_api_common.tests.schema import get_spec
8+
9+
from brc.datamodel.tests.factories import BesluitFactory, BesluitInformatieObjectFactory
10+
11+
from .mixins import MockSyncMixin
12+
13+
14+
class BesluitCacheTests(CacheMixin, JWTAuthMixin, APITestCase):
15+
heeft_alle_autorisaties = True
16+
17+
def test_besluit_get_cache_header(self):
18+
besluit = BesluitFactory.create()
19+
20+
response = self.client.get(reverse(besluit))
21+
22+
self.assertHasETag(response)
23+
24+
def test_besluit_head_cache_header(self):
25+
besluit = BesluitFactory.create()
26+
27+
self.assertHeadHasETag(reverse(besluit))
28+
29+
def test_head_in_apischema(self):
30+
spec = get_spec()
31+
32+
endpoint = spec["paths"]["/besluiten/{uuid}"]
33+
34+
self.assertIn("head", endpoint)
35+
36+
def test_conditional_get_304(self):
37+
besluit = BesluitFactory.create(with_etag=True)
38+
response = self.client.get(
39+
reverse(besluit), HTTP_IF_NONE_MATCH=f'"{besluit._etag}"'
40+
)
41+
42+
self.assertEqual(response.status_code, status.HTTP_304_NOT_MODIFIED)
43+
44+
def test_conditional_get_stale(self):
45+
besluit = BesluitFactory.create(with_etag=True)
46+
47+
response = self.client.get(reverse(besluit), HTTP_IF_NONE_MATCH=f'"not-an-md5"')
48+
49+
self.assertEqual(response.status_code, status.HTTP_200_OK)
50+
51+
52+
class BesluitInformatieObjectCacheTests(
53+
MockSyncMixin, CacheMixin, JWTAuthMixin, APITestCase
54+
):
55+
heeft_alle_autorisaties = True
56+
57+
def test_besluit_get_cache_header(self):
58+
bio = BesluitInformatieObjectFactory.create()
59+
60+
response = self.client.get(reverse(bio))
61+
62+
self.assertHasETag(response)
63+
64+
def test_besluit_head_cache_header(self):
65+
bio = BesluitInformatieObjectFactory.create()
66+
67+
self.assertHeadHasETag(reverse(bio))
68+
69+
def test_head_in_apischema(self):
70+
spec = get_spec()
71+
72+
endpoint = spec["paths"]["/besluitinformatieobjecten/{uuid}"]
73+
74+
self.assertIn("head", endpoint)
75+
76+
def test_conditional_get_304(self):
77+
bio = BesluitInformatieObjectFactory.create(with_etag=True)
78+
response = self.client.get(reverse(bio), HTTP_IF_NONE_MATCH=f'"{bio._etag}"')
79+
80+
self.assertEqual(response.status_code, status.HTTP_304_NOT_MODIFIED)
81+
82+
def test_conditional_get_stale(self):
83+
bio = BesluitInformatieObjectFactory.create(with_etag=True)
84+
85+
response = self.client.get(reverse(bio), HTTP_IF_NONE_MATCH=f'"not-an-md5"')
86+
87+
self.assertEqual(response.status_code, status.HTTP_200_OK)
88+
89+
90+
class BesluitCacheTransactionTests(JWTAuthMixin, APITransactionTestCase):
91+
heeft_alle_autorisaties = True
92+
93+
def setUp(self):
94+
super().setUp()
95+
self._create_credentials(
96+
self.client_id,
97+
self.secret,
98+
self.heeft_alle_autorisaties,
99+
self.max_vertrouwelijkheidaanduiding,
100+
)
101+
102+
def test_invalidate_etag_after_change(self):
103+
"""
104+
Because changes are made to the besluit, a code 200 should be returned
105+
"""
106+
besluit = BesluitFactory.create(toelichting="", with_etag=True)
107+
etag = besluit._etag
108+
109+
besluit.toelichting = "bla"
110+
besluit.save()
111+
112+
response = self.client.get(reverse(besluit), HTTP_IF_NONE_MATCH=f"{etag}")
113+
self.assertEqual(response.status_code, status.HTTP_200_OK)

src/brc/api/viewsets.py

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
AuditTrailViewSet,
99
AuditTrailViewsetMixin,
1010
)
11+
from vng_api_common.caching import conditional_retrieve
1112
from vng_api_common.notifications.viewsets import (
1213
NotificationCreateMixin,
1314
NotificationDestroyMixin,
@@ -31,6 +32,7 @@
3132
from .serializers import BesluitInformatieObjectSerializer, BesluitSerializer
3233

3334

35+
@conditional_retrieve()
3436
class BesluitViewSet(
3537
NotificationViewSetMixin,
3638
CheckQueryParamsMixin,
@@ -119,6 +121,7 @@ class BesluitViewSet(
119121
audit = AUDIT_BRC
120122

121123

124+
@conditional_retrieve()
122125
class BesluitInformatieObjectViewSet(
123126
NotificationCreateMixin,
124127
NotificationDestroyMixin,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Generated by Django 2.2.4 on 2019-09-10 10:37
2+
3+
from django.db import migrations, models
4+
import vng_api_common.fields
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [("datamodel", "0010_migrate_to_flattened_urls")]
10+
11+
operations = [
12+
migrations.AddField(
13+
model_name="besluit",
14+
name="_etag",
15+
field=models.CharField(
16+
default="",
17+
editable=False,
18+
help_text="MD5 hash of the resource representation in its current version.",
19+
max_length=32,
20+
verbose_name="etag value",
21+
),
22+
preserve_default=False,
23+
),
24+
migrations.AddField(
25+
model_name="besluitinformatieobject",
26+
name="_etag",
27+
field=models.CharField(
28+
default="",
29+
editable=False,
30+
help_text="MD5 hash of the resource representation in its current version.",
31+
max_length=32,
32+
verbose_name="etag value",
33+
),
34+
preserve_default=False,
35+
),
36+
]

src/brc/datamodel/models.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from django.db import models
55
from django.utils.translation import ugettext_lazy as _
66

7+
from vng_api_common.caching import ETagMixin
78
from vng_api_common.fields import RSINField
89
from vng_api_common.models import APIMixin
910
from vng_api_common.utils import (
@@ -21,7 +22,7 @@
2122
logger = logging.getLogger(__name__)
2223

2324

24-
class Besluit(APIMixin, models.Model):
25+
class Besluit(ETagMixin, APIMixin, models.Model):
2526
uuid = models.UUIDField(default=_uuid.uuid4)
2627

2728
identificatie = models.CharField(
@@ -142,7 +143,7 @@ def unique_representation(self):
142143
return f"{self.identificatie}"
143144

144145

145-
class BesluitInformatieObject(models.Model):
146+
class BesluitInformatieObject(ETagMixin, models.Model):
146147
"""
147148
Aanduiding van het (de) INFORMATIEOBJECT(en) waarin
148149
het BESLUIT beschreven is.

src/brc/datamodel/tests/factories.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@ def ingangsdatum(self):
2121
end_date=self.datum + timedelta(days=180),
2222
tzinfo=timezone.utc,
2323
)
24-
return _ingangsdatum.evaluate(self, None, None)
24+
return _ingangsdatum.evaluate(self, None, None).date()
25+
26+
class Params:
27+
with_etag = factory.Trait(
28+
_etag=factory.PostGenerationMethodCall("calculate_etag_value")
29+
)
2530

2631

2732
class BesluitInformatieObjectFactory(factory.django.DjangoModelFactory):
@@ -30,3 +35,8 @@ class BesluitInformatieObjectFactory(factory.django.DjangoModelFactory):
3035

3136
class Meta:
3237
model = "datamodel.BesluitInformatieObject"
38+
39+
class Params:
40+
with_etag = factory.Trait(
41+
_etag=factory.PostGenerationMethodCall("calculate_etag_value")
42+
)

0 commit comments

Comments
 (0)