Django test returns 404 error - python

I'm using the django test framwork to test my API. I have a simple view that returns "ok" at the address GET http://localhost:8000/v1/ping/. When I run the server and I test this with Chrome, it works well. However, when I launch a test on it, I get a 404 error. This is my test:
def test_ping(self):
c = Client()
response = c.get('/v1/ping/')
print response.content
print response.status_code
and the response:
<h1>Not Found</h1><p>The requested URL /v1/ping/ was not found on this server.</p>
404

The get method on Django's Test Client takes a relative path as an argument. Have you tried response = c.get('/v1/ping/')?

I found the error: I use rest_framework_swagger and there was a test file in it. I deleted it and everything is OK now.

Related

Django test for 404 erroring because Client expects 200?

I am trying to test my 404 page to ensure certain elements are present on it.
My test looks like this:
class TestApp404PageIncludesLink(TestCase):
def setUp(self):
superuser = UserFactory(is_superuser=True, is_staff=True)
self.client.force_login(superuser)
def test_superuser_can_see_link(self):
response = self.client.get("404")
self.assertTrue(response.status_code == 404)
self.assertContains(response, 'href="/special_link/">Specialty</a>')
I am running this test as a logged in user - other tests for other views work fine.
I'm trying to check the 404 page.
It fails with this:
Couldn't retrieve content: Response code was 404 (expected 200)
200 != 404
How do I set up the test so it knows I am trying to get a 404?
The issue had to do with me not reading the documentation thoroughly enough apparently.
The assertContains takes a status_code argument that by default assumes a status of 200, which a 404 is not. Once I added that to the assertion it was resolved.
def test_superuser_can_see_link(self):
response = self.client.get("404")
self.assertTrue(response.status_code == 404)
self.assertContains(response, 'href="/special_link/">Specialty</a>', status_code=404)

Python request.url not returning full url that is shown in the browser

I am implementing Signin via Microsoft Auth in my App. When I go to authorization url and provide my credentials, the app redirects to my redirect uri. In the browser I am getting this url "http://localhost:5000/app/microsoft_signin/callback#code=M.R3_BAY.bc055b02-10a5-be57-8933-191cbb5d6b1d&state=12345" but when I try to get this url using request.url, I am getting only this part of the url "http://localhost:5000/app/microsoft_signin/callback".
Here is my code:
app.route("/app/microsoft_signin",methods=['GET','POST'])
def microsoft_signin_():
authorization_url = f'{MICROSOFT_CONFIG["MICROSOFT_AUTHORIZATION_URL"]}?client_id={MICROSOFT_CONFIG["MICROSOFT_CLIENT_ID"]}&response_type=code&redirect_uri={MICROSOFT_CONFIG["MICROSOFT_REDIRECT_URI"]}&response_mode=fragment&scope={MICROSOFT_CONFIG["MICROSOFT_SCOPE"]}&state=12345'
return redirect(authorization_url)
#app.route("/app/microsoft_signin/callback",methods=['POST','PUT','GET'])
def microsoft_signin_callback_():
print('!!! CALL BACK HIT SUCCESSFULLY !!!')
print(f'Returned URL is: {request.url}') // http://localhost:5000/app/microsoft_signin/callback
Is there any other way to get this complete url? Also I found something strange with the returned url. Before "code", I am getting # instead of ?, due to which I am unable to get the code using this line code = request.args.get("code")
Replace response_mode=fragment with response_mode=query

Python Django url reverse in unittest returns a 404

url:
path('some/path_to/<int:special_id>/', some_views.someAPI.as_view(), name="someAPI")
Normally when accessing the API with https://some_domain/some/path_to/1, I can get the data with special_id=1. No issue here.
However, when I run a test which contains the reverse() function, the special_id doesn't seem to be loaded.
I'm doing
url = reverse('someAPI', kwargs={'special_id': 1})
request = self.factory.get(url)
force_authenticate(request, user=self.user)
response = someAPI.as_view()(request, special_id=1)
it gave me a 404: Not found when I expect a 200
I checked the path, and it seems to be correct. I'm wondering why I'm receiving a 404. This is running through django unittest.
EDIT:
Turns out I didn't save the object in the test db. Make sure you call save() when creating object.....
During a test a new database called "test_dbname" is created and flushed immediately. You have to create the element with id: 1 before the reverse() function.
And what if you do:
reverse('someAPI', args=[1]

how to redirect to a external 404 page python flask

I am trying to redirect my 404 to a external URL like this:
#app.route('404')
def http_error_handler(error):
return flask.redirect("http://www.exemple.com/404"), 404
but it does not work. I keep getting:
Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
You should try something like this:
from flask import render_template
#app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
Source http://flask.pocoo.org/docs/1.0/patterns/errorpages/
You cannot do this - the user-agent (in most cases, a browser) looks at the status code that is returned to determine what to do. When you return a 404 status code what you are saying to the user-agent is, "I don't know what this thing is you are requesting" and the user-agent can then:
Display what you return in the body of the response
Display its own error message to the end user
Do some combination of the above two options
redirect actually creates a little HTML response (via werkzeug.exceptions), which normally the end user doesn't see because the user-agent follows the Location header when it sees the 302 response. However, you override the status code when you provide your own status code (404).
The fix is to either:
Remove the status code (at the cost of sending the wrong signal to the end user, potentially)
or Send a 404 with a meta:refresh and / or JavaScript redirect (slightly better, still confusing):
return redirect("/where-ever"), 404, {"Refresh": "1; url=/where-ever"}
Try this instead of a route
from flask import request
#app.errorhandler(404)
def own_404_page(error):
pageName = request.args.get('url')
print(pageName)
print(error)
f = open('erreur404.tpl')
return f.read()

Urllib - HTTP 403 error with no message (Facebook notification)

I have successfully used the following Python code, running on a Google App Engine server on localhost, to send Facebook notifications to myself. I use the template feature of Facebook notifications to expand a Facebook user ID into a bolded name in the text of the notification:
url = 'https://graph.facebook.com/'+myOwnID+'/notifications'
values = {'access_token' : 426547656256546|4fhe34FJdeV3WvfF6SNfehs7GfW
'href' : 'http://localhost:8080/',
'template' : '#['+myOwnID+'] says hi.'}
req = urllib2.Request(url, urllib.urlencode(values))
urllib2.urlopen(req)
Note that the app access token is made-up, but has the same format as a real token.
When I change the template's ID to the ID of one of my friends:
url = 'https://graph.facebook.com/'+myOwnID+'/notifications'
values = {'access_token' : 426547656256546|4fhe34FJdeV3WvfF6SNfehs7GfW
'href' : 'http://localhost:8080/',
'template' : '#['+myFriendID+'] says hi.'}
req = urllib2.Request(url, urllib.urlencode(values))
urllib2.urlopen(req)
I get the error
HTTP Error 403: Forbidden
It works the same even if I hard-code the IDs into the template, so it's not an issue of incorrect variable values.
Why does the second case not work? How can I fix it?
I didn't realize that urllib2 can print a more detailed error message than just the status code, by replacing the last line with:
try:
urllib2.urlopen(req)
except urllib2.HTTPError, error:
logging.info(error.read()) # or "print error.read()"
This gives the clear error message:
{"error":{"message":"(#200) Cannot tag users who have not installed the app","type":"OAuthException","code":200}}
For a fuller discussion of urllib2's behaviour with 403 status codes, see 1, 2 and 3.
It appears, according to your error message, that your friend has to install your app in order for you to send them notifications. There's nothing you can do to fix that.

Categories

Resources