Is there any way to simulate some GAE server error? - python

Are there ways to test my error_handlers setup in the app.yaml file, especially the error code over_quota?

Testing error_handlers
dev_appserver.py is the application that is parsing your app.yaml and serving these error files. This means that you're best bet is probably a straight up acceptance test where you bring up dev_appserver.py and try hitting it localhost:8080 with GETs and PUTs that would trigger the various errors you're expecting.
So, if /foo returns a 404, you could do the following with Python requests:
>>> def test_foo():
>>> response = requests.get('/foo')
>>> assert response.status_code == 404
Testing Over Quota Error
In this specific case it sounds like you're trying to explicitly raise the over_quota error. This link mentions that the exception you're looking for is apiproxy_errors.OverQuotaError.
I'm not sure what your test code is, but have you tried explicitly raising this error, with straight up raise?
I was able to run the following code after bootstrapping my apiproxy_stub_map, setting up my path, etc.:
from google.appengine.runtime import apiproxy_errors
def test_foo():
raise apiproxy_errors.OverQuotaError

Related

Correctly test with pytest

So I want to start using tests with pytest in my python programs.
EDIT: I'm only trying to test the response because it seemed like the easiest thing to test. I now understand that there are multiple ways to test the response, but I'm more looking to just get a general grip on building tests and using them.
I'm starting by testing if the correct response happens when I call a page using requests.
Like so:
**main.py**
def get_page(search_url):
page = requests.get(search_url)
return page
url = "https://www.google.com/search?q=weather+results&oq=weather+results&aqs=chrome..69i57.4626j0j1&sourceid=chrome&ie=UTF-8"
get_page(url)
Here is the test code I made to test the response. This is the first test I've ever written.
**test_main.py**
from main import get_page
def test_page_response():
test_url = "https://www.google.com/search?q=weather+results&oq=weather+results&aqs=chrome..69i57.4626j0j1&sourceid=chrome&ie=UTF-8"
assert str(get_page(test_url2)) == "<Response [200]>"
Am I doing this right? When I take out the url to break it and trigger a test, it shows me a ton of text. Sure, it's the error in it's full glory, but isn't testing supposed to make this simpler to read and understand what broke?
This leads me to believe I'm going about this the wrong way.
EDIT 2: Here's the output: http://pastebin.com/kTgc5bsR
### test_main.py ###
from main import get_page
def test_page_response():
test_url = "https://www.google.com/search?q=weather+results&oq=weather+results&aqs=chrome..69i57.4626j0j1&sourceid=chrome&ie=UTF-8"
response = get_page(test_url2) # get_page() returns a response object
assert response.status_code == 200
# also here reponse.text will contain the html string.
# You can parse it and have more assertions.
# This will be your real test to see if you got search results you expected.
Read more on how to use python-requests:
http://docs.python-requests.org/en/master/
Your url is basically your test input, you may modify the url to generate tests.
I suggest going through py.test basic examples:
http://pytest.org/latest/example/index.html
and also taking a primer on testing in general.
Is your goal to write a unit test?
If so, testing requests.get is already covered by rhe tests inside requests. It's considered unpythonic (and redundant) to re-check something that Python or your library already test for you. Instead, you should focus on testing the unique part of your app.
For example, mock the usage of requests. One way to do that is with the library requests-mock, though of course there are more one off approaches too.
Assuming you've mocked requests, the way I'd approach writing a unit test for get_page(...) is to assert that it returns the expected response body. You could also test for status code, but if you're mocking the request, this may not add a ton of value.
You may also consider testing retrieving the webpage itself in an integration test.
I'm happy to add code examples here if it would make it clearer.

Why does urllib2's .getcode() method crash on 404's?

In the beginner Python course I took on Lynda it said to use .getcode() to get the http code from a url and that that can be used as a test before reading the data:
webUrl = urllib2.urlopen('http://www.wired.com/tag/magazine-23-05/page/4')
print(str(webUrl.getcode()))
if (webURL.getcode() == 200):
data = webURL.read()
else:
print 'error'
However, when used with the 404 page above it causes Python to quit: Python function terminated unexpectedly: HTTP Error 404: Not Found, so it seems this lesson was completely wrong?
My question then is what exactly is .getcode() actually good for? You can't actually use it to test what the http code is unless you know what it is (or at least that it's not a 404). Was the course wrong or am I missing something?
My understanding is the proper way to do it is like this, which doesn't use .getcode() at all (though tell me if there is a better way):
try:
url = urllib2.urlopen('http://www.wired.com/tag/magazine-23-05/page/4')
except urllib2.HTTPError, e:
print e
This doesn't use .getcode() at all. Am I misunderstanding the point of .getcode() or is it pretty much useless? It seems strange to me a method for getting a page code in a library dedicated to opening url's can't handle something as trivial as returning a 404.
A 404 code is considered an error status by urllib2 and thus an exception is raised. The exception object also supports the getcode() method:
>>> import urllib2
>>> try:
... url = urllib2.urlopen('http://www.wired.com/tag/magazine-23-05/page/4')
... except urllib2.HTTPError, e:
... print e
... print e.getcode()
...
HTTP Error 404: Not Found
404
The fact that errors are raised is poorly documented. The library uses a stack of handlers to form a URL opener (created with (urllib2.build_opener(), installed with urllib2.install_opener()), and in the default stack the urllib2.HTTPErrorProcessor class is included.
It is that class that causes anything response with a response code outside the 2xx range to be handled as an error. The 3xx status codes then are handled by the HTTPRedirectHandler object, and some of the 40x codes (related to authentication) are handled by specialised authentication handlers, but most codes simply are left to be raised as an exception.
If you are up to installing additional Python libraries, I recommend you install the requests library instead, where error handling is a lot saner. No exceptions are raised unless you explicitly request it:
import requests
response = requests.get(url)
response.raise_for_status() # raises an exception for 4xx or 5xx status codes.
Yes you are understanding right, It throws an exception for a non-"OK" http status code. At the time of writing the lesson might have worked because the URL was valid, but if you try that URL in a browser now, you will also get a 404 not found, because the URL is now no longer valid.
In this case, urllib2.urlopen is in a way (arguably), abusing exceptions to return http status codes as exceptions (see docs for urllib2.HTTPError)
As an aside, I would suggest trying the requests library, which is much nicer to work with if you are planning to do some actual scripting work in this space outside of tutorials.

Catching SSLErrors within Tornado

I'm running Tornado 4.0.2 in a Python 2.7.5 virtualenv using SSL and a self-signed certificate and am the following SSLError is showing up repeatedly:
SSLError: [Errno 1] _ssl.c:1419: error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca
A few questions follow:
I'm assuming these exceptions are due to clients freaking out about my self-signed certificate. Is this correct?
Assuming this is the case - I don't care about this exception, and I don't want to see it in the log. (It's an internal webserver - we're never going to pay for a CA. All connections are just going to have to be untrusted.) In an attempt to catch the exceptions myself, I've tried subclassing IOLoop as follows:
class MyIOLoop(IOLoop):
def handle_callback_exception(callback):
print "Exception in callback", callback
if __name__ == "__main__":
app = Application(urls, compress_response = True)
ioloop=MyIOLoop.instance()
http_server = httpserver.HTTPServer(app, ssl_options={"certfile": "cert.pem", "keyfile": "key.pem" }, io_loop=ioloop )
http_server.listen(8888)
ioloop.start()
But this hasn't helped - I still get the full stack trace.
What do I need to do to handle (i.e. ignore) such exceptions myself? I've experimented with setting cert_reqs" : ssl.CERT_NONE in the ssl_options but that also hasn't helped.
Is there anything else I need to do - such as close the connection myself - when I've caught such an exception? If so, what, and how?
I also asked this question on the Tornado mailing list, and got the following response:
This error is coming from HTTP1ServerConnection, not IOLoop (I think
it's uncommon for errors to make it all the way up to the IOLoop these
days). You're correct that this means that a client has refused to
connect because it doesn't trust your certificate. It's arguably
useful to log something in this case (you'd want to know if this
started happening a lot), but it should be at most one line instead of
a full stack trace. It might also be better to treat it as more like
ECONNRESET and log nothing.
We don't currently expose any useful ways to customize this logging,
but you have options in the logging module itself. You could attach a
Filter to the logger and block entries where exc_info[0] is SSLError
and exc_info[1] has the right error code, for example.
I ended up adding a filter to Tornado's logger as suggested. One slight snag was that record.exc_info was sometimes None, but in such situations I was able to get enough information out of record.args to decide if I want to filter it.
Following on from helgridly's own answer: the error can't be caught, but you can filter the logs.
Create a function that checks for the presence of an SSL error in a log record, and rejects certain such errors
Install it as a filter for the tornado.general logger
For example:
def ssl_log_filter(record):
if record.exc_info is not None:
e = record.exc_info[1]
elif len(record.args) >= 3 and isinstance(record.args[2], Exception):
e = record.args[2]
else:
e = None
if isinstance(e, SSLEOFError):
return False
if isinstance(e, SSLError):
if e.reason in {'NO_SHARED_CIPHER'}:
return False
return True
logging.getLogger('tornado.general').addFilter(ssl_log_filter)
The code above will only work for Python 3.2+. For older versions, subclass Filter instead.

urllib2.open giving 500 HTTPError exception even when call is successful

I am using urllib2 to access a URL and read the data. The urlopen call is in a try except block like below. I have seen other questions asked on the site saying they are encountering this 500 error but I could not find a concrete answer as to why we get this 500 exception even when the call is successful. Can anyone elaborate on that or point out ways to encounter it?
try:
data = urllib2.urlopen(url).read().split('\n')
except urllib2.HTTPError, e:
print "Could not get data with url {0} due to error code {1}.".format(url,e.code)
except urllib2.URLError, e:
print "Could not get data with url {0} due to reason {1}.".format(url,e.reason)
sys.exit(1)
HTTP Error 500 is a server error (https://en.wikipedia.org/wiki/List_of_HTTP_status_codes). You should investigate the server side logs
You're getting a server side error.
You need to inspect the error (e) to see if there is any feedback on what is causing it. it usually has some of the actual error data from the server in it. not all servers will return error data though, sometimes it's just on the server logs.
If this is running on a daemon, or sporadically, you could write something that logs the contents of e somewhere.
You could also use pdb.set_trace() to set a breakpoint and inspect the object yourself.
also, while this line looks great:
data = urllib2.urlopen(url).read().split('\n')
it's a real pain during debugging and troubleshooting, which happens A LOT when using urllib.
i would suggest splitting it into a few lines like this
url_obj = urllib2.urlopen(url)
data = url_obj.read()
data = data.split('\n')
if you enter in a few breakpoints with pdb ( pdb.set_trace() ) you'll be able to instead each variable.
since you're not using a custom opener, i would also just use the requests library, which just wraps urllib and makes it less horrible.

Is there a way to abort a test if the settings library setup fails?

I have a library management_utils.py that's something like:
path = global_settings.get_rdio_base_path()
if path == "":
raise PathRequiredError("Path is required...")
def some_keyword():
# keyword requires path to be set to some valid value
In my test case file I have something like:
***Settings***
Library management_utils
***Test Cases***
Smoke Test
some keyword
...
Is it possible to abort running these test cases if the management_utils setup fails? Basically I'd like to abort execution of these test cases if PathRequiredError was raised in management_utils.py.
When I run the tests, I see the error being raised but execution continues on.
I saw in the Robot documentation you can set ROBOT_EXIT_ON_FAILURE = True in your error class but this doesn't seem to work for this case. Also ideally I'd be able to do something more granular so that it only aborts the test cases that require this Library, not all test execution.
Thank you!
The problem is that the exception is raised during library loading, since it is in the top level of module. ROBOT_EXIT_ON_FAILURE only effects if the failure comes from a keyword.
Instead, do this:
def get_path():
path = global_settings.get_rdio_base_path()
if path == "":
raise PathRequiredError("Path is required...")
def some_keyword():
path = get_path()
...
Now the exception is raised inside a keyword, and the test execution will be stopped.
As for the other point, there's no way to abort just some tests using ROBOT_EXIT_ON_FAILURE.

Categories

Resources