使用Falcon的测试模块模拟multipart / form-data文件上传

时间:2017-03-14 12:50:41

标签: python file-upload functional-testing falconframework

这个简单的Falcon API将HTTP POSTenctype=multipart/form-data并在file参数中上传文件,并在控制台上打印文件内容:

# simple_api.py
import cgi
import falcon

class SomeTestApi(object):
    def on_post(self, req, resp):
        upload = cgi.FieldStorage(fp=req.stream, environ=req.env)
        upload = upload['file'].file.read()
        print(upload)


app = falcon.API()
app.add_route('/', SomeTestApi())

也可以使用falcon-multipart中间件来实现相同的目标。

要尝试一下,请运行它,例如使用gunicornpip install gunicorn),

gunicorn simple_api.py

然后使用cUrl(或任何选择的REST客户端)上传文本文件:

# sample.txt
this is some sample text

curl -F "file=@sample.txt" localhost:8000

我想通过模拟文件上传来使用Falcon testing helpers测试此API。但是,我还不明白如何做到这一点(如果可能的话)? simulate_request method有一个file_wrapper参数可能很有用但是从文档中我不明白这是如何填充的。

有什么建议吗?

1 个答案:

答案 0 :(得分:3)

这就是我想出来的,它试图模拟我的Chrome所做的事情。 请注意,这会模拟仅上载一个文件的情况,但您只需修改此功能即可上传多个文件,每个文件由两个新行分隔。

def create_multipart(data, fieldname, filename, content_type):
    """
    Basic emulation of a browser's multipart file upload
    """
    boundry = '----WebKitFormBoundary' + random_string(16)
    buff = io.BytesIO()
    buff.write(b'--')
    buff.write(boundry.encode())
    buff.write(b'\r\n')
    buff.write(('Content-Disposition: form-data; name="%s"; filename="%s"' % \
               (fieldname, filename)).encode())
    buff.write(b'\r\n')
    buff.write(('Content-Type: %s' % content_type).encode())
    buff.write(b'\r\n')
    buff.write(b'\r\n')
    buff.write(data)
    buff.write(b'\r\n')
    buff.write(boundry.encode())
    buff.write(b'--\r\n')
    headers = {'Content-Type': 'multipart/form-data; boundary=%s' %boundry}
    headers['Content-Length'] = str(buff.tell())
    return buff.getvalue(), headers

然后您可以使用此功能,如下所示:

with open('test/resources/foo.pdf', 'rb') as f:
    foodata = f.read()

# Create the multipart data
data, headers = create_multipart(foodata, fieldname='uploadFile',
                                 filename='foo.pdf',
                                 content_type='application/pdf')

# Post to endpoint
client.simulate_request(method='POST', path=url,
                        headers=headers, body=data)