FEAT: Modernized to support latest Pythons and DRF JSONAPI
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
from types import SimpleNamespace
|
||||
|
||||
from rest_framework_json_api import serializers
|
||||
|
||||
from enhanced_drf_jsonapi.api import (
|
||||
HardenedGenericAPIView,
|
||||
HardenedModelViewSet,
|
||||
PreloadIncludesMixin,
|
||||
ReasonableModelSerializer,
|
||||
ReasonableModelViewSet,
|
||||
)
|
||||
from enhanced_drf_jsonapi.exceptions import HardenedExceptionHandlingMixin
|
||||
|
||||
|
||||
class QuerySetSpy:
|
||||
def __init__(self):
|
||||
self.select_calls = []
|
||||
self.prefetch_calls = []
|
||||
|
||||
def select_related(self, *fields):
|
||||
self.select_calls.append(fields)
|
||||
return self
|
||||
|
||||
def prefetch_related(self, *fields):
|
||||
self.prefetch_calls.append(fields)
|
||||
return self
|
||||
|
||||
|
||||
class QuerySetProvider:
|
||||
queryset_spy = None
|
||||
|
||||
def get_queryset(self, *args, **kwargs):
|
||||
return self.queryset_spy
|
||||
|
||||
|
||||
class IncludeView(PreloadIncludesMixin, QuerySetProvider):
|
||||
select_for_includes = {
|
||||
"__all__": ["owner"],
|
||||
"author": ["author", "author__profile"],
|
||||
}
|
||||
prefetch_for_includes = {
|
||||
"author": ["author__books"],
|
||||
"comments": lambda view: [f"comments_for_{view.request.marker}"],
|
||||
}
|
||||
|
||||
|
||||
def test_preload_includes_applies_requested_and_unconditional_rules(monkeypatch):
|
||||
queryset = QuerySetSpy()
|
||||
view = IncludeView()
|
||||
view.queryset_spy = queryset
|
||||
view.request = SimpleNamespace(marker="request")
|
||||
monkeypatch.setattr(
|
||||
"enhanced_drf_jsonapi.api.get_included_resources",
|
||||
lambda request: ["author", "comments"],
|
||||
)
|
||||
|
||||
assert view.get_queryset() is queryset
|
||||
assert queryset.select_calls == [("author", "author__profile"), ("owner",)]
|
||||
assert queryset.prefetch_calls == [
|
||||
("author__books",),
|
||||
("comments_for_request",),
|
||||
]
|
||||
|
||||
|
||||
def serializer_fields(monkeypatch, method, *, include="", data=None, configured=True):
|
||||
monkeypatch.setattr(
|
||||
serializers.ModelSerializer,
|
||||
"get_field_names",
|
||||
lambda self, declared_fields, info: ["id", "name"],
|
||||
)
|
||||
request = SimpleNamespace(
|
||||
method=method,
|
||||
query_params={"include": include} if include else {},
|
||||
data=data or {},
|
||||
)
|
||||
serializer = ReasonableModelSerializer(context={"request": request})
|
||||
if configured:
|
||||
serializer.included_serializers = {"owner": object, "comments": object}
|
||||
return serializer.get_field_names({}, None)
|
||||
|
||||
|
||||
def test_serializer_adds_requested_get_relationships_without_duplicates(monkeypatch):
|
||||
fields = serializer_fields(monkeypatch, "GET", include="owner,comments,missing,owner")
|
||||
assert fields == ["id", "name", "owner", "comments"]
|
||||
|
||||
|
||||
def test_serializer_adds_relationships_from_post_and_patch_payloads(monkeypatch):
|
||||
assert serializer_fields(monkeypatch, "POST", data={"owner": {}, "other": 1}) == [
|
||||
"id",
|
||||
"name",
|
||||
"owner",
|
||||
]
|
||||
assert serializer_fields(monkeypatch, "PATCH", data={"comments": []}) == [
|
||||
"id",
|
||||
"name",
|
||||
"comments",
|
||||
]
|
||||
|
||||
|
||||
def test_serializer_is_safe_without_request_or_included_serializers(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
serializers.ModelSerializer,
|
||||
"get_field_names",
|
||||
lambda self, declared_fields, info: ["id"],
|
||||
)
|
||||
assert ReasonableModelSerializer().get_field_names({}, None) == ["id"]
|
||||
assert serializer_fields(monkeypatch, "GET", include="owner", configured=False) == [
|
||||
"id",
|
||||
"name",
|
||||
]
|
||||
|
||||
|
||||
def test_view_classes_preserve_methods_and_offer_opt_in_hardening():
|
||||
assert ReasonableModelViewSet.http_method_names == [
|
||||
"get",
|
||||
"post",
|
||||
"patch",
|
||||
"delete",
|
||||
"head",
|
||||
"options",
|
||||
]
|
||||
assert issubclass(HardenedModelViewSet, HardenedExceptionHandlingMixin)
|
||||
assert issubclass(HardenedGenericAPIView, HardenedExceptionHandlingMixin)
|
||||
Reference in New Issue
Block a user