0

Background:
I have integration test which is working fine, but later on failed when I added the customized middleware

def test_mobile_update_customer(self):
    user = User.objects.create(username='warhead')
    self.client.force_authenticate(user=user)
    mommy.make(Customer, family_name='IBM', created_user=self.soken_staff, updated_user=self.soken_staff)
    data = {
        "family_name": "C0D1UM"
    }
    customer = Customer.objects.first()
    res = self.client.patch(reverse('api:customer-detail', kwargs={'pk': customer.id}), data=data)
    self.assertEqual(200, res.status_code)
    customer.refresh_from_db()
    self.assertEqual('C0D1UM', customer.family_name)
    self.assertEqual('spearhead', customer.created_user.username)
    self.assertEqual('warhead', customer.updated_user.username)

Problem:
The middleware break it with Exception

  File "/Users/el/Code/norak-cutter/soken/soken-web/soken_web/middleware.py", line 47, in process_request
    data['PATCH'] = json.loads(request.body)
  File "/Users/el/.pyenv/versions/soken/lib/python3.6/site-packages/django/http/request.py", line 264, in body
    raise RawPostDataException("You cannot access body after reading from request's data stream")
django.http.request.RawPostDataException: You cannot access body after reading from request's data stream

The problem is data has been read before the RESTful api do the job. Then the program raises an exception.

def process_request(self, request):

    if request.path.startswith('/api/'):
        data = collections.OrderedDict()
        data["user"] = request.user.username
        data["path"] = request.path
        data["method"] = request.method
        data["content-type"] = request.content_type
        if request.method == 'GET':
            data['GET'] = request.GET
        elif request.method == 'POST':
            data['POST'] = request.POST

        # https://stackoverflow.com/questions/4994789/django-where-are-the-params-stored-on-a-put-delete-request
        # elif request.method == 'PUT':
        #     data['PUT'] = json.loads(request.body)

        # test_mobile_update_customer
        # raise RawPostDataException("You cannot access body after reading from request's data stream")
        # django.http.request.RawPostDataException: You cannot access body after reading from request's data stream
        # elif request.method == 'PATCH':
        #     data['PATCH'] = json.loads(request.body)
        elif request.method == 'DELETE':
            pass
        self.__uuid = str(uuid.uuid4())
        request_logger.info(f'{self.__uuid} {json.dumps(data)}')

Update2
Attempt:
I change client constructor refer to https://github.com/encode/django-rest-framework/issues/2774

def test_mobile_update_customer(self):
    user = User.objects.create(username='warhead')
    # self.client.force_authenticate(user=user)
    from django.test import Client
    client = Client()
    client.force_login(user)
    mommy.make(Customer, family_name='IBM', created_user=self.soken_staff, updated_user=self.soken_staff)
    data = {
        "family_name": "C0D1UM"
    }
    customer = Customer.objects.first()
    res = client.patch(reverse('api:customer-detail', kwargs={'pk': customer.id}), data=data, content_type='application/json')
    self.assertEqual(200, res.status_code)
    customer.refresh_from_db()
    self.assertEqual('C0D1UM', customer.family_name)
    self.assertEqual('spearhead', customer.created_user.username)
    self.assertEqual('warhead', customer.updated_user.username)

It does not work. The Client misinterpret the payload

>>> res.content
b'{"detail":"JSON parse error - Expecting property name enclosed in double quotes: line 1 column 2 (char 1)"}'

Workaround:
I don't know this is correct for all cases or not, but I workaround by this
test.py https://gist.github.com/elcolie/88eb7c90cfca1c369a020ac232c7fbcc
middleware.py https://gist.github.com/elcolie/5d9b1a2f890a0efcb46fdb95c0e90908
result.py https://gist.github.com/elcolie/298e595b404c1a5839ed8dd584d2f07f

Question:
How do I do integration test of PATCH with the same time that testcase will not break by my middleware?

Right now I have to choose either one of them.

halfer
  • 19,824
  • 17
  • 99
  • 186
joe
  • 8,383
  • 13
  • 61
  • 109
  • You haven't set `content_type` in your `client.patch()` call like the [example you linked to](https://github.com/encode/django-rest-framework/issues/2774). I believe you have to convert the data dictionary to json using `json.dumps` as well. – Alasdair Oct 06 '17 at 08:37
  • @Alasdair Thank you for you reply. I started to giving up on this. It looks like Django fundamental mechanics limitation. How do you `log` all payload of traffice to your system?. Payload can be `json`, `form`, `form+file` – joe Oct 06 '17 at 09:27
  • @Alasdair I have added my workaround. Could you please have a look? – joe Oct 06 '17 at 09:36
  • I don't understand why you added `content_type` to `force_login()`. You need to add it to `client.patch()`. – Alasdair Oct 06 '17 at 09:56
  • If I use `django.test.Client` it misinterpret the payload. Then I have follow the docs http://www.django-rest-framework.org/api-guide/testing/#apiclient Currently workaround is find. But I am not sure it will break by `file` or not. When I have time I will update on this question. – joe Oct 06 '17 at 10:13

0 Answers0