-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add Pearson engine client #209
Merged
Merged
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
"""Client module for Pearson Engine API integration. | ||
|
||
Classes: | ||
PearsonEngineApiClient: Base class to interact with Pearson Engine services. | ||
""" | ||
from django.conf import settings | ||
|
||
from eox_nelp.api_clients import AbstractAPIRestClient | ||
from eox_nelp.api_clients.authenticators import Oauth2Authenticator | ||
|
||
|
||
class PearsonEngineApiClient(AbstractAPIRestClient): | ||
""" | ||
Client to interact with Pearson Engine API for importing candidate demographics | ||
and exam authorization data. | ||
|
||
Attributes: | ||
client_id (str): The client ID for Pearson Engine API. | ||
client_secret (str): The client secret for Pearson Engine API. | ||
authentication_path (str): The path for authentication. | ||
""" | ||
authentication_class = Oauth2Authenticator | ||
|
||
def __init__(self): | ||
self.client_id = getattr(settings, "PEARSON_ENGINE_API_CLIENT_ID") | ||
self.client_secret = getattr(settings, "PEARSON_ENGINE_API_CLIENT_SECRET") | ||
self.authentication_path = "oauth2/token/" | ||
|
||
super().__init__() | ||
|
||
@property | ||
def base_url(self): | ||
"""Return the base URL for Pearson Engine API.""" | ||
return getattr(settings, "PEARSON_ENGINE_API_URL") | ||
|
||
def _get_user_data(self, user): | ||
""" | ||
Retrieve user data for the request payload. | ||
|
||
Args: | ||
user: The user object containing user data. | ||
|
||
Returns: | ||
dict: The user data formatted for the request. | ||
""" | ||
return { | ||
"username": user.username, | ||
"first_name": user.first_name, | ||
"last_name": user.last_name, | ||
"email": user.email, | ||
"country": user.profile.country.code, | ||
"city": user.profile.city, | ||
"phone": user.profile.phone_number, | ||
"address": user.profile.mailing_address, | ||
"arabic_first_name": user.extrainfo.arabic_first_name, | ||
"arabic_last_name": user.extrainfo.arabic_last_name, | ||
} | ||
|
||
def _get_platform_data(self): | ||
""" | ||
Retrieve platform data for the request payload. | ||
|
||
Returns: | ||
dict: The platform data formatted for the request. | ||
""" | ||
return { | ||
"name": settings.PLATFORM_NAME, | ||
"tenant": getattr(settings, "EDNX_TENANT_DOMAIN", None) | ||
} | ||
|
||
def _get_exam_data(self, exam_id): | ||
""" | ||
Retrieve exam data for the request payload. | ||
|
||
Args: | ||
exam_id: The external key for the exam. | ||
|
||
Returns: | ||
dict: The exam data formatted for the request. | ||
""" | ||
return { | ||
"external_key": exam_id, | ||
} | ||
|
||
def import_candidate_demographics(self, user, **kwargs): | ||
""" | ||
Import candidate demographics into Pearson Engine. | ||
|
||
Args: | ||
user: The user object containing user data. | ||
|
||
Returns: | ||
dict: The response from Pearson Engine API. | ||
""" | ||
path = "rti/api/v1/candidate-demographics/" | ||
|
||
candidate = { | ||
"user_data": self._get_user_data(user), | ||
"platform_data": self._get_platform_data(), | ||
**kwargs | ||
} | ||
|
||
return self.make_post(path, candidate) | ||
|
||
def import_exam_authorization(self, user, exam_id, **kwargs): | ||
""" | ||
Import exam authorization data into Pearson Engine. | ||
|
||
Args: | ||
user: The user object containing user data. | ||
exam_id: The external key for the exam. | ||
|
||
Returns: | ||
dict: The response from Pearson Engine API. | ||
""" | ||
path = "rti/api/v1/exam-authorization/" | ||
exam_data = { | ||
"user_data": {"username": user.username}, | ||
"exam_data": self._get_exam_data(exam_id), | ||
**kwargs | ||
} | ||
|
||
return self.make_post(path, exam_data) | ||
|
||
def real_time_import(self, user, exam_id, **kwargs): | ||
""" | ||
Perform a real-time import of exam authorization data. | ||
|
||
Args: | ||
user: The user object containing user data. | ||
exam_id: The external key for the exam. | ||
|
||
Returns: | ||
dict: The response from Pearson Engine API. | ||
""" | ||
path = "rti/api/v1/exam-authorization/" | ||
data = { | ||
"user_data": self._get_user_data(user), | ||
"exam_data": self._get_exam_data(exam_id), | ||
"platform_data": self._get_platform_data(), | ||
**kwargs | ||
} | ||
|
||
return self.make_post(path, data) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
""" | ||
Test suite for PearsonEngineApiClient. | ||
|
||
This module contains unit tests for the PearsonEngineApiClient class, which | ||
integrates with Pearson Engine services. The tests cover the main methods | ||
import_candidate_demographics, import_exam_authorization, and real_time_import | ||
to ensure they work as expected. | ||
|
||
Classes: | ||
TestPearsonEngineApiClient: Unit test class for PearsonEngineApiClient. | ||
""" | ||
import unittest | ||
from unittest.mock import patch | ||
|
||
import requests | ||
from django_countries.fields import Country | ||
|
||
from eox_nelp.api_clients.pearson_engine import PearsonEngineApiClient | ||
from eox_nelp.api_clients.tests.mixins import TestOauth2AuthenticatorMixin, TestRestApiClientMixin | ||
|
||
|
||
class TestPearsonEngineApiClient(TestRestApiClientMixin, TestOauth2AuthenticatorMixin, unittest.TestCase): | ||
""" | ||
Test suite for PearsonEngineApiClient. | ||
|
||
This class tests the methods of PearsonEngineApiClient, including | ||
import_candidate_demographics, import_exam_authorization, and real_time_import. | ||
""" | ||
|
||
def setUp(self): | ||
""" | ||
Set up the test environment. | ||
|
||
This method initializes the API client class for testing. | ||
""" | ||
self.api_class = PearsonEngineApiClient | ||
|
||
@patch.object(PearsonEngineApiClient, "make_post") | ||
@patch.object(PearsonEngineApiClient, "_authenticate") | ||
def test_import_candidate_demographics(self, auth_mock, post_mock): | ||
""" | ||
Test import_candidate_demographics API call. | ||
|
||
Expected behavior: | ||
- Response is the expected value. | ||
- make_post is called with the correct path and payload. | ||
""" | ||
auth_mock.return_value = requests.Session() | ||
expected_value = { | ||
"status": {"success": True}, | ||
} | ||
post_mock.return_value = expected_value | ||
|
||
user = self._create_test_user() | ||
api_client = self.api_class() | ||
|
||
response = api_client.import_candidate_demographics(user) | ||
|
||
self.assertDictEqual(response, expected_value) | ||
# pylint: disable=protected-access | ||
post_mock.assert_called_with("rti/api/v1/candidate-demographics/", { | ||
"user_data": api_client._get_user_data(user), | ||
"platform_data": api_client._get_platform_data(), | ||
}) | ||
|
||
@patch.object(PearsonEngineApiClient, "make_post") | ||
@patch.object(PearsonEngineApiClient, "_authenticate") | ||
def test_import_exam_authorization(self, auth_mock, post_mock): | ||
""" | ||
Test import_exam_authorization API call. | ||
|
||
Expected behavior: | ||
- Response is the expected value. | ||
- make_post is called with the correct path and payload. | ||
""" | ||
auth_mock.return_value = requests.Session() | ||
expected_value = { | ||
"status": {"success": True, "message": "successful", "code": 1} | ||
} | ||
post_mock.return_value = expected_value | ||
user = self._create_test_user() | ||
exam_id = "exam-123" | ||
api_client = self.api_class() | ||
|
||
response = api_client.import_exam_authorization(user, exam_id, transaction_type="Add") | ||
|
||
self.assertDictEqual(response, expected_value) | ||
post_mock.assert_called_with("rti/api/v1/exam-authorization/", { | ||
"user_data": {"username": user.username}, | ||
"exam_data": api_client._get_exam_data(exam_id), # pylint: disable=protected-access | ||
"transaction_type": "Add", | ||
}) | ||
|
||
@patch.object(PearsonEngineApiClient, "make_post") | ||
@patch.object(PearsonEngineApiClient, "_authenticate") | ||
def test_real_time_import(self, auth_mock, post_mock): | ||
""" | ||
Test real_time_import API call. | ||
|
||
Expected behavior: | ||
- Response is the expected value. | ||
- make_post is called with the correct path and payload. | ||
""" | ||
auth_mock.return_value = requests.Session() | ||
expected_value = { | ||
"status": {"success": True, "message": "successful", "code": 1}, | ||
} | ||
post_mock.return_value = expected_value | ||
user = self._create_test_user() | ||
exam_id = "exam-123" | ||
api_client = self.api_class() | ||
|
||
response = api_client.real_time_import(user, exam_id) | ||
|
||
self.assertDictEqual(response, expected_value) | ||
# pylint: disable=protected-access | ||
post_mock.assert_called_with("rti/api/v1/exam-authorization/", { | ||
"user_data": api_client._get_user_data(user), | ||
"exam_data": api_client._get_exam_data(exam_id), | ||
"platform_data": api_client._get_platform_data(), | ||
}) | ||
|
||
def _create_test_user(self): | ||
""" | ||
Create a mock user for testing. | ||
|
||
Returns: | ||
user: A mock user object with necessary attributes. | ||
""" | ||
# pylint: disable=missing-class-docstring | ||
class MockUser: | ||
username = "testuser" | ||
first_name = "Test" | ||
last_name = "User" | ||
email = "[email protected]" | ||
|
||
class Profile: | ||
country = Country("US") | ||
city = "New York" | ||
phone_number = "+1234567890" | ||
mailing_address = "123 Test St" | ||
|
||
class ExtraInfo: | ||
arabic_first_name = "اختبار" | ||
arabic_last_name = "مستخدم" | ||
|
||
profile = Profile() | ||
extrainfo = ExtraInfo() | ||
|
||
return MockUser() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like that the inner key has the same name of dict. But it is only an opinion. I leave it to your consideration