diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/.env b/Project1_Simple_REST_API/RestDjango/django_restframework/.env index cd4bb2a..ff2da6e 100644 --- a/Project1_Simple_REST_API/RestDjango/django_restframework/.env +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/.env @@ -1,2 +1,3 @@ -SECRET_KEY='$2t!11nw4*dvhcuhc3b=)6-@-m$r$^9r9s9^_arq(m3-p4^c_=' +export SECRET_KEY='$2t!11nw4*dvhcuhc3b=)6-@-m$r$^9r9s9^_arq(m3-p4^c_=' + diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/.gitignore b/Project1_Simple_REST_API/RestDjango/django_restframework/.gitignore index c7a0414..5cd64c2 100644 --- a/Project1_Simple_REST_API/RestDjango/django_restframework/.gitignore +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/.gitignore @@ -107,7 +107,7 @@ celerybeat.pid # SageMath parsed files *.sage.py - +../.vscode/ # Environments .venv env/ diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/__init__.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/api_views_pytest.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/api_views_pytest.py new file mode 100644 index 0000000..ca1286f --- /dev/null +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/api_views_pytest.py @@ -0,0 +1,343 @@ +from api.views import CreateUser,UserList,UserDetail, Todos,TodoOperations,Login,RefreshToken +from django.contrib.auth import get_user_model +from api.serializer import UserSerializer +from django.test import TestCase, Client +from rest_framework.test import APIRequestFactory +from rest_framework.test import APIClient +from api.models import Todo +from rest_framework.test import APITestCase +from django.urls import reverse +import pytest +import time +User = get_user_model() + + + + +@pytest.mark.django_db +def create_user_test(client,setup): + + path = reverse("user_create") + + response = client.post(path,setup.get("user"),format='json') + + assert response.status_code == 201 + + response_2 = client.post(path, setup.get("user"), format='json') + + assert response_2.status_code == 400 + + user = User.objects.filter(id=1).first() + + assert user.first_name == "test_user" + assert user.username == "testname" + assert user.email == "test@gmail.com" + + +@pytest.mark.django_db +def user_list_test(client): + + path = reverse("user_list") + + response = client.get(path) + + assert response.status_code == 200 + + + +def user_detail_test(client): + user = User.objects.create( + first_name="test_user", + username="testname", + password="test12345", + email="test@gmail.com", + last_name="testlastname" + ) + + path = reverse("user_detail",args="1") + + + response = client.get(path,format='json') + + assert response.status_code == 200 + + assert user.first_name == response.json().get("first_name") + assert user.username == response.json().get("username") + assert user.email == response.json().get("email") + assert user.last_name == response.json().get("last_name") + + + +def user_detail_test(client): + path = reverse("user_detail",args="1") + + new_user = User.objects.create( + first_name="test_user", + username="testname", + password="test12345", + email="test@gmail.com", + last_name="testlastname" + ) + data = {"first_name": "TuralYek"} + + + response = client.put(path,data,format='json') + + + edited_user = User.objects.filter(id=1).first() + + assert response.status_code == 200 + + assert edited_user.first_name == response.json().get("first_name") + + +@pytest.mark.django_db +def user_detail_test(client): + + new_user = User.objects.create( + first_name="test_user", + username="testname", + password="test12345", + email="test@gmail.com", + last_name="testlastname" + ) + + path = reverse("user_detail",args="1") + + response = client.delete(path,format='json') + assert response.status_code == 200 + + + assert User.objects.filter(id=1).first() == None + + +@pytest.mark.django_db +def login_test(): + client = APIClient() + + user = User.objects.create_user( + username="test_user", + password="test_password", + ) + + path = reverse("login") + + response = client.post(path,{"username":"test_user","password":"test_password"},format='json') + + + assert response.status_code == 200 + + assert ['access'] == [k for k,v in response.data.items() if k =="access" ] + + + assert ['refresh'] == [k for k,v in response.data.items() if k =="refresh" ] + + time.sleep(5) + + todo_path = reverse("user_todo") + + data = { + "title": "Test Title", + "description": "Test description" + } + + client.credentials(HTTP_AUTHORIZATION=f"Bearer {response.get('access')}") + + res = client.post(todo_path,data,format='json') + + + assert res.status_code == 401 + + assert res.json().get("detail") == "Given token not valid for any token type" + assert res.json().get("messages") == [{'message': 'Token is invalid or expired', 'token_class': 'AccessToken', 'token_type': 'access'}] + + refresh_path = reverse("token_refresh") + + + response_refresh = client.post(refresh_path,{"refresh":response.json().get("refresh")},format='json') + + assert response_refresh.status_code == 200 + + + data = { + "title": "Test Title", + "description": "Test description" + } + + client.credentials(HTTP_AUTHORIZATION=f"Bearer {response_refresh.json().get('access')}") + + response_after_Refresh = client.post(todo_path,data,format='json') + + assert response_after_Refresh.status_code == 201 + + client.credentials(HTTP_AUTHORIZATION=f"Bearer {response_refresh.json().get('refresh')}") + + another_Request = client.post(todo_path,data,format='json') + + assert another_Request.status_code == 401 + + assert another_Request.json().get("detail") == "Given token not valid for any token type" + assert another_Request.json().get("code") == "token_not_valid" + assert another_Request.json().get("messages") == [{'token_class': 'AccessToken', 'token_type': 'access', 'message': 'Token has wrong type'}] + + + + +@pytest.mark.django_db +def missingfields_test(client): + + path = reverse("login") + + response = client.post(path,format='json') + + assert response.status_code == 400 + +@pytest.mark.django_db +def token_refresh_test(client): + user = User.objects.create_user( + username="test_user", + password="test_password") + + path_login = reverse("login") + path_token_refresh = reverse("token_refresh") + + response = client.post(path_login,{"username":"test_user","password":"test_password"},format='json') + + response_login = response.json() + + response_refresh = client.post(path_token_refresh,{"refresh":response_login.get("refresh")},format='json') + + + assert response.status_code == 200 + + assert response_refresh.status_code == 200 + + + + +@pytest.mark.django_db +def post_todo_test(user_setUp): + + client = APIClient() + + path = reverse("user_todo") + + data = { + "title": "Test Title", + "description": "Test description" + } + + client.credentials(HTTP_AUTHORIZATION=f"Bearer {user_setUp.get('access')}") + + res = client.post(path,data,format='json') + + + assert res.status_code == 201 + + assert res.json().get("title") == data["title"] + assert res.json().get("description") == data["description"] + + + +@pytest.mark.django_db +def get_all_todos_test(user_setUp): + client = APIClient() + + path = reverse("user_todo") + + client.credentials(HTTP_AUTHORIZATION=f"Bearer {user_setUp.get('access')}") + + res = client.get(path,format='json') + + assert res.status_code == 200 + + +@pytest.mark.django_db +def todo_operation_test(user_setUp): + client = APIClient() + + path = reverse("user_todo_operation",args="1") + + user_todo = reverse("user_todo") + + data = { + "title": "Test Title", + "description": "Test description" + } + + client.credentials(HTTP_AUTHORIZATION=f"Bearer {user_setUp.get('access')}") + + res = client.post(user_todo,data,format='json') + + + client.credentials(HTTP_AUTHORIZATION=f"Bearer {user_setUp.get('access')}") + + res = client.get(path,format='json') + + assert res.status_code == 200 + assert res.json().get("id") == 1 + + +@pytest.mark.django_db +def test_todo_operation_test(user_setUp): + client = APIClient() + + path = reverse("user_todo_operation",args="1") + + user_todo = reverse("user_todo") + + data_1 = { + "title": "Test Title", + "description": "Test description" + } + + data_2 = { + "title": "Test Title2", + "description": "Test description2" + } + + client.credentials(HTTP_AUTHORIZATION=f"Bearer {user_setUp.get('access')}") + + res = client.post(user_todo,data_1,format='json') + + + client.credentials(HTTP_AUTHORIZATION=f"Bearer {user_setUp.get('access')}") + + res = client.get(path,format='json') + assert res.json().get("title") == data_1["title"] + + res_2 = client.put(path,data_2,format='json') + + + assert res_2.json().get("title") == data_2["title"] + + assert res.status_code == 200 + +@pytest.mark.django_db +def todo_operation_test(user_setUp): + client = APIClient() + + path = reverse("user_todo_operation",args="1") + + client.credentials(HTTP_AUTHORIZATION=f"Bearer {user_setUp.get('access')}") + + res = client.delete(path,format='json') + + assert res.status_code == 404 + + + + + + + + + + + + + + + + + diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/conftest.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/conftest.py new file mode 100644 index 0000000..55de53a --- /dev/null +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/conftest.py @@ -0,0 +1,101 @@ +import pytest +from api.serializer import UserSerializer +from django.contrib.auth import get_user_model +from api.models import Todo +from django.db.utils import IntegrityError +from django.urls import reverse, resolve + +User = get_user_model() +#wherner we need to run some code before test we use pytets fixture + +# You can test your Django application without using a Library but pytest offers some features that are not present in Django’s standard test mechanism: : +# Detailed info on failing assert statements (no need to remember self.assert* names); +# Auto-discovery of test modules and functions; +# Modular fixtures for managing small or parametrized long-lived test resources; +# Can run unit test (including trial) and nose test suites out of the box; +#to run test with multiple markeers use dec + +#wherner we need to run some code before test we use pytets fixture + +# A number of third-party testing frameworks attempt to address some of the issues with unittest, and pytest has proven to be one of the most popular. pytest is a feature-rich, plugin-based ecosystem for testing your Python code. + +@pytest.fixture +def created_user(): + + user = User.objects.create(username="testuser", email="test@gmail.com") + return user + + + +@pytest.fixture +@pytest.mark.django_db +def create_todo(created_user): + todo = Todo.objects.create( + user=created_user, + title="Test title", + description="Test description" + ) + return todo + + + +@pytest.fixture +def user_serlize(): + user_data = { + "first_name":"TestName", + "last_name":"TestSurname", + "username":"testuser", + "email":"test@gmail.com", + "password":"test12345" + } + + + user_serializer = UserSerializer(instance=user_data) + return user_serializer + +@pytest.fixture +def data(): + user_data = { + "first_name":"TestName", + "last_name":"TestSurname", + "username":"testuser", + "email":"test@gmail.com", + "password":"test12345" + } + return user_data + + +@pytest.fixture +def user_setUp(client): + + user = User.objects.create_user( + username="test_user", + password="test_password", + ) + path_login = reverse("login") + + response = client.post(path_login,{"username":"test_user","password":"test_password"},format='json') + + return response.json() + + + +@pytest.fixture +def setup(): + data = { + "user":{ + "first_name": "test_user", + "username":"testname", + "password":"test12345", + "email":"test@gmail.com", + "last_name":"testlastname" + }, + "user_2":{ + "first": "test_user", + "username":"testname", + "password":"test12345", + "email":"test@gmailcom", + "last_name":"testlastname"} + } + return data + diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/function_pytest.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/function_pytest.py new file mode 100644 index 0000000..89bfc1d --- /dev/null +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/function_pytest.py @@ -0,0 +1,19 @@ +import pytest +from api.utils import jwt_decode_handler +from django.conf import settings +from jwt.exceptions import ExpiredSignatureError + + + +def jwt_test(): + + token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTkwNTczMzIzLCJqdGkiOiI2YjVkZDBhOGU0ZDE0YzMzODQwM2ZiZWFiZjE3ZmE0MSIsInVzZXJfaWQiOjEwfQ.WZFnpB805o045MJnzqhsMit6p30mu-2TVgA6oitYWI0" + result = {'token_type': 'access', 'exp': 1590573323, 'jti': '6b5dd0a8e4d14c338403fbeabf17fa41', 'user_id': 10} + + with pytest.raises(ExpiredSignatureError) as expired: + + + assert jwt_decode_handler(token)== result + + assert expired.type == ExpiredSignatureError + \ No newline at end of file diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/model_pytest.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/model_pytest.py new file mode 100644 index 0000000..5e5d521 --- /dev/null +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/model_pytest.py @@ -0,0 +1,50 @@ +import pytest +from django.db import models +from django.db.utils import IntegrityError +from django.contrib.auth import get_user_model +from api.models import Todo +from django.db.utils import IntegrityError + +User = get_user_model() + +''' + +You can use pytest marks to tell pytest-django your test needs database access: +import pytest + +It is also possible to mark all tests in a class or module at once. This demonstrates all the ways of marking, even +though they overlap. Just one of these marks would have been sufficient. See t +''' + + + + + +@pytest.mark.django_db +def my_user_test(created_user): + + assert created_user.username == "testuser" + + assert created_user.email == "test@gmail.com" + + + +@pytest.mark.django_db +def todo_model_test(create_todo): + + assert create_todo.user.username == "testuser" + assert create_todo.title == "Test title" + assert create_todo.description == "Test description" + + + + + +@pytest.mark.django_db +def new_test(created_user): + with pytest.raises(IntegrityError) as error: + user = User.objects.create(username="testuser", email="test@gmail.com") + + assert user.username == "testuser" + + assert error.type == IntegrityError \ No newline at end of file diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/serializers_pytest.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/serializers_pytest.py new file mode 100644 index 0000000..aacfbd1 --- /dev/null +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/serializers_pytest.py @@ -0,0 +1,150 @@ +import pytest +from api.serializer import UserSerializer,UserSerializerDetails,TodoSerializer +from api.models import Todo +from django.contrib.auth import get_user_model +from django.db.utils import IntegrityError + +User = get_user_model() + + + + + + + + +def check_test(user_serlize): + + + assert user_serlize.data['first_name'] == "TestName" + assert user_serlize.data['last_name'] == "TestSurname" + assert user_serlize.data['username'] == "testuser" + assert user_serlize.data['email'] == "test@gmail.com" + assert user_serlize.data['password'] == "test12345" + + + +def validate_password_test(user_serlize): + + + assert user_serlize.validate_password(user_serlize.data['password']) == user_serlize.data['password'] + +@pytest.mark.django_db +def is_valid_test(data): + + + user_serializer = UserSerializer(data=data) + + assert user_serializer.is_valid() == True + + assert user_serializer.create(user_serializer.validated_data) ==User.objects.filter(id=1).first() + + with pytest.raises(Exception) as error: + + user_serializer.save() + + assert user.username == "testuser" + + assert error.type == IntegrityError + + +@pytest.fixture +def update_func(): + temp = [{ + 'first_name': "initial_test", + "last_name": "intial_surname", + "email": "intialtest@gmail.com", + "username": "intialtestuser", + "password": "intial12345" + }, + { + 'first_name': "new_test", + "last_name": "test_surname", + "email": "test@gmail.com", + "username": "newtestuser", + }] + + + return temp + + +@pytest.mark.django_db +def update_test(update_func): + + user_ = User.objects.create(**update_func[0]) + + update_serializer = UserSerializer(instance=user_, data=update_func[1], partial=True) + + assert update_serializer.is_valid() == True + + assert update_serializer.save() == User.objects.filter(id=1).first() + new_user_db = User.objects.filter(id=1).first() + + + assert new_user_db.username == "newtestuser" + assert new_user_db.last_name == "test_surname" + assert new_user_db.first_name =="new_test" + assert new_user_db.email == "test@gmail.com" + + + + + + +@pytest.fixture +def saved_user(): + user_data = { + "first_name":"TestName", + "last_name":"TestSurname", + "username":"testuser", + "email":"test@gmail.com", + "password":"test12345" + } + + + + user = User.objects.create(**user_data) + + return user + + + +@pytest.fixture +@pytest.mark.django_db +def todo_fucntion(saved_user): + todo_data = { + "title": "Test Title", + "description": "Test description" + } + + todo_data["user"] = saved_user + + todo = todo_seriralizer = TodoSerializer(instance=todo_data) + + return todo + + +@pytest.mark.django_db +def todo_serializer_fields_test(todo_fucntion): + + + assert todo_fucntion.data['title'] == "Test Title" + + assert todo_fucntion.data['description'] == "Test description" + + assert todo_fucntion.data['user'] == User.objects.get(id=1).id + + +@pytest.mark.django_db +def is_valid_test(todo_fucntion): + + todo_serializer = TodoSerializer(data={"title":"Test Title", "description": "Test description" }) + + assert todo_serializer.is_valid() == True + + assert todo_serializer.save() == Todo.objects.get(id=1) + + + + + diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/urls_pytest.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/urls_pytest.py new file mode 100644 index 0000000..e893bc9 --- /dev/null +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/api/pytest/urls_pytest.py @@ -0,0 +1,74 @@ + +import pytest +from django.urls import reverse, resolve + +from django.contrib.auth import get_user_model +from api.models import Todo + +User = get_user_model() + +''' +client fixture is included with django, client instance passed in whenever you add this as argument to your test funtions. BTW you can create your own fixture as well below an example: + +@pytest.fixture +def fixture_test(): + return "Hello World!" + +So the fucntion above, will allow us fixture_test add as an argument to any test function in our testsute So you can put that globally to acces accros project. + +fixetures are powerfull +''' + + +@pytest.mark.django_db +def api_users_test(client): + + path = reverse("user_detail",args="1") + response = client.get(path) + assert response.status_code == 404 + + assert resolve(path).func.view_class, UserDetail + + + +@pytest.mark.django_db +def test_api_user_list_test(client): + path = reverse("user_create") + + response = client.post(path) + + assert resolve(path).func.view_class, CreateUser + + assert response.status_code == 400 + +# @pytest.mark.django_db +def api_user_todo_operation_test(client): + path = reverse("user_todo_operation",args="1") + + response = client.post(path) + + assert response.status_code == 401 + assert resolve(path).func.view_class, TodoOperations + + +# @pytest.mark.django_db +def api_login_path_test(client): + path = reverse("login") + + response = client.post(path) + + assert response.status_code == 400 + assert resolve(path).func.view_class, Login + + print("the acutal path =>", path) + + +# @pytest.mark.django_db +def api_toke_refresh_path_test(client): + path = reverse("token_refresh") + + response = client.post(path) + + assert resolve(path).func.view_class, RefreshToken + + assert response.status_code == 400 \ No newline at end of file diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/__init__.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/test_api_views.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/test_api_views.py new file mode 100644 index 0000000..9153138 --- /dev/null +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/test_api_views.py @@ -0,0 +1,295 @@ +from api.views import CreateUser,UserList,UserDetail, Todos,TodoOperations,Login,RefreshToken +from django.contrib.auth import get_user_model +from api.serializer import UserSerializer +from django.test import TestCase, Client +from rest_framework.test import APIRequestFactory +from rest_framework.test import APIClient +from api.models import Todo +from rest_framework.test import APITestCase +from django.urls import reverse +User = get_user_model() + + + +class TestUserViews(APITestCase): + + def setUp(self): + self.client = APIClient() + + self.user = { + "first_name": "test_user", + "username":"testname", + "password":"test12345", + "email":"test@gmail.com", + "last_name":"testlastname" + } + self.user_2 = { + "first": "test_user", + "username":"testname", + "password":"test12345", + "email":"test@gmailcom", + "last_name":"testlastname" + } + + + + def test_create_user(self): + path = reverse("user_create") + + response = self.client.post(path,self.user,format='json') + + self.assertEqual(response.status_code, 201) + + response_2 = self.client.post(path,self.user,format='json') + + self.assertEqual(response_2.status_code, 400) + + user = User.objects.filter(id=1).first() + + self.assertEqual(user.first_name, "test_user") + self.assertEqual(user.username, "testname") + self.assertEqual(user.email, "test@gmail.com") + + + # print(response_2.json()) + + def test_user_list(self): + + path = reverse("user_list") + + response = self.client.get(path) + + self.assertEqual(response.status_code, 200) + + + + def test_user_detail_get(self): + user = User.objects.create( + first_name="test_user", + username="testname", + password="test12345", + email="test@gmail.com", + last_name="testlastname" + ) + + path = reverse("user_detail",args="1") + + + response = self.client.get(path,format='json') + + self.assertEqual(response.status_code, 200) + + self.assertEqual(user.first_name, response.json().get("first_name")) + self.assertEqual(user.username, response.json().get("username")) + self.assertEqual(user.email, response.json().get("email")) + self.assertEqual(user.last_name, response.json().get("last_name")) + + + + def test_user_detail_put(self): + path = reverse("user_detail",args="1") + + new_user = User.objects.create( + first_name="test_user", + username="testname", + password="test12345", + email="test@gmail.com", + last_name="testlastname" + ) + data = {"first_name": "TuralYek"} + + + response = self.client.put(path,data,format='json') + + + edited_user = User.objects.filter(id=1).first() + + self.assertEqual(response.status_code, 200) + + self.assertEqual(edited_user.first_name, response.json().get("first_name")) + + + def test_user_detail_delete(self): + + new_user = User.objects.create( + first_name="test_user", + username="testname", + password="test12345", + email="test@gmail.com", + last_name="testlastname" + ) + + path = reverse("user_detail",args="1") + + response = self.client.delete(path,format='json') + self.assertEqual(response.status_code, 200) + + + self.assertIsNone(User.objects.filter(id=1).first()) + + + + def test_login(self): + self.user = User.objects.create_user( + username="test_user", + password="test_password", + ) + + path = reverse("login") + + response = self.client.post(path,{"username":"test_user","password":"test_password"},format='json') + + + self.assertEqual(response.status_code, 200) + self.assertIn('access', response.data) + self.assertIn('refresh', response.data) + + def test_missingfields(self): + + path = reverse("login") + + response = self.client.post(path,format='json') + + self.assertEqual(response.status_code, 400) + + + + def test_token_refresh(self): + self.user = User.objects.create_user( + username="test_user", + password="test_password") + + path_login = reverse("login") + path_token_refresh = reverse("token_refresh") + + response = self.client.post(path_login,{"username":"test_user","password":"test_password"},format='json') + + response_login =response.json() + + response_refresh = self.client.post(path_token_refresh,{"refresh":response_login.get("refresh")},format='json') + + + self.assertEqual(response.status_code, 200) + + self.assertEqual(response_refresh.status_code, 200) + + + +class TestTodoViews(APITestCase): + + + + def setUp(self): + self.client = APIClient() + + self.user = User.objects.create_user( + username="test_user", + password="test_password", + ) + path_login = reverse("login") + + self.response = self.client.post(path_login,{"username":"test_user","password":"test_password"},format='json') + + self.response_login =self.response.json() + + def test_post_todo(self): + path = reverse("user_todo") + + data = { + "title": "Test Title", + "description": "Test description" + } + + self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {self.response_login.get('access')}") + + res = self.client.post(path,data,format='json') + + + self.assertEqual(res.status_code, 201) + + self.assertEqual(res.json().get("title"), data["title"]) + self.assertEqual(res.json().get("description"), data["description"]) + + + + + def test_get_all_todos(self): + path = reverse("user_todo") + + self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {self.response_login.get('access')}") + + res = self.client.get(path,format='json') + self.assertEqual(res.status_code, 200) + + + + def test_todo_operation_get(self): + + path = reverse("user_todo_operation",args="1") + + user_todo = reverse("user_todo") + + data = { + "title": "Test Title", + "description": "Test description" + } + + self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {self.response_login.get('access')}") + + res = self.client.post(user_todo,data,format='json') + + + self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {self.response_login.get('access')}") + + res = self.client.get(path,format='json') + + self.assertEqual(res.status_code, 200) + self.assertEqual(res.json().get("id"), 1) + + + + def test_todo_operation_put(self): + + path = reverse("user_todo_operation",args="1") + + user_todo = reverse("user_todo") + + data_1 = { + "title": "Test Title", + "description": "Test description" + } + + data_2 = { + "title": "Test Title2", + "description": "Test description2" + } + + self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {self.response_login.get('access')}") + + res = self.client.post(user_todo,data_1,format='json') + + + self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {self.response_login.get('access')}") + + res = self.client.get(path,format='json') + self.assertEqual(res.json().get("title"), data_1["title"]) + + res_2 = self.client.put(path,data_2,format='json') + + + self.assertEqual(res_2.json().get("title"), data_2["title"]) + + self.assertEqual(res.status_code, 200) + + + def test_todo_operation_delete(self): + + path = reverse("user_todo_operation",args="1") + + self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {self.response_login.get('access')}") + + res = self.client.delete(path,format='json') + + self.assertEqual(res.status_code, 404) + + diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/test_function.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/test_function.py new file mode 100644 index 0000000..51425e5 --- /dev/null +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/test_function.py @@ -0,0 +1,22 @@ +from django.test import SimpleTestCase +from api.utils import jwt_decode_handler +from django.conf import settings +from jwt.exceptions import ExpiredSignatureError + + + +class TestFunc(SimpleTestCase): + + + def test_jwt(self): + + token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTkwNTczMzIzLCJqdGkiOiI2YjVkZDBhOGU0ZDE0YzMzODQwM2ZiZWFiZjE3ZmE0MSIsInVzZXJfaWQiOjEwfQ.WZFnpB805o045MJnzqhsMit6p30mu-2TVgA6oitYWI0" + result = {'token_type': 'access', 'exp': 1590573323, 'jti': '6b5dd0a8e4d14c338403fbeabf17fa41', 'user_id': 10} + + with self.assertRaises(ExpiredSignatureError) as expired: + + + self.assertEqual(jwt_decode_handler(token),result) + self.assertEqual(ExpiredSignatureError, type(expired.exception)) + + \ No newline at end of file diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/test_models.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/test_models.py new file mode 100644 index 0000000..e032274 --- /dev/null +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/test_models.py @@ -0,0 +1,60 @@ + +# What is test actually ? +# Test is piece of code that makes sure that code you wrote works perfectly under speicif conditions + +# main reason companies requires test: more quality meaning application without bugs, make sure peiace code working correctly + + +#There types of Tests exists: + +# 1) Unit Test +# 2) Integration Test +# 3) Functional Test + +# 1) Testing one piece independently of another code, we need to assert function reterun value + +# 2) Tetsing multiple part of your code that integrated with each other + +# 3) Functional test is actullay testing applications from end user point view, basicly it is done by selinum,what user will type or fill gthe form + + +from django.test import TestCase +from django.contrib.auth import get_user_model +from api.models import Todo +from django.db.utils import IntegrityError + +User = get_user_model() + +class TestModels(TestCase): + + def setUp(self): + + self.user = User.objects.create(username="testuser", email="test@gmail.com") + + + def test_user_model(self): + + self.assertEqual(self.user.username, "testuser") + self.assertEqual(self.user.email,"test@gmail.com") + + + def test_todo_model(self): + self.todo = Todo.objects.create( + user=self.user, + title="Test title", + description="Test description" + ) + + + self.assertEqual(self.todo.user.username, "testuser") + self.assertEqual(self.todo.title,"Test title") + self.assertEqual(self.todo.description,"Test description") + + + def test_new_insert(self): + + with self.assertRaises(Exception) as raised: # top level exception as we want to figure out its exact type + new_user = User.objects.create(username="testuser", email="test@gmail.com") + self.assertEqual(IntegrityError, type(raised.exception)) + + diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/test_paths.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/test_paths.py new file mode 100644 index 0000000..1803fcc --- /dev/null +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/test_paths.py @@ -0,0 +1,109 @@ +from django.test import SimpleTestCase,TestCase +from django.urls import reverse, resolve,include,path +from api.views import UserDetail,UserList,CreateUser,Todos,TodoOperations,Login,RefreshToken +from rest_framework.test import APITestCase, URLPatternsTestCase,APIRequestFactory +from rest_framework import status + + + + +#SimpleTestCase is just basic testing class that in case if you dont need to interact with DB + +# APITestCase, +# URLPatternsTestCase +# TestCase + +#NOTE: be carefull django testcase works it looks basily what folder and files start with test work then class and functions. So in every class or function we should begin with Test keyword. + +#AssertionError: Database queries to 'default' are not allowed in SimpleTestCase subclasses. Either subclass TestCase or TransactionTestCase to ensure proper test isolation or add 'default' to api.tests.test_paths.TestApiEndPoints.databases to silence this failure. + +class TestApiEndPoints(TestCase): + + + def test_api_users_path(self): + + path = reverse("user_detail",args="1") + + # print("the acutal path =>", path) + + self.assertEquals(resolve(path).func.view_class, UserDetail) + response = self.client.get(reverse("user_detail",args="1"),format='json') + + # print(response.data) + # print(response.status_code) + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) #checking if it is 404 + + + def test_api_user_list_path(self): + path = reverse("user_list") + + # print("the acutal path =>", path) + + self.assertEquals(resolve(path).func.view_class, UserList) + + response = self.client.get(reverse("user_detail",args="1"),format='json') + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_api_user_create_path(self): + path = reverse("user_create") + + # print("the acutal path =>", path) + + self.assertEquals(resolve(path).func.view_class, CreateUser) + + response = self.client.post(reverse("user_create"),format='json') + # print(response.data) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_api_user_todo_path(self): + path = reverse("user_todo") + + # print("the acutal path =>", path) + + self.assertEquals(resolve(path).func.view_class, Todos) + + response = self.client.post(reverse("user_todo"),format='json') + # print(response.data) + + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) + + def test_api_user_todo_operation_path(self): + path = reverse("user_todo_operation",args="1") + + # print("the acutal path =>", path) + + self.assertEquals(resolve(path).func.view_class, TodoOperations) + + response = self.client.post(path,format='json') + # print(response.data) + + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) + + def test_api_login_path(self): + path = reverse("login") + + # print("the acutal path =>", path) + + self.assertEquals(resolve(path).func.view_class, Login) + + response = self.client.post(reverse("login"),format='json') + # print(response.data) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_api_toke_refresh_path(self): + path = reverse("token_refresh") + + # print("the acutal path =>", path) + + self.assertEquals(resolve(path).func.view_class, RefreshToken) + + response = self.client.post(path,format='json') + # print(response.data) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/test_serializers.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/test_serializers.py new file mode 100644 index 0000000..17472fc --- /dev/null +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/api/tests/test_serializers.py @@ -0,0 +1,144 @@ +from django.test import TestCase +from api.serializer import UserSerializer,UserSerializerDetails,TodoSerializer +from api.models import Todo +from django.contrib.auth import get_user_model + +User = get_user_model() + +class TestUserSerializers(TestCase): + + + def setUp(self): + + self.user_data = { + "first_name":"TestName", + "last_name":"TestSurname", + "username":"testuser", + "email":"test@gmail.com", + "password":"test12345" + } + + + self.user_serializer = UserSerializer(instance=self.user_data) + + def test_user_serializer_fields(self): + data = self.user_serializer.data + + + self.assertEqual(data['first_name'], self.user_data["first_name"]) + self.assertEqual(data['last_name'], self.user_data["last_name"]) + self.assertEqual(data['username'], self.user_data["username"]) + self.assertEqual(data['password'], self.user_data["password"]) + self.assertEqual(data['first_name'], self.user_data["first_name"]) + + + + def test_validate_password(self): + + + data = self.user_serializer.data + + self.assertTrue(self.user_serializer.validate_password(data["password"]),self.user_data["password"]) + + def test_is_valid(self): + + user_serializer = UserSerializer(data=self.user_data) + + self.assertTrue(user_serializer.is_valid()) + + self.assertTrue(self.user_serializer.create(user_serializer.validated_data)) + + + with self.assertRaises(Exception): + self.assertTrue(user_serializer.save()) + + + + def test_update(self): + initial_data = { + 'first_name': "initial_test", + "last_name": "intial_surname", + "email": "intialtest@gmail.com", + "username": "intialtestuser", + "password": "intial12345" + } + + new_data = { + 'first_name': "new_test", + "last_name": "test_surname", + "email": "test@gmail.com", + "username": "newtestuser", + } + user_ = User.objects.create(**initial_data) + + update_serializer = UserSerializer(instance=user_, data=new_data, partial=True) + + self.assertTrue(update_serializer.is_valid()) + + self.assertTrue(update_serializer.save()) + new_user_db = User.objects.filter(id=1).first() + + + self.assertEqual(new_user_db.username, "newtestuser") + self.assertEqual(new_user_db.last_name,"test_surname") + self.assertEqual(new_user_db.first_name,"new_test") + self.assertEqual(new_user_db.email,"test@gmail.com") + + + + +class TestTodoSerializers(TestCase): + + + def setUp(self): + + self.user_data = { + "first_name":"TestName", + "last_name":"TestSurname", + "username":"testuser", + "email":"test@gmail.com", + "password":"test12345" + } + + self.todo_data = { + "title": "Test Title", + "description": "Test description" + } + + self.user = User.objects.create(**self.user_data) + + + self.todo_data["user"] = self.user + + self.todo_seriralizer = TodoSerializer(instance=self.todo_data) + + def test_todo_serializer_fields(self): + + data = self.todo_seriralizer.data + + self.assertEqual(data['title'],self.todo_data["title"]) + + self.assertEqual(data['description'],self.todo_data["description"]) + + self.assertEqual(data['user'], self.user.id) + + + def test_is_valid(self): + + + self.todo_data["user"] = self.user.id + + todo_serializer = TodoSerializer(data=self.todo_data) + + self.assertTrue(todo_serializer.is_valid()) + + self.assertTrue(todo_serializer.save()) + + + + + + + + + \ No newline at end of file diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/urls.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/urls.py index f3bdbce..8c3ffaa 100644 --- a/Project1_Simple_REST_API/RestDjango/django_restframework/api/urls.py +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/api/urls.py @@ -1,18 +1,19 @@ from django.urls import path -from .views import UserDetail,UserList,CreateUser, Todos, TodoOperations,Login +from .views import UserDetail,UserList,CreateUser, Todos, TodoOperations,Login,RefreshToken from rest_framework_simplejwt.views import token_refresh urlpatterns = [ - path('users//',UserDetail.as_view()), - path('users/',UserList.as_view()), - path('user/',CreateUser.as_view()), + path('users//',UserDetail.as_view(),name="user_detail"), + path('users/',UserList.as_view(),name="user_list"), + path('user/',CreateUser.as_view(),name="user_create"), + - path("user/todo/",Todos.as_view()),#POST ,#GET all todos - path("user/todo//",TodoOperations.as_view()), #PUT,GET,DELETE specifc + path("user/todos/",Todos.as_view(),name="user_todo"),#POST ,#GET all todos + path("user/todos//",TodoOperations.as_view(),name="user_todo_operation"), #PUT,GET,DELETE specifc - path("login/", Login.as_view()), - path("token-refresh/", token_refresh) + path("login/", Login.as_view(),name="login"), + path("token-refresh/", RefreshToken.as_view(),name="token_refresh") -] +] \ No newline at end of file diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/api/views.py b/Project1_Simple_REST_API/RestDjango/django_restframework/api/views.py index 7874bfc..d79d97c 100644 --- a/Project1_Simple_REST_API/RestDjango/django_restframework/api/views.py +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/api/views.py @@ -13,7 +13,7 @@ from .models import Todo from django.contrib.auth import get_user_model from .utils import jwt_decode_handler -from rest_framework_simplejwt.views import TokenObtainPairView +from rest_framework_simplejwt.views import TokenObtainPairView,TokenRefreshView logging.config.dictConfig(LOGGING) User = get_user_model() @@ -63,7 +63,7 @@ def get(self, request, pk): user_data = get_object_or_404(User, pk=pk) - print(user_data) + # print(user_data) data = UserSerializerDetails(user_data).data return Response(data) @@ -192,7 +192,7 @@ def get(self,request,pk): token = request.headers.get("Authorization").split(" ")[1] details = jwt_decode_handler(token) - + # print(details) if not (User.objects.filter(id=details.get("user_id")).last() and Todo.objects.filter(id=pk).last()): return Response({"message": "No such a user or todo"},status=status.HTTP_404_NOT_FOUND) @@ -210,12 +210,17 @@ def get(self,request,pk): class Login(TokenObtainPairView): def post(self, request, *args, **kwargs): + + data = super().post(request, *args, **kwargs) data = data.data + # print(data) acces_token = jwt_decode_handler(data.get("access")) - + ref = jwt_decode_handler(data.get("refresh")) + # print(ref) + # print(acces_token) if not User.objects.filter(id=acces_token.get("user_id")).last(): return Response({"error": True,"message": "No such a user"},status=status.HTTP_404_NOT_FOUND) todos = Todo.objects.filter(user=acces_token.get("user_id")).all() @@ -230,4 +235,17 @@ def post(self, request, *args, **kwargs): data["user_details"] = user_details.data - return Response(data) \ No newline at end of file + return Response(data) + +class RefreshToken(TokenRefreshView): + def post(self, request, *args, **kwargs): + data = super().post(request, *args, **kwargs) + + new_token = data.data + # print(new_token) + acces_token = jwt_decode_handler(new_token.get("access")) + ref = jwt_decode_handler(new_token.get("refresh")) + # print(ref) + # print(acces_token) + + return data \ No newline at end of file diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/pytest.ini b/Project1_Simple_REST_API/RestDjango/django_restframework/pytest.ini new file mode 100644 index 0000000..de2f4a2 --- /dev/null +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/pytest.ini @@ -0,0 +1,6 @@ +[pytest] +DJANGO_SETTINGS_MODULE = testApi.settings +python_files = *pytest.py +python_classes = *_test +python_functions = *_test +addopts = -p no:warnings diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/restApi/settings.py b/Project1_Simple_REST_API/RestDjango/django_restframework/restApi/settings.py index 1190ca9..8fd2377 100644 --- a/Project1_Simple_REST_API/RestDjango/django_restframework/restApi/settings.py +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/restApi/settings.py @@ -82,11 +82,12 @@ 'USER_ID_FIELD': 'id', #The database field from the user model that will be included in generated tokens to identify users. 'USER_ID_CLAIM': 'user_id', #value of 'user_id' would mean generated tokens include a “user_id” claim that contains the user’s identifier. + 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), #token_type 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), 'TOKEN_TYPE_CLAIM': 'token_type', #The claim name that is used to store a token’s type 'JTI_CLAIM': 'jti', #The claim name that is used to store a token’s unique identifier. - 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5), #which specifies how long access tokens are valid + 'ACCESS_TOKEN_LIFETIME': timedelta(seconds=3), #which specifies how long access tokens are valid 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), # how long refresh tokens are valid. } @@ -99,6 +100,12 @@ 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_simplejwt.authentication.JWTAuthentication', ), + 'TEST_REQUEST_DEFAULT_FORMAT': 'json', + 'TEST_REQUEST_RENDERER_CLASSES': [ + 'rest_framework.renderers.MultiPartRenderer', + 'rest_framework.renderers.JSONRenderer', + 'rest_framework.renderers.TemplateHTMLRenderer' + ] } ''' diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/testApi/__init__.py b/Project1_Simple_REST_API/RestDjango/django_restframework/testApi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Project1_Simple_REST_API/RestDjango/django_restframework/testApi/settings.py b/Project1_Simple_REST_API/RestDjango/django_restframework/testApi/settings.py new file mode 100644 index 0000000..3428592 --- /dev/null +++ b/Project1_Simple_REST_API/RestDjango/django_restframework/testApi/settings.py @@ -0,0 +1,90 @@ +import os +import os +from django.conf import settings +from datetime import timedelta + +SECRET_KEY = os.getenv("SECRET_KEY") + + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": "mem_db" + } +} + +SIMPLE_JWT = { + 'ROTATE_REFRESH_TOKENS': True, + 'BLACKLIST_AFTER_ROTATION': True, + + 'ALGORITHM': 'HS256', + 'SIGNING_KEY': settings.SECRET_KEY, + 'VERIFYING_KEY': None, + 'AUDIENCE': None, + 'ISSUER': None, + + 'AUTH_HEADER_TYPES': ('Bearer',), + 'USER_ID_FIELD': 'id', + 'USER_ID_CLAIM': 'user_id', + + 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), + 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), + 'TOKEN_TYPE_CLAIM': 'token_type', + + 'JTI_CLAIM': 'jti', + 'ACCESS_TOKEN_LIFETIME': timedelta(seconds=3), + 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), +} + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + "api.apps.MyAppConfig", + "rest_framework", + + +] + + +#rest framework config +REST_FRAMEWORK = { + 'DEFAULT_PERMISSION_CLASSES': ( + 'rest_framework.permissions.IsAuthenticated', + ), + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework_simplejwt.authentication.JWTAuthentication', + ), + 'TEST_REQUEST_DEFAULT_FORMAT': 'json', + 'TEST_REQUEST_RENDERER_CLASSES': [ + 'rest_framework.renderers.MultiPartRenderer', + 'rest_framework.renderers.JSONRenderer', + 'rest_framework.renderers.TemplateHTMLRenderer' + ] +} + + +ROOT_URLCONF = 'restApi.urls' + + + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +