How can I test "uploading a file" using Tornado unit tests? - python

I'm want to test my web service (built on Tornado) using tornado.testing.AsyncHTTPTestCase. It says here that using POST for AsyncHttpClients should look like the following.
from tornado.testing import AsyncHTTPTestCase
from urllib import urlencode
class ApplicationTestCase(AsyncHTTPTestCase):
def get_app(self):
return app.Application()
def test_file_uploading(self):
url = '/'
filepath = 'uploading_file.zip' # Binary file
data = ??????? # Read from "filepath" and put the generated something into "data"
self.http_client.fetch(self.get_url(url),
self.stop,
method="POST",
data=urlencode(data))
response = self.wait()
self.assertEqual(response.code, 302) # Do assertion
if __name__ == '__main__':
unittest.main()
The problem is that I've no idea what to write at ???????. Are there any utility functions built in Tornado, or is it better to use alternative libraries like Requests?
P.S.
... actually, I've tried using Requests, but my test stopped working because probably I didn't do good for asynchronous tasking
def test_file_uploading(self):
url = '/'
filepath = 'uploading_file.zip' # Binary file
files = {'file':open(filepath,'rb')}
r = requests.post(self.get_url(url),files=files) # Freezes here
self.assertEqual(response.code, 302) # Do assertion

You need to construct a multipart/form-data request body. This is officially defined in the HTML spec. Tornado does not currently have any helper functions for generating a multipart body. However, you can use the MultipartEncoder class from the requests_toolbelt package. Just use the to_string() method instead of passing the encoder object directly to fetch().

Related

How to write unit testing script using unittest

I want to write a unit test cases using unittest where my input is set of images and output is set of images with boundary box in the text, also it generate co-ordinate of the boundary boxes. How can I write test script for that using unittest pyunit framework.
So I have written unittest script to test api is working or not, response should be json / and list format and response of image file format should be png,jpg format, which is working now. I have below test case scenario need to test but how I will check? I don't know.
If optional keys are not passed to API, it should not throw an error. (opposite for compulsory ones) 8) The implemented route should throw/return error if GET request is passed instead of POST. 9) If valid path but invalid file name is provided, you should see respective error. 10) In case of invalid path, you should see respective error message. 11) There is specified set of keys which are compulsory to be passed to APIs, if not it returns an error 12) verify for session time out.
Here is my code:
import requests
import json
import sshtunnel
import unittest
class TestSequentialExecutions(unittest.TestCase):
def setUp(self) -> None:
a=10
def test_API(self):
self.resp_list = []
# API url
url = ['dummy url','dummyurl']
# Additional headers.
headers = {'Content-Type': 'application/json'}
# Body
payload = [{'input': 'dummy path'},
{"path": "dummy"}]
# Test case-1 checking valid API is routed or not
# convert dict to json by json.dumps() for body data.
for i in range(len(url)):
resp = requests.post(url[i], headers=headers, data=json.dumps(payload[i], indent=4))
self.assertEqual(resp.status_code, 200)
self.resp_list.append(resp.json())
#Test case-2 to check input file is in JPG ,PNG format or not
def test_fileformat(self):
n = len(self.resp_list[1])
my_list = [1]*n
empty_list=[]
extensions = ['png','v']
for filename in self.resp_list[0]:
if filename.lower().endswith(('.png', '.jpg')):
empty_list.append(1)
else:
empty_list.append(0)
self.assertEqual(my,empy_list)
if __name__ == '__main__':
unittest.main()
Actually I am trying to write test script for below github code: https://github.com/eragonruan/text-detection-ctpn

Python script works as pure python but not with Flask

I'm working on some code that pulls course info from Canvas. As pure python, it works fine. If I try to incorporate it with Flask, I get the following error
requests.exceptions.MissingSchema: Invalid URL 'run/api/v1/courses/1234567': No schema supplied. Perhaps you meant http://run/api/v1/courses/1234567?
This is the code in question:
Canvas file
import sys
from canvasapi import Canvas
def getinfo():
canvasurl = "https://canvas.instructure.com/";
canvastoken = #Redacted for this example
try:
canvastoken = sys.argv[1];
canvasurl = sys.argv[2];
except:
print()
#Create a new canvas object passing in the newly aquired url and token
canvas = Canvas(canvasurl, canvastoken);
#print(canv)
# Create a new course oject -- passing in course number as a parameter
# Course number is currently hard coded
print(canvas.get_course(1234567))
Flask file code (the file that I'm trying to run):
from flask import Flask
import canvas
canvas.getinfo()
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
No schema provided usually means you haven't specified the http:// or https:// in the URL.
In the code you provided, I don't see any reference to a run/api/v1/courses/1234567. One possibility is if you are using the url_for method from requests anywhere in your code, try setting _external=True:
url = url_for('relativeURL', _external=True)
This allows Flask to construct an absolute URL (i.e., a URL with domain included).
If you aren't using url_for, check other places in your code where you might be omitting the http or https from the URL.
If you update your question to include the part that refers to the offending URL, we might be able to provide more specific help.

Mock requests in Django

I have this function:
def function_to_test(..):
# some stuff
response = requests.post("some.url", data={'dome': 'data'})
# some stuff with response
I want to make a test, but mocking requests.post("some.url", data={'dome': 'data'}) because I know it works. I need something like:
def my tets():
patch('requests.post', Mock(return_value={'some': 'values'})).start()
# test for *function_to_test*
Is that possible? If so, how?
Edited
I found these ways:
class MockObject(object):
status_code = 200
content = {'some': 'data'}
# First way
patch('requests.post', Mock(return_value=MockObject())).start()
# Second way
import requests
requests.post = Mock(return_value=MockObject())
Are these approaches good? which one is better? another one?
You can use HTTPretty(https://github.com/gabrielfalcao/HTTPretty), a library made just for that kind of mocks.
you can use flexmock for that. see the example below
Say you have function in file ./myfunc.py
# ./myfunc.py
import requests
def function_to_test(..):
# some stuff
response = requests.post("www.google.com", data={'dome': 'data'})
return response
Then the testcase is in ./test_myfunc.py
# ./test_myfunc.py
import flexmock as flexmock
import myfunc
def test_myfunc():
(flexmock(myfunc.requests).should_recieve("post").with_args("www.google.com", data={"dome":
"data"}).and_return({'some': 'values'}))
resp = myfunc.function_to_test()
assert resp["some"] == "values"
Try this, see if this works or let me know for more enhancement/improvement.
After continue testing and testing I prefer to use this to mock requests. Hope it helps others.
class MockObject(object):
status_code = 200
content = {'some': 'data'}
patch('requests.post', Mock(return_value=MockObject())).start()

How do you unit test a file post with webapp2?

I am unit testing a webapp2 application and would like to write a test that simulates a file post. How can I create a request object in my unit test that contains the simulated contents of a file?
import unittest
import webapp2
import main
file_contents = """id, first, last
1, Bruce, Banner
2, Tony, Stark
"""
class TestHandlers(unittest.TestCase):
def test_hello(self):
request = webapp2.Request.blank('/')
request.method = 'POST'
# Magic needed here.
#Put file_contents into a form parameter
response = request.get_response(main.app)
#Test that the returned text contains something from the posted file
self.assertEqual(True, "Bruce" in response.body)
Looks to me like the blank method includes a named POST parameter. It says in the docs http://webapp-improved.appspot.com/guide/testing.html#request-blank that by using it, the request method is automatically set to POST and the CONTENT_TYPE is set to ‘application/x-www-form-urlencoded’.
So in the above it could just be:
post_contents = {'someVar':file_contents}
request = webapp2.Request.blank('/', POST=post_contents)
response = request.get_response(main.app)

How do you use FCKEditor's image upload and browser with mod-wsgi?

I am using FCKEditor within a Django app served by Apache/mod-wsgi. I don't want to install php just for FCKEditor andI see FCKEditor offers image uploading and image browsing through Python. I just haven't found good instructions on how to set this all up.
So currently Django is running through a wsgi interface using this setup:
import os, sys
DIRNAME = os.sep.join(os.path.abspath(__file__).split(os.sep)[:-3])
sys.path.append(DIRNAME)
os.environ['DJANGO_SETTINGS_MODULE'] = 'myapp.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
In fckeditor in the editor->filemanager->connectors->py directory there is a file called wsgi.py:
from connector import FCKeditorConnector
from upload import FCKeditorQuickUpload
import cgitb
from cStringIO import StringIO
# Running from WSGI capable server (recomended)
def App(environ, start_response):
"WSGI entry point. Run the connector"
if environ['SCRIPT_NAME'].endswith("connector.py"):
conn = FCKeditorConnector(environ)
elif environ['SCRIPT_NAME'].endswith("upload.py"):
conn = FCKeditorQuickUpload(environ)
else:
start_response ("200 Ok", [('Content-Type','text/html')])
yield "Unknown page requested: "
yield environ['SCRIPT_NAME']
return
try:
# run the connector
data = conn.doResponse()
# Start WSGI response:
start_response ("200 Ok", conn.headers)
# Send response text
yield data
except:
start_response("500 Internal Server Error",[("Content-type","text/html")])
file = StringIO()
cgitb.Hook(file = file).handle()
yield file.getvalue()
I need these two things two work together by means of modifying my django wsgi file to serve the fckeditor parts correctly or make apache serve both django and fckeditor correctly on a single domain.
This describes how to embed the FCK editor and enable image uploading.
First you need to edit fckconfig.js to change the image upload
URL to point to some URL inside your server.
FCKConfig.ImageUploadURL = "/myapp/root/imageUploader";
This will point to the server relative URL to receive the upload.
FCK will send the uploaded file to that handler using the CGI variable
name "NewFile" encoded using multipart/form-data. Unfortunately you
will have to implement /myapp/root/imageUploader, because I don't think
the FCK distribution stuff can be easily adapted to other frameworks.
The imageUploader should extract the NewFile and store it
somewhere on the server.
The response generated by /myapp/root/imageUploader should emulate
the HTML constructed in /editor/.../fckoutput.py.
Something like this (whiff template format)
{{env
whiff.content_type: "text/html",
whiff.headers: [
["Expires","Mon, 26 Jul 1997 05:00:00 GMT"],
["Cache-Control","no-store, no-cache, must-revalidate"],
["Cache-Control","post-check=0, pre-check=0"],
["Pragma","no-cache"]
]
/}}
<script>
//alert("!! RESPONSE RECIEVED");
errorNumber = 0;
fileUrl = "fileurl.png";
fileName = "filename.png";
customMsg = "";
window.parent.OnUploadCompleted(errorNumber, fileUrl, fileName, customMsg);
</script>
The {{env ...}} stuff at the top indicate the content type and
recommended HTTP headers to send. The fileUrl should be the Url to
use to find the image on the server.
Here are the basic steps to get the html fragment which
generates the FCK editor widget. The only tricky part is you have to put the
right client indentification into the os.environ -- it's ugly
but that's the way the FCK library works right now (I filed a bug
report).
import fckeditor # you must have the fck editor python support installed to use this module
import os
inputName = "myInputName" # the name to use for the input element in the form
basePath = "/server/relative/path/to/fck/installation/" # the location of FCK static files
if basePath[-1:]!="/":
basePath+="/" # basepath must end in slash
oFCKeditor = fckeditor.FCKeditor(inputName)
oFCKeditor.BasePath = basePath
oFCKeditor.Height = 300 # the height in pixels of the editor
oFCKeditor.Value = "<h1>initial html to be editted</h1>"
os.environ["HTTP_USER_AGENT"] = "Mozilla/5.0 (Macintosh; U;..." # or whatever
# there must be some way to figure out the user agent in Django right?
htmlOut = oFCKeditor.Create()
# insert htmlOut into your page where you want the editor to appear
return htmlOut
The above is untested, but it's based on the below which is tested.
Here is how to use FCK editor using mod-wsgi:
Technically it uses a couple features of WHIFF (see
WHIFF.sourceforge.net),
-- in fact it is part of the WHIFF distribution --
but
the WHIFF features are easily removed.
I don't know how to install it in Django, but if
Django allows wsgi apps to be installed easily, you
should be able to do it.
NOTE: FCK allows the client to inject pretty much anything
into HTML pages -- you will want to filter the returned value for evil
attacks.
(eg: see whiff.middleware.TestSafeHTML middleware for
an example of how to do this).
"""
Introduce an FCK editor input element. (requires FCKeditor http://www.fckeditor.net/).
Note: this implementation can generate values containing code injection attacks if you
don't filter the output generated for evil tags and values.
"""
import fckeditor # you must have the fck editor python support installed to use this module
from whiff.middleware import misc
import os
class FCKInput(misc.utility):
def __init__(self,
inputName, # name for input element
basePath, # server relative URL root for FCK HTTP install
value = ""): # initial value for input
self.inputName = inputName
self.basePath = basePath
self.value = value
def __call__(self, env, start_response):
inputName = self.param_value(self.inputName, env).strip()
basePath = self.param_value(self.basePath, env).strip()
if basePath[-1:]!="/":
basePath+="/"
value = self.param_value(self.value, env)
oFCKeditor = fckeditor.FCKeditor(inputName)
oFCKeditor.BasePath = basePath
oFCKeditor.Height = 300 # this should be a require!
oFCKeditor.Value = value
# hack around a bug in fck python library: need to put the user agent in os.environ
# XXX this hack is not safe for multi threaded servers (theoretically)... need to lock on os.env
os_environ = os.environ
new_os_env = os_environ.copy()
new_os_env.update(env)
try:
os.environ = new_os_env
htmlOut = oFCKeditor.Create()
finally:
# restore the old os.environ
os.environ = os_environ
start_response("200 OK", [('Content-Type', 'text/html')])
return [htmlOut]
__middleware__ = FCKInput
def test():
env = {
"HTTP_USER_AGENT":
"Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14"
}
f = FCKInput("INPUTNAME", "/MY/BASE/PATH", "THE HTML VALUE TO START WITH")
r = f(env, misc.ignore)
print "test result"
print "".join(list(r))
if __name__=="__main__":
test()
See this working, for example, at
http://aaron.oirt.rutgers.edu/myapp/docs/W1500.whyIsWhiffCool.
btw: thanks. I needed to look into this anyway.
Edit: Ultimately I was unhappy with this solution also so I made a Django app that takes care of the file uploads and browsing.
This is the solution I finally hacked together after reading the fckeditor code:
import os, sys
def fck_handler(environ, start_response):
path = environ['PATH_INFO']
if path.endswith(('upload.py', 'connector.py')):
sys.path.append('/#correct_path_to#/fckeditor/editor/filemanager/connectors/py/')
if path.endswith('upload.py'):
from upload import FCKeditorQuickUpload
conn = FCKeditorQuickUpload(environ)
else:
from connector import FCKeditorConnector
conn = FCKeditorConnector(environ)
try:
data = conn.doResponse()
start_response('200 Ok', conn.headers)
return data
except:
start_response("500 Internal Server Error",[("Content-type","text/html")])
return "There was an error"
else:
sys.path.append('/path_to_your_django_site/')
os.environ['DJANGO_SETTINGS_MODULE'] = 'your_django_site.settings'
import django.core.handlers.wsgi
handler = django.core.handlers.wsgi.WSGIHandler()
return handler(environ, start_response)
application = fck_handler

Categories

Resources