Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django test file download - "ValueError: I/O operation on closed file"

I have code for a view which serves a file download, and it works fine in the browser. Now I am trying to write a test for it, using the internal django Client.get:

    response = self.client.get("/compile-book/", {'id': book.id})
    self.assertEqual(response.status_code, 200)
    self.assertEquals(response.get('Content-Disposition'), 
                      "attachment; filename=book.zip")

so far so good. Now I would like to test if the downloaded file is the one I expect it to download. So I start by saying:

    f = cStringIO.StringIO(response.content)

Now my test runner responds with:

Traceback (most recent call last):
  File ".../tests.py", line 154, in test_download
    f = cStringIO.StringIO(response.content)
  File "/home/epub/projects/epub-env/lib/python2.7/site-packages/django/http/response.py", line 282, in content
    self._consume_content()
  File "/home/epub/projects/epub-env/lib/python2.7/site-packages/django/http/response.py", line 278, in _consume_content
    self.content = b''.join(self.make_bytes(e) for e in self._container)   
  File "/home/epub/projects/epub-env/lib/python2.7/site-packages/django/http/response.py", line 278, in <genexpr>
    self.content = b''.join(self.make_bytes(e) for e in self._container)   
  File "/usr/lib/python2.7/wsgiref/util.py", line 30, in next 
    data = self.filelike.read(self.blksize) 
ValueError: I/O operation on closed file

Even when I do simply: self.assertIsNotNone(response.content) I get the same ValueError

The only topic on the entire internet (including django docs) I could find about testing downloads was this stackoverflow topic: Django Unit Test for testing a file download. Trying that solution led to these results. It is old and rare enough for me to open a new question.

Anybody knows how the testing of downloads is supposed to be handled in Django? (btw, running django 1.5 on python 2.7)

like image 303
xor Avatar asked Mar 23 '23 01:03

xor


1 Answers

This works for us. We return rest_framework.response.Response but it should work with regular Django responses, as well.

import io
response = self.client.get(download_url, {'id': archive_id})
downloaded_file = io.BytesIO(b"".join(response.streaming_content))

Note: streaming_content is only available for StreamingHttpResponse (also Django 1.10): https://docs.djangoproject.com/en/1.10/ref/request-response/#django.http.StreamingHttpResponse.streaming_content

like image 162
Risadinha Avatar answered Apr 07 '23 18:04

Risadinha