Testing an APIView, which uses data from a cookie (Django 3.1)

Viewed 211

Django 3.1, python 3.7

I have an APIView that does work based on values in a JWT..... which is a defined cookie format - but how do I feed in a canned cookie to test the view?

The basic JWT stuff is fine - we use it elsewhere in the code, and have done for a couple of years

from rest_framework_jwt.settings import api_settings as jwt_settings

def get_jwt_payload(request) -> dict:
    jwt = request.auth
    if jwt:
        logger.debug(f"Checking token {jwt}")
        jwt_decode_handler = jwt_settings.JWT_DECODE_HANDLER
        return jwt_decode_handler(jwt)
    else:
        raise Exception(f"JWT token is missing, is django rest framework DEFAULT_AUTHENTICATION_CLASSES configured?")

I've hacked my view down to minimal code to prove there's no cookie:

class FeatureFlagsView(APIView):
    permission_classes = (AllowAny,)
    throttle_classes = (AnonRateThrottle,)

    def get(self, request):
        features = {}
        print(f"cookies: {request.COOKIES}")

        return Response(data=features, status=200)

My test is thus:

import pytest
from django.test import TestCase
from rest_framework.test import APIClient, RequestsClient, APITestCase

from rest_framework_jwt.settings import api_settings as jwt_settings
from myapp_utils.test_utils import TestCreators # helper routines for creating DB entries

class TestFeatureFlagsView(TestCreators, TestCase):

    @pytest.mark.django_db
    def test_call_with_no_features(self):
        self.create_unknown_user = True

        username = "1-test"

        # helper method to create a user
        user = self.create_user(username=username)

        # Lifted from existing code that tests JWT authentication
        payload = {
            "username": username,
            "n_cnm": "My Funky Course",
            "n_rl": "urn:lti:role:ims/lis/Learner",
            "n_nb": "Standard service",
        }
        token = jwt_settings.JWT_ENCODE_HANDLER(payload)
        expiration = datetime.utcnow() + jwt_settings.JWT_EXPIRATION_DELTA
        cookies = {jwt_settings.JWT_AUTH_COOKIE: token}

        ## View testing code
        # self.client.cookies.load(cookies)
        # response = self.client.get('/api/features/', HTTP_AUTHORIZATION='JWT ' + token)


        # client = RequestsClient()
        # response = client.post('http://testserver/api/features', headers={'referer': "http://testserver/", 'cookies': cookies})
        # assert response.status_code == 200
        # assert response.json().get("status") == "failed"

        client = APIClient(HTTP_AUTHORIZATION='JWT ' + token)
        client.credentials(HTTP_AUTHORIZATION='JWT ' + token)
        print(f"JWT token: {token}")
        response = client.get('/api/features/')
        assert False

I run the test: pytest -vvv path/to/test_api.py::TestFeatureFlagsView - The test fails (obviously: assert False ensures that).

However it does allow me to see the print outputs:

JWT token: obfuscated.meaningless.text
cookies: {}

I know the token is right, no problems there.... but no cookie!

As you can see, I've tried TestCase's built-in client, APIClient, and RequestClient... and I just can't seem to figure out how to set a JWT cookie [that's going to be read by the get_jwt_payload method.

Help!

1 Answers

I had all the working parts, I must have just failed to put them together properly.

This works:

class TestFeatureFlagsView(TestCreators, TestCase):

    @pytest.mark.django_db
    def test_call_with_no_features(self):
        self.create_unknown_user = True

        username = "1-test"

        # helper method to create a user
        user = self.create_user(username=username)

        # Lifted from existing code that tests JWT authentication
        payload = {
            "username": username,
            "n_cnm": "My Funky Course",
            "n_rl": "urn:lti:role:ims/lis/Learner",
            "n_nb": "Standard service",
        }
        token = jwt_settings.JWT_ENCODE_HANDLER(payload)
        expiration = datetime.utcnow() + jwt_settings.JWT_EXPIRATION_DELTA
        cookies = {jwt_settings.JWT_AUTH_COOKIE: token}

        self.client.cookies = SimpleCookie(cookies)

        # Add a restriction for TEST_TRUE, but with an invalid course
        # code, and it doesn't show
        feature = "TEST_TRUE"
        restriction = self.create_featureRestriction(
            feature=feature,
            customer=custA,
            course_code="wrong course code",
        )
        response = self.client.get("/api/features/")
        assert response.json() == {}

        # Add a restriction for TEST_TRUE, and it should show
        restriction = self.create_featureRestriction(
            feature=feature,
            customer=custA,
            course_code=course_code,
        )
        response = self.client.get("/api/features/")
        assert response.json() == {"TEST_TRUE": True}

Related