Open Arka-cell opened 3 years ago
@garyburgmann The following code contains the tests that I have made:
import ast
import json
import pytest
from api_app.models import Seeker, CV
from api_app.serializers import SeekerSerializer
from django.core.management import call_command
from fpdf import FPDF
from graphene.test import Client as graphene_client
from rest_framework.renderers import JSONRenderer
from rest_framework.reverse import reverse
from token_generator_phone import TokenGenerator, PHONE_NUMBER
from api_app.schema import schema
test_token = TokenGenerator().generate_id_token()
test_user = TokenGenerator().get_test_user()
@pytest.fixture
def test_get_seeker_infos_successful_200(client):
"""
:param client: Simulate HTTP methods requests on a URL and observe the response.
:return: Status code 200 with a JSON object representing user profile data
"""
"""
GIVEN a registered firebase user
"""
token = test_token
url = reverse("personal-infos")
client.defaults["HTTP_AUTHORIZATION"] = f"Bearer {token}"
"""
WHEN he sends a get with authentication credentials
"""
response = client.get(url)
"""
THEN drf_firebase_auth would register him in local database and his personal data
would be put into default and returned as a JSON object.
"""
test_client = Seeker.objects.get(username=test_user.uid)
serializer = SeekerSerializer(test_client)
mock_data = JSONRenderer().render(serializer.data)
assert (
response.status_code == 200
), f"Status code should be 200 instead of {response.status_code}"
"""
AND response content would assert serializer data in JSON format.
"""
assert mock_data == response.content
@pytest.mark.django_db
def test_get_seeker_infos_absent_credentials_401(client):
"""
:param client: Simulate HTTP methods requests on a URL and observe the response.
:return: Status code 401 with the message: {"detail": "Authentication credentials were not provided."}
"""
"""
GIVEN a registered or an un-registered user in Firebase
WHEN he sends a patch request without a token
"""
url = reverse("seeker-infos")
response = client.get(url)
"""
THEN the status code should return 401.
"""
assert (
response.status_code == 401
), f"Status code should be 401 instead of {response.status_code}"
@pytest.mark.django_db
def test_patch_seeker_infos_successful_200(client):
"""
:param client: Simulate HTTP methods requests on a URL and observe the response.
:return: Status code 200 with the user's newly updated profile data.
"""
"""
GIVEN a registered firebase user
"""
url = reverse("seeker-infos")
token = test_token
client.defaults["HTTP_AUTHORIZATION"] = f"Bearer {token}"
"""
WHEN he sends a patch with new data with authentication credentials
"""
response = client.patch(
url,
json={
"first_name": "test",
"last_name": "seeker",
"birthdate": "2021-03-28",
},
)
"""
THEN the client response will be successful
"""
assert (
response.status_code == 200
), f"Status code should be 200 instead of {response.status_code}"
"""
AND response data should be the same as the serializer data in a JSON format
"""
test_client = Seeker.objects.get(username=test_user.uid)
serializer = SeekerSerializer(test_client)
mock_data = JSONRenderer().render(serializer.data)
assert mock_data == response.content
@pytest.mark.django_db
def test_patch_seeker_infos_absent_credentials_401(client):
"""
:param client: Simulate HTTP methods requests on a URL and observe the response.
:return: Status code 401 with the message: {"detail": "Authentication credentials were not provided."}
"""
"""
GIVEN a un-registered user in Firebase
WHEN he sends a patch request
"""
url = reverse("seeker-infos")
response = client.patch(
url,
json={
"first_name": "test",
"last_name": "seeker",
"birthdate": "2021-03-28",
},
)
"""
THEN the status code should return 401.
"""
assert (
response.status_code == 401
), f"Status code should be 401 instead of {response.status_code}"
@pytest.mark.django_db
def test_seeker_infos_not_allowed(client):
"""
:param client: Simulate HTTP methods requests on a URL and observe the response.
:return json: Status code 405 with the message: {"detail":"HTTP method not allowed"}"
"""
"""
GIVEN a registered firebase user
"""
url = reverse("seeker-infos")
token = test_token
client.defaults["HTTP_AUTHORIZATION"] = f"Bearer {token}"
"""
WHEN he sends a POST method in seeker-infos
"""
response = client.post(
url,
json={
"email": "Jobseeker@email.com",
"username": "FirebaseUID",
"first_name": "Job",
"last_name": "Seeker",
"birthdate": "2021-11-30",
"phone_number": "0795524594",
"longitude": "0.111111",
"latitude": "-0.111111",
},
)
"""
THEN the data will not be registered in the local database
and status code is going to be 405.
"""
assert (
response.status_code == 405
), f"Status code should be 405 instead of {response.status_code}"
"""
AND when he sends a DELETE method
"""
response = client.delete(url)
"""
THEN the DELETE method will not be performed
and status code is going to be 405.
"""
assert (
response.status_code == 405
), f"Status code should be 405 instead of {response.status_code}"
@pytest.mark.django_db
def test_seeker_personal_info_unsupported_media_415(client):
"""
:param client: Simulate HTTP methods requests on a URL and observe the response.
:return json: Status code 415 with the message: {"detail":"Unsupported Media Type."
"""
"""
GIVEN a registered firebase user
"""
url = reverse("seeker-infos")
token = test_token
client.defaults["HTTP_AUTHORIZATION"] = f"Bearer {token}"
"""
WHEN he sends a patch with data in format other than JSON
"""
response = client.patch(
url,
data={
"first_name": "test",
"last_name": "seeker",
"birthdate": "2021-03-28",
},
)
"""
THEN the data will not be registered in the local database
and status code is going to be 415.
"""
assert (
response.status_code == 415
), f"Status code should be 415 instead of {response.status_code}"
@pytest.mark.django_db
class TestCVFile:
pytestmark = pytest.mark.django_db
pdf = FPDF()
pdf.add_page()
pdf.set_font("Arial", size=15)
pdf.cell(200, 10, txt="PDF Sample", ln=1, align="C")
pdf.output("sample.pdf")
def test_seeker_cv_file_put_get_200(self, client):
"""
:param client: Simulate HTTP methods requests on a URL to observe the response.
:return json: Status code 200 with a pdf file of content-type: application/pdf "
"""
"""
GIVEN a registered firebase user
"""
url = reverse("seeker-cv-file")
token = test_token
client.defaults["HTTP_AUTHORIZATION"] = f"Bearer {token}"
"""
WHEN he sends a put request with a file
"""
client.defaults["HTTP_CONTENT_DISPOSITION"] = "cv_file; filename=cv.pdf"
client.defaults["HTTP_CONTENT_TYPE"] = "application/pdf"
response = client.put(
url, data=open("sample.pdf", "rb").read(), content_type="application/pdf"
)
"""
THEN the response status code will be 200 and his CV would therefore be saved
as binary on database
"""
assert (
response.status_code == 200
), f"Status code should be 200 instead of {response.status_code}"
assert (
response.headers["Content-Type"] == "application/pdf"
), f"Content-Type should be 'application/pdf' instead of {response.headers['Content-Type']}"
"""
AND he requests CV file as binary based on his content-type
"""
client.defaults["HTTP_CONTENT_TYPE"] = "application/octet-stream"
response = client.get(url, content_type="application/octet-stream")
"""
THEN he receives the file with the content-type he requested for
"""
assert (
response.status_code == 200
), f"Status code should be 200 instead of {response.status_code}"
client.defaults["HTTP_CONTENT_TYPE"] = "application/pdf"
assert (
response.headers["Content-Type"] == "application/octet-stream"
), f"Content-Type should be 'octet-stream' instead of {response.headers['Content-Type']}"
"""
AND he requests CV file as a PDF
"""
response = client.get(url, content_type="application/pdf")
"""
THEN he receives the file with the content-type he requested for
"""
assert (
response.status_code == 200
), f"Status code should be 200 instead of {response.status_code}"
assert (
response.headers["Content-Type"] == "application/pdf"
), f"Content-Type should be 'application/pdf' instead of {response.headers['Content-Type']}"
def test_get_500(self, client):
"""
:param client: Simulate HTTP methods requests on a URL to observe the response.
:return json: Status code 500 with the following JSON: {"Message": "CV not available"}"
"""
"""
GIVEN a registered firebase user
"""
url = reverse("seeker-cv-file")
token = test_token
client.defaults["HTTP_AUTHORIZATION"] = f"Bearer {token}"
"""
WHEN he sends a put request with a file
"""
client.defaults["HTTP_CONTENT_DISPOSITION"] = "cv_file; filename=cv.pdf"
client.defaults["HTTP_CONTENT_TYPE"] = "application/pdf"
response = client.get(url, content_type="application/pdf")
content = ast.literal_eval(response.content.decode("UTF-8"))
"""
THEN the server would point out that the CV has not been uploaded in order to
be able to perform a GET request
"""
assert (
response.status_code == 200
), f"Status code should be 200 instead of {response.status_code}"
assert (
content["Message"] == "CV not available"
), f"Response content should be 'CV not available' instead of {content['Message']}"
def test_seeker_cv_file_put_415(self, client):
"""
:param client: Simulate HTTP methods requests on a URL to observe the response.
:return json: Status code 415 with the message saying that cv file media type is incorrect"
"""
"""
GIVEN a registered firebase user with a html file
"""
url = reverse("seeker-cv-file")
token = test_token
client.defaults["HTTP_AUTHORIZATION"] = f"Bearer {token}"
html_string = "<p>This is an html file</p>"
with open("file.pdf", "w") as file:
file.write(html_string)
"""
WHEN he sends a put request with an html file carrying a false extension
"""
client.defaults["HTTP_CONTENT_DISPOSITION"] = "cv_file; filename=cv.pdf"
client.defaults["HTTP_CONTENT_TYPE"] = "application/pdf"
response = client.put(
url, data=open("file.pdf", "rb").read(), content_type="application/pdf"
)
assert (
response.status_code == 415
), f"Status code should be 415 instead of {response.status_code}"
class TestCV:
pytestmark = pytest.mark.django_db
def test_seeker_cv_get_200(self, client):
"""
:param client: Simulate HTTP methods requests on a URL to observe the response.
:return json: Status code 200 with CV fields to be filled by admin or AI model"
"""
"""
GIVEN an authenticated seeker uploading a file
"""
file_upload_url = reverse("seeker-cv-file")
token = test_token
client.defaults["HTTP_AUTHORIZATION"] = f"Bearer {token}"
client.get(reverse("seeker-infos"))
client.defaults["HTTP_CONTENT_DISPOSITION"] = "cv_file; filename=cv.pdf"
client.defaults["HTTP_CONTENT_TYPE"] = "application/pdf"
client.put(
file_upload_url,
data=open("sample.pdf", "rb").read(),
content_type="application/pdf",
)
"""
WHEN an admin update CV fields according to field
"""
mock_data = {"category": "developer", "tags": ["pytest", "unit-testing"]}
seeker_cv = CV.objects.get(seeker=Seeker.objects.get(email=PHONE_NUMBER))
seeker_cv.category = mock_data["category"]
seeker_cv.tags = mock_data["tags"]
seeker_cv.save()
"""
AND the authenticated seeker want to retrieve the updated CV fields by the admin
"""
cv_url = reverse("seeker-cv")
client.defaults["HTTP_AUTHORIZATION"] = f"Bearer {token}"
response = client.get(cv_url)
"""
THEN he would get a status code, as well as data JSON data such as the one saved by the admin
"""
assert (
response.status_code == 200
), f"Status code should be 200 instead of {response.status_code}"
assert (
ast.literal_eval(response.content.decode("utf-8")) == mock_data
), f"Retrieved content should be the same content as this: {mock_data}"
class TestJobAppliance:
pytestmark = pytest.mark.django_db
def test_apply(self, client):
url = reverse("job-apply", args=[1])
token = test_token
client.defaults["HTTP_AUTHORIZATION"] = f"Bearer {token}"
response = client.put(url)
response_data = json.loads(response.content.decode("UTF-8"))
assert response.status_code == 200
assert response_data == [
{
"id": 1,
"company": "some_company",
"description": "",
"title": "Vue Developer",
"category": "Developement",
"active": True,
"created_at": "2021-05-20T16:24:34.824385+02:00",
}
], f"{response_data} is not the expected data"
"""
WHEN seeker asks for jobs he applied for
"""
"""
WHEN the seeker tries to apply for the same job, the message "You already
applied for this job" would be returned
"""
url = reverse("job-apply", args=[1])
response = client.put(url)
assert ast.literal_eval(response.content.decode("UTF-8")) == {
"Message": "You already applied for this job"
}, f"{response.content} is not the expected message."
url = reverse("job-applications")
response = client.get(url)
response_data = json.loads(response.content.decode("UTF-8"))
assert (
response.status_code == 200
), f"Status code should be 200 instead of {response.status_code}"
assert response_data == [
{
"id": 1,
"company": "some_company",
"description": "",
"title": "Vue Developer",
"category": "Developement",
"active": True,
"created_at": "2021-05-20T16:24:34.824385+02:00",
}
], f"{response_data} is not the expected data"
thanks @Arka-cell , I will review this when I have time
@garyburgmann got time ?
@garyburgmann did you got time?
I did make a minor change, whereas, the phone number, if the user is registered with it in firebase, would be mapped to the email field in
auth_user
. I did run unit tests within my app with the phone number and it is expected to work absolutely fine in production mode (I did not run it in my CI/CD pipeline). My app's settings were by default:The only thing is that the current email field should be identifier instead of email in
auth_user