Django Test Client client.post() sends GET request in my Testcase - python

How can I submit a POST request with Django test Client? I just want to test the login function of my application. It's strange that I put
response = self.client.post(reverse('rbac:login'), data=data) in my testcase, and I want to validate it so I print response.status_code.Actually it should return 302 coz it should turn to another page. but it return 200. This situation happens when I use "python manage.py test testmodel" to test. However, if I use "python manage.py shell" to make an InteractiveConsole and write exactly the same code, it return 302 at last.
I have nearly tried all the methods provided from stack overflow, e.g. change the url, offer the content-type when I post....but these are meaningless.
from django.test import TestCase
from django.test.utils import setup_test_environment,teardown_test_environment
from django.test import Client
from django.urls import reverse
import django
from rbac.models import RbacUser, RbacRole
from system_module.models import Redeploy
from urllib import urlencode
class CreateUser(TestCase):
#classmethod
def setUp(self):
self.client = Client()
def test_create_user(self):
data = {"Username": "admin_xy", "Password": "aaa"}
response = self.client.post(reverse('rbac:login'), data=data)
print response
and it shows me 200.....
However, in interactive console:
>>> response = client.post(reverse('rbac:login'), data=data)
>>> print response.status_code
302
it shows the right result.
I want to know how to cope with this annoying problem. Thx
I expect when I use test file to test my test case, it works fine....like show 302 code.

Before sending the POST or GET request by using Client, first you need to create the user make the user active and give necessary permissions and login through client and then send the post request.
Ex: self.client.login(username='username', 'password'='password)

It's been long time that this question is here, I hope you found the answer, but for other people I'll suggest to add this to this code to be redirected:
response = self.client.post(reverse('rbac:login'), data=data, follow=True)
The follow=True will follow the redirect .

Related

Can't access or print any request data with FastAPI

I have a simple FastAPI endpoint, where I want to receive a string value. In this case, I tried it with a JSON body, but basically it doesn't need to be JSON. I really need only a simple string to separate the requests from each other. Unfortunately, I can't access any of the request parameters with a GET method. I also tried POST method instead, but I get an error:
request:
url = "http://127.0.0.1:5000/ping/"
payload=json.dumps({"key":"test"})
headers = {
"Content-Type": "application/json"
}
response = requests.request("POST", url, headers=headers, json=payload)
print(response.text)
api:
#app.get("/ping/{key}")
async def get_trigger(key: Request):
key = key.json()
test = json.loads(key)
print(test)
test2 = await key.json()
print(key)
print(test2)
return
I can't print anything with post or put:
#app.post("/ping/{key}")
async def get_trigger(key: Request):
...
or
#app.put("/ping/{key}")
async def get_trigger(key: Request):
I get a 405 Method not allowed error.
How can I get this fixed?
The 405 Method Not Allowed status code indicates that "the server knows the request method, but the target resource doesn't support this method". You get this error when you attempt, for instance, to send a POST request to a GET route (as shown in your first example). This, however, is not the only issue with your code (on both client and server sides). Below is given an example on how to achieve what you described in the question using Path parameters. The same could be achieved using Query parameters, as well as Request Body. Please have a look at Python requests documentation on how to specify the parameters/body for each case. I would also highly suggest to take the FastAPI tutorial online—you'll find most of the answers you are looking for there.
app.py
from fastapi import FastAPI
app = FastAPI()
#app.get("/ping/{ping_id}")
async def get_trigger(ping_id: str):
return {"ping_id": ping_id}
test.py
import requests
url = 'http://127.0.0.1:8000/ping/test1'
resp = requests.get(url=url)
print(resp.json())

django csrf_token verification with python requests module

I want to send post request using python requests module. Since, I use Django for backend server. So, I need verify csrf_token for post method. I know that i have option to stop csrf_token verification using Django built in decorators. But, i don't want to do that for cross site protection.
My Django Sample Code:
from django.http import HttpResponse
from django.middleware.csrf import get_token
def pv(v, s):
print(f"----------Value of {s}-------")
print(f"Type= {type(v)}")
print()
print(v)
print()
def index(request):
pv(request.COOKIES,"HttpRequest.COOKIES")
pv(request.headers,"HttpRequest.headers")
token = get_token(request) # I think, Here have some worng. But What?
return HttpResponse("Hello World")
index() is work for both get and post reequest. Though i don't use redirect() for post method in sample code. Here is my get and post request code using python requests module:
import requests
import time
def pv(obj, s):
print(f"-----Value of {s} --------")
print(type(obj))
print(obj)
print()
url = "http://192.168.0.102:8000/home/"
data = {"a":"5", "b":4}
d = requests.get(url)
time.sleep(2)
requests.post(url, cookies=d.cookies, data=data)
# For Test
pv(d.headers, "d.headers")
pv(d.cookies['csrftoken'], "d.cookies")
get request work properly and return me csrf_token.when i use this toke with post method. Django server give me Forbidden (CSRF token missing or incorrect.): /home/ error and post request doesn't work properly. How can i verify csrf_token?

How to make a request inside a simple mitmproxy script?

Good day,
I am currently trying to figure out a way to make non blocking requests inside a simple script of mitmproxy, but the documentation doesn't seem to be clear for me for the first look.
I think it's probably the easiest if I show my current code and describe my issue below:
from copy import copy
from mitmproxy import http
def request(flow: http.HTTPFlow):
headers = copy(flow.request.headers)
headers.update({"Authorization": "<removed>", "Requested-URI": flow.request.pretty_url})
req = http.HTTPRequest(
first_line_format="origin_form",
scheme=flow.request.scheme,
port=443,
path="/",
http_version=flow.request.http_version,
content=flow.request.content,
host="my.api.xyz",
headers=headers,
method=flow.request.method
)
print(req.get_text())
flow.response = http.HTTPResponse.make(
200, req.content,
)
Basically I would like to intercept any HTTP(S) request done and make a non blocking request to an API endpoint at https://my.api.xyz/ which should take all original headers and return a png screenshot of the originally requested URL.
However the code above produces an empty content and the print returns nothing either.
My issue seems to be related to: mtmproxy http get request in script and Resubmitting a request from a response in mitmproxy but I still couldn't figure out a proper way of sending requests inside mitmproxy.
The following piece of code probably does what you are looking for:
from copy import copy
from mitmproxy import http
from mitmproxy import ctx
from mitmproxy.addons import clientplayback
def request(flow: http.HTTPFlow):
ctx.log.info("Inside request")
if hasattr(flow.request, 'is_custom'):
return
headers = copy(flow.request.headers)
headers.update({"Authorization": "<removed>", "Requested-URI": flow.request.pretty_url})
req = http.HTTPRequest(
first_line_format="origin_form",
scheme='http',
port=8000,
path="/",
http_version=flow.request.http_version,
content=flow.request.content,
host="localhost",
headers=headers,
method=flow.request.method
)
req.is_custom = True
playback = ctx.master.addons.get('clientplayback')
f = flow.copy()
f.request = req
playback.start_replay([f])
It uses the clientplayback addon in order to send out the request. When this new request is sent, that will generate another request event which will then be an infinite loop. That is the reason for the is_custom attribute I added to the request there. If the request that generated this event is the one that we have created, then we don't want to create a new request from it.

How to test `#authenticated` handler using tornado.testing?

I am new to unit testing using script. I tried to verify login with arguments in post data, but I am getting login page as response and not get logged in.Because of #tornado.web.authenticated i can't access other functions without login and it responding to login page
import tornado
from tornado.testing import AsyncTestCase
from tornado.web import Application, RequestHandler
import app
import urllib
class MyTestCase(AsyncTestCase):
#tornado.testing.gen_test
def test_http_fetch_login(self):
data = urllib.urlencode(dict(username='admin', password=''))
client = AsyncHTTPClient(self.io_loop)
response = yield client.fetch("http://localhost:8888/console/login/?", method="POST",body=data)
# Test contents of response
self.assertIn("Automaton web console", response.body)
#tornado.testing.gen_test
def test_http_fetch_config(self):
client = AsyncHTTPClient(self.io_loop)
response = yield client.fetch("http://localhost:8888/console/configuration/?")
self.assertIn("server-version",response.body)
To test code that uses #authenticated (unless you are testing the redirection to the login page itself), you need to pass a cookie (or whatever form of authentication you're using) that will be accepted by your get_current_user method. The details of this will vary depending on how exactly you are doing your authentication, but if you're using Tornado's secure cookies you'll probably use the create_signed_value function to encode a cookie.
From documentation:
If you decorate post() methods with the authenticated decorator, and the user is not logged in, the server will send a 403 response. The #authenticated decorator is simply shorthand for if not self.current_user: self.redirect() and may not be appropriate for non-browser-based login schemes.
So you can use mock do like pointed in this answer: https://stackoverflow.com/a/18286742/1090700
Another 403 status will be thrown on POST calls if you have secure_cookies=True app param. If you want to test the code in a non debug fashion, you can also using mock POST actions while keeping the secure_cookies=True application parameter and then just mock the check_xsrf_cookie Handler method as well, like this:
# Some previous stuff...
with mock.patch.object(YourSecuredHandler, 'get_secure_cookie') as mget:
mget.return_value = 'user_email'
response = self.fetch('/', method='GET')
with mock.patch.object(
YourSecuredHandler, 'check_xsrf_cookie') as mpost:
mpost.return_value = None
response = self.fetch(
url, method="POST", body=parse.urlencode(body1),
headers=headers)
self.assertEqual(response.code, 201)

Django: set cookie on test client?

My Django site is set up with some middleware that on each request, checks for a cookie, and if it is not set, forwards the user elsewhere.
I now want to run some tests on the site. This is my code:
def test_contactform(self):
response = self.client.get('/contact/')
self.assertEqual(response.status_code, 200)
print response
self.assertTrue('Contact me' in response.content)
Unfortunately, this fails with:
Vary: Cookie
Content-Type: text/html; charset=utf-8
Location: http://testserver/ldap/?next=/contact/
Traceback (most recent call last):
File "tests.py", line 43, in test_contactform
self.assertEqual(response.status_code, 200)
AssertionError: 302 != 200
Can I either (i) set a cookie on the Django test client (and if so how) or (ii) require the Django test client to follow the redirect and test against the final page?
None of the above worked for me (Django1.9, Python3.4). Found this solution here:
from django.test import TestCase
from http.cookies import SimpleCookie
class TestViewWithCookies(TestCase):
def test_votes(self):
self.client.cookies = SimpleCookie({'name': 'bla'})
response = self.client.get('/vote/2')
self.assertEqual(response.status_code, 200)
While the accepted answer is the right approach for this problem, I just want to point out that you can set cookies directly (i.e. approach number (i) as you call it), but not via the test client. Instead you need to use a RequestFactory to construct a request which you can set the cookie on, then pass that directly to the view in question.
So instead of:
response = self.client.get('/contact/')
you do:
request = RequestFactory().get('/contact/')
request.COOKIES['thing'] = 'whatever'
response = contact_view(request)
where contact_view is the view serving /contact/.
You can set cookies for test client by calling load on cookies attribute which is SimpleCookie object.
from django.core import signing
self.client.cookies.load({
'example': '123',
'signed_example': signing.get_cookie_signer('signed_example').sign('123')
})
Django's test client is stateful - will persist cookies between tests and will ignore expire dates. For removal, you need to manually remove cookie or create a new client. - See docs
--- For Python 3 and Django 2+
The client.get method takes a follow argument which allows it to follow redirects:
response = self.client.get('/contact/', follow=True)
This is an old question but maybe this is handy for someone:
from http.cookies import SimpleCookie
from django.test import TestCase, Client
class CookieClientTests(TestCase):
def test_cookie(self):
cookies = SimpleCookie()
cookies["cookie_key"] = "something"
client = Client(HTTP_COOKIE=cookies.output(header='', sep='; '))
resp = client.get("/")
self.assertEqual(200, resp.status_code)

Categories

Resources