Django TestCase do not pass anymore: wrong url - python

I develop a DJango project and have develop few tests
One of these tests used to pass but do not anymore and I do not understand why
class IndexPageTestCase(TestCase):
def setUp(self):
self.client = Client()
self.pays = Pays.objects.create(pay_ide = 1,pay_nom = 'Côte d\'Ivoire',pay_abr = 'CIV')
self.region = Region.objects.create(reg_ide = 1,pay = self.pays,reg_nom = 'Region 1',reg_abr = 'RE1')
self.site = Site.objects.create(sit_ide = 1,reg=self.region,sit_typ = 'National',sit_nom = 'PA',sit_abr = 'PA')
self.user = User.objects.create_user('user','user#user.com','password')
self.profile = Profile.objects.create(user=self.user,site = self.site)
def test_index_page(self):
self.client.post('/registration/login/', {'username': 'user', 'password': 'password'})
response = self.client.get(reverse('randomization:index'))
print(response)
self.assertEquals(response.status_code,200)
print show it is not the good url (/accounts/login/?next=/randomization/ instead of /registration/login/):
<HttpResponseRedirect status_code=302, "text/html; charset=utf-8", url="/accounts/login/?next=/randomization/">

The url you pass returns a 302 which means redirect.
Your URL is good but is just redirected. set your assertEquals status code to 302

Related

Django Test User Login With Factory And setUpClass

I am trying to test a user login with setUpClass, but the credentials of the saved user do not get accepted (403) during authentification although it works if I register the user manually (but I wanted to omit that for all functions so I do not have to do that, that's why I looked up setUpclass())
Am I missing something? test_register() works just fine.
class AuthenticationTest(APITestCase):
#classmethod
def setUpClass(cls):
super(AuthenticationTest, cls).setUpClass()
cls.user_object = UserFactory.build()
cls.user_saved = UserFactory.create()
cls.client = APIClient()
cls.base_url_login = reverse("api:login-list")
cls.base_url_register = reverse("api:register-list")
cls.base_url_logout = reverse("api:logout-list")
cls.base_url_check_session = reverse("api:check-session-list")
cls.faker_obj = Faker()
def test_register(self):
# Prepare data
signup_dict = {
'username': self.user_object.username,
'password': 'test_Pass',
'email': self.user_object.email,
}
# Make request
response = self.client.post(
self.base_url_register, signup_dict
)
# Check status response
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
response_data = response.json()
self.assertEqual(response_data["success"], True)
self.assertEqual(User.objects.count(), 2)
# Check database
new_user = User.objects.get(username=self.user_object.username)
self.assertEqual(
new_user.email,
self.user_object.email,
)
def test_login(self):
# Prepare Data
login_dict = {
'password': self.user_saved.password,
'email': self.user_saved.email,
}
# Make request
response = self.client.post(self.base_url_login, login_dict)
# Check status response
self.assertEqual(response.status_code, status.HTTP_200_OK)
response_data = response.json()
self.assertEqual(response_data["success"], True)
...
class UserFactory(django.DjangoModelFactory):
class Meta:
model = User
username = Faker("user_name")
email = Faker("email")
#post_generation
def password(self, create: bool, extracted: Sequence[Any], **kwargs):
password = (
extracted
if extracted
else FakerClass().password(
length=30,
special_chars=True,
digits=True,
upper_case=True,
lower_case=True,
)
)
self.set_password(password)

How to write a unit test on Django REST API endpoint that has permission_classes = (IsAuthenticated,)

Hello everyone I'm looking to write unit test on my django app, in order to test the different API endpoint but it seems like i can't figure our the problem here is a snap code of what i have done so far :
urls.py :
path('translate/display/', DisplayTranslation.as_view(), name='display_translation'),
it's corresponding DRF view.py :
class DisplayTranslation(generics.ListAPIView):
queryset = Translation.objects.all()
serializer_class = TranslationSerializers
permission_classes = (IsAuthenticated,)
and here is what I have done so far on my unit test.py :
apiclient = APIClient()
class TranslationTestCases(APITestCase):
def setUp(self):
self.role = baker.make(Roles)
self.user = baker.make(Users, user_role=self.role)
self.token = reverse('token_obtain_pair', kwargs={'email': self.user.email, 'password': self.user.password})
self.translation = baker.make(Translation, _quantity=10)
def test_get_all_translations(self):
header = {'HTTP_AUTHORIZATION': 'Token {}'.format(self.token)}
response = self.client.get(reverse('display_translation'), {}, **header)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 10)
This is the error I'm getting when I run the test :
in _reverse_with_prefix raise NoReverseMatch(msg) django.urls.exceptions.NoReverseMatch: Reverse for 'token_obtain_pair' with keyword arguments '{'email': 'dZbQNWCjif#example.com', 'password': 'PfQzPqqVVLAdLZtJyVUxVjkGJEgRABYdHxMRhCGZJWxnZxpxEgUkgUKklENrWlBiYOCxhaDtJXdtXCtNdOJYtSWTzIrdvPnrmezXBNjEYYTpyZWjOLMnMIBMAfYnLwcC'}' not found. 1 pattern(s) tried: ['token/$']
Some more info, in the authentication on my Django app, I worked with DRF, rest_auth & SimpleJWT library.
What I could do to improve my code? or an alternative solution? I couldn't find a similar problem to mine.
You can basically use
#patch.object(DisplayTranslation, "permission_classes", [])
def test_get_all_translations(self):
...
https://docs.python.org/3/library/unittest.mock.html#patch-object
With Authentication:
urlpatterns = [
...
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
...
]
class TranslationTestCases(APITestCase):
def setUp(self):
self.api_client = APIClient()
self.role = baker.make(Roles)
self.user = baker.make(Users, user_role=self.role)
self.token_url = reverse('token_obtain_pair')
self.translation = baker.make(Translation, _quantity=10)
response = self.api_client.post(self.token_url, {"username": self.user.username, "password": self.user.password})
self.token = response.json()["access"]
def test_get_all_translations(self):
header = {'HTTP_AUTHORIZATION': 'Bearer {}'.format(self.token)}
...
https://django-rest-framework-simplejwt.readthedocs.io/en/latest/getting_started.html

Python Mocking a request for a bearer token?

I'm trying to figure out how to mock my request for a bearer token in python.
I have a class:
class grab_apitokens(object):
def __init__(self, consumer_key, first_api_url, second_api_user, second_api_password, second_api_url):
self.consumer_key = consumer_key
self.second_api_user = second_api_user
self.second_api_password = second_api_password
self.first_api_url = first_api_url
self.second_api_url = second_api_url
def logintofirstsite(self):
b64val = base64.b64encode(self.consumer_key.encode()).decode()
headers = {"Authorization": "Basic %s" % b64val}
data = {'grant_type': 'client_credentials', 'validity_period': '3600'}
try:
response = requests.post(self.first_api_url, headers=headers, data=data)
decodedresponse = json.loads(response.content.decode())
access_token = decodedresponse['access_token']
return access_token
except:
return None
def logintosecondsite(self):
header = {"accept": "application/json", "Content-Type": "application/x-www-form-urlencoded"}
logindata = {'grant_type': 'password',
'username': "" + self.second_api_user + "", 'password': "" + self.second_api_password + ""
}
try:
returnedfromsite = requests.post(self.second_api_url + '/api/V1/token',
headers=header, data=logindata)
return returnedfromsite.json()['access_token']
except:
return None
What I can't figure out is how to mock that requests call and what it would look like in Python.
My test currently looks like:
class MyTestCase(unittest.TestCase):
def setUp(self) -> None: # PROBLEM BEGINS HERE
self.grab_apitokens = grab_apitokens(actual_key, actual_site1, actual_user, actual_pass, actual_2nd_site)
#patch('grab_apitokens.requests.get')
def test_login(self, mock_get):
mock_get.return_value.ok = True
response = self.grab_apitokens.logintosite()
assert_is_not_none(response)
# self.assertEqual(True, False)
if __name__ == '__main__':
unittest.main()
How would I mock the requests.post functionality?
With the help of a good mentor I figured out that my approach was all wrong. Here's what I ended up with for the unit test:
class MyTestCase(unittest.TestCase):
def setUp(self) -> None:
self.grab_apitokens = grab_apitokens("complete","gibberish","it really doesnt","matter","what is","in","here")
#patch('grab_apitokens.requests.posts')
def test_login(self, mock_get):
mock_json = {'token': 'foo'}
mock_get.return_value = Mock(ok=True)
mock_get.return_value.json.return_value = mock_json
mock_get.return_value.content = b'{"token": "foo"}'
response = self.grab_apitokens.logintofirstsite()
assert_equal(response, "foo")
if __name__ == '__main_
To understand what this does, I needed to know that what we're really mocking isn't the method logintofirstsite(), we're mocking the response that requests.post is making in the method. With mock_get, we're inject requests.posts to always be: {'token': 'foo'} . So everything after
response = requests.post(self.first_api_url, headers=headers, data=data)
in logintofirstsite() is what I'm really testing. Which is:
decodedresponse = json.loads(response.content.decode())
access_token = decodedresponse['token']
return access_token
The setup before the requests.post call doesn't matter one bit. Since with {'token': 'foo'} is what my requests.post call returns, the returned value after that bit of logic is 'foo', and so the assert_equal back in MyTestCase passes.

datas' session not well managed with pyramid_beaker

I have the following codes, I'm using pyramid_beaker + gunicorn + pyramid_jinja2.
I noticed that when user is logged in, if I quickly and repeatedly do a "GET" to "http://my_server_ip_adress/addClientPersonne", I got many times a permission deny as if the logged user doesn't have "add_client" permission which is not normal. When making a "print session" I can see that sometimes the session has all the authentications informations to allow user to access the link above but another time it doesn't and the access is deny...maybe my configurations about pyramid_beaker are not good? any suggestions?
thanks.
my production.ini file
[app:main]
use = egg:annuaireldap#main
pyramid.includes = pyramid_beaker
pyramid_jinja2
session.key = annuaireldap
session.secret = iuyryoiuiytghvfs-tifrsztft
session.cookie_on_exception = true
session.type = memory
my views.py
#view_config(route_name="Menu", renderer='templates/menu.jinja2', request_method='GET')
def menu(request):
bootstrap_css_url = request.static_url('annuaireldap:static/bootstrap.min.css')
bootstrap_js_url = request.static_url('annuaireldap:static/bootstrap.min.js')
jquery_js_url = request.static_url('annuaireldap:static/jquery.min.js')
custom_css_url = request.static_url('annuaireldap:static/custom_css.css')
to_rend = {'bootstrap_css':bootstrap_css_url,'bootstrap_js':bootstrap_js_url,'jquery_js':jquery_js_url,'custom_css':custom_css_url}
to_rend.update({'Menu_1':request.route_url('addClientPersonne'),
'Menu_2':request.route_url('addClientEntreprise'),
'Menu_3':request.route_url('SeeAll')})
return to_rend
#view_config(route_name='SeeAll', renderer='templates/menu.jinja2', request_method=('GET', 'POST'))
def seeall(request):
return {}
#view_config(route_name='login', renderer='templates/login.jinja2',
request_method=('GET', 'POST'))
def login(request):
bootstrap_css_url = request.static_url('annuaireldap:static/bootstrap.min.css')
bootstrap_js_url = request.static_url('annuaireldap:static/bootstrap.min.js')
jquery_js_url = request.static_url('annuaireldap:static/jquery.min.js')
custom_css_url = request.static_url('annuaireldap:static/custom_css.css')
settings = request.registry.settings
server_uri = settings['server_uri']
rendered_form = None
base_dn_user = settings['base_dn_user']
cl = Credentials().bind(request=request)
se_connecter = deform.form.Button(name='se_connecter',
title='se connecter')
form = deform.form.Form(cl, buttons=(se_connecter,))
url_redirect = request.route_url('login')
session = request.session
session.save()
if authenticated_userid(request):
url_redirect = request.route_url("Menu")
resp = HTTPFound(location=url_redirect)
return request.response.merge_cookies(resp)
if request.method == 'POST':
if 'se_connecter' in request.POST:
try:
deserialized = form.validate(request.POST.items())
username = deserialized['username']
password = deserialized['password']
server = Server(server_uri)
user_dn = 'uid=%s,%s'%(username, base_dn_user)
user_dn = 'cn=admin,dc=splynx,dc=lan'
password = '1235789'
conn = Connection(server, user=user_dn, password=password)
if conn.bind():
session[username] = ['agent']
remember(request, username)
url_redirect = request.route_url('Menu')
resp = HTTPFound(location=url_redirect)
return request.response.merge_cookies(resp)
except ValidationFailure as e:
rendered_form = e.render()
else:
rendered_form = form.render()
return {'bootstrap_css':bootstrap_css_url,
'bootstrap_js':bootstrap_js_url,
'jquery_js':jquery_js_url,
'rendered_form':rendered_form,
'custom_css':custom_css_url}
#view_config(route_name='addClientPersonne', permission='add_client',
request_method=('GET', 'POST'), renderer='templates/addPersonne.jinja2')
def addClientPersonne(request):
bootstrap_css_url = request.static_url('annuaireldap:static/bootstrap.min.css')
bootstrap_js_url = request.static_url('annuaireldap:static/bootstrap.min.js')
jquery_js_url = request.static_url('annuaireldap:static/jquery.min.js')
custom_css_url = request.static_url('annuaireldap:static/custom_css.css')
rendered_form = None
settings = request.registry.settings
cl = ClientPersonne().bind(request=request)
ajouter = deform.form.Button(name='Ajouter',
title='Ajouter')
form = deform.form.Form(cl, buttons=(ajouter,))
request.session.save()
if request.method == 'POST':
if 'Ajouter' in request.POST:
try:
server_uri = settings['server_uri']
server = Server(server_uri)
deserialized = form.validate(request.POST.items())
nom = deserialized['nom']
prenom = deserialized['prenom']
telephone = deserialized['telephone']
description = deserialized['description']
description = "" if description == colander.null else description
creator_dn = settings['creator_dn']
creator_pwd = settings['creator_pwd']
conn = Connection(server, user=creator_dn, password=creator_pwd)
base_clients_personnes = settings['base_clients_personnes']
new_user_dn = 'uid=%s,%s'%(get_token(14), base_clients_personnes)
if conn.bind():
attributes = {'telephoneNumber':telephone,
'sn':nom,
'cn':prenom}
if description:
attributes['description'] = description
conn.add(new_user_dn, ['person', 'uidObject'], attributes)
conn.unbind()
url_redirect = request.route_url('Menu')
resp = HTTPFound(location=url_redirect)
return request.response.merge_cookies(resp)
except ValidationFailure as e:
rendered_form = e.render()
except Exception as e:
rendered_form = form.render()
else:
rendered_form = form.render()
return {'bootstrap_css':bootstrap_css_url,
'bootstrap_js':bootstrap_js_url,
'jquery_js':jquery_js_url,
'rendered_form':rendered_form,
'custom_css':custom_css_url}
my root factory
class CustomResourceFactory():
__acl__ = [
(Allow, 'agent', {'add_client', 'modify_client', 'view_client', 'delete_client'}),
DENY_ALL
]
def __init__(self, request):
print "concombre"
pass
If you have gunicorn configured to fork then you can't use an in-memory session store as it will not be shared across processes. You can confirm that this is the issue by turning off forking in gunicorn or switching to a wsgi server like waitress that does not fork.
The issue is with the gunicorn multiple workers. If you run this code with single worker it will run fine. The user session in is in memory for that worker and will not accessible from other workers.
So when you login the user details will be with only that worker and when hit the next GET call the request will go to the different worker where it will not get the user details and it will deny your request.

Getting back a nonexistant url in test

So I have a django web app called notes where I have a viewset. The viewset is composed of CRUD commands. When I created a test to the api it keeps redirecting to a nonexistent url instead of the Json String. Here is my code:
For tests.py:
def test_list(self):
e = Employee.objects.get(first_name="Dylan")
organ = Organization.objects.get(name='test')
cl = APIClient()
# cl = APIClient()
c = Customer.objects.get(first_name="John")
cl.credentials(HTTP_AUTHORIZATION='Token ' + organ.token.key)
response = cl.post('/api/notes/list', {'customer_id': c.uuid}, follow=True)
#cl.login(username = "Dylan", password="Snyder")
pprint("list: %s" % response.data)
for api.py:
def list(self, request):
c = Customer.objects.get(pk=request.POST['customer_id'])
n = Note.objects.get(customer=c, retired=False)
notes = NoteListSerializer(n)
return HttpResponse(notes)
The results I get:
.'list: {\'detail\': \'Method "GET" not allowed.\'}'
in the command prompt I use. I never made a directory or have anything that contains /details/ in it

Categories

Resources