def test_expired_access_token(self): expired_token_response_body = { "expires_in": 0, "access_token": self.access_token } responses.add(responses.POST, self.url_base + self.oauth_api_path, json=expired_token_response_body, status=200) responses.add(responses.POST, self.url_base + self.oauth_api_path, json=self.expected_token_response_body, status=200) expected_course_response_body = self.content_payload expected_course_response_body[ "@odata.context"] = "$metadata#OcnCourses/$entity" responses.add(responses.POST, self.url_base + self.course_api_path, json=expected_course_response_body, status=200) sap_client = SAPSuccessFactorsAPIClient(self.enterprise_config) sap_client.create_content_metadata(self.content_payload) assert len(responses.calls) == 3 assert responses.calls[ 0].request.url == self.url_base + self.oauth_api_path assert responses.calls[ 1].request.url == self.url_base + self.oauth_api_path assert responses.calls[ 2].request.url == self.url_base + self.course_api_path
def test_expired_access_token(self): """ If our token expires after some call, make sure to get it again. Make a call, have the token expire after waiting some time (technically no time since time is frozen), and make a call again and notice 2 OAuth calls in total are required. """ expired_token_response_body = {"expires_in": 0, "access_token": self.access_token} responses.add( responses.POST, self.url_base + self.oauth_api_path, json=expired_token_response_body, status=200 ) expected_course_response_body = self.content_payload expected_course_response_body["@odata.context"] = "$metadata#OcnCourses/$entity" responses.add( responses.POST, self.url_base + self.course_api_path, json=expected_course_response_body, status=200 ) sap_client = SAPSuccessFactorsAPIClient(self.enterprise_config) sap_client.create_content_metadata(self.content_payload) sap_client.create_content_metadata(self.content_payload) assert len(responses.calls) == 4 assert responses.calls[0].request.url == self.url_base + self.oauth_api_path assert responses.calls[1].request.url == self.url_base + self.course_api_path assert responses.calls[2].request.url == self.url_base + self.oauth_api_path assert responses.calls[3].request.url == self.url_base + self.course_api_path
def test_get_oauth_access_token_response_missing_fields(self): with raises(requests.RequestException): responses.add(responses.POST, self.url_base + self.oauth_api_path, json={"issuedFor": "learning_public_api"}) SAPSuccessFactorsAPIClient.get_oauth_access_token( self.url_base, self.client_id, self.client_secret, self.company_id, self.user_id, self.user_type)
def test_get_oauth_access_token_response_non_json(self): """ Test get_oauth_access_token with non json type response""" with raises(requests.RequestException): responses.add( responses.POST, urljoin(self.url_base, self.oauth_api_path), ) SAPSuccessFactorsAPIClient.get_oauth_access_token( self.url_base, self.client_id, self.client_secret, self.company_id, self.user_id, self.user_type)
def test_expired_access_token(self): expired_token_response_body = { "expires_in": 0, "access_token": self.access_token } responses.add( # pylint: disable=no-member responses.POST, # pylint: disable=no-member self.url_base + self.oauth_api_path, json=expired_token_response_body, status=200) responses.add( # pylint: disable=no-member responses.POST, # pylint: disable=no-member self.url_base + self.oauth_api_path, json=self.expected_token_response_body, status=200) payload = { "ocnCourses": [{ "courseID": "TED1", "providerID": "TED", "status": "ACTIVE", "title": [{ "locale": "English", "value": "Can a computer write poetry?" }] }] } expected_course_response_body = payload expected_course_response_body[ "@odata.context"] = "$metadata#OcnCourses/$entity" responses.add( # pylint: disable=no-member responses.POST, # pylint: disable=no-member self.url_base + self.course_api_path, json=expected_course_response_body, status=200) expected_response = 200, json.dumps(expected_course_response_body) sap_client = SAPSuccessFactorsAPIClient(self.enterprise_config) actual_response = sap_client.send_course_import(payload) assert actual_response == expected_response assert len(responses.calls) == 3 # pylint: disable=no-member assert responses.calls[ 0].request.url == self.url_base + self.oauth_api_path # pylint: disable=no-member assert responses.calls[ 1].request.url == self.url_base + self.oauth_api_path # pylint: disable=no-member assert responses.calls[ 2].request.url == self.url_base + self.course_api_path # pylint: disable=no-member
def test_get_oauth_access_token(): oauth_api_path = "learning/oauth-api/rest/v1/token" url_base = "http://test.successfactors.com/" client_id = "client_id" client_secret = "client_secret" company_id = "company_id" user_id = "user_id" expires_in = 1485383526 access_token = "access_token" SAPSuccessFactorsGlobalConfiguration.objects.create( completion_status_api_path="", course_api_path="", oauth_api_path=oauth_api_path) expected_response_body = { "expiresIn": expires_in, "access_token": access_token } expected_response = (access_token, datetime.datetime.utcfromtimestamp(expires_in)) responses.add( # pylint: disable=no-member responses.POST, # pylint: disable=no-member url_base + oauth_api_path, json=expected_response_body) actual_response = SAPSuccessFactorsAPIClient.get_oauth_access_token( url_base, client_id, client_secret, company_id, user_id) assert actual_response == expected_response assert len(responses.calls) == 1 # pylint: disable=no-member assert responses.calls[0].request.url == url_base + oauth_api_path # pylint: disable=no-member
def test_send_completion_status(self): responses.add( # pylint: disable=no-member responses.POST, # pylint: disable=no-member self.url_base + self.oauth_api_path, json=self.expected_token_response_body, status=200) payload = { "userID": "abc123", "courseID": "course-v1:ColumbiaX+DS101X+1T2016", "providerID": "EDX", "courseCompleted": "true", "completedTimestamp": 1485283526, "instructorName": "Professor Professorson", "grade": "Pass" } expected_response_body = { "success": "true", "completion_status": payload } responses.add( # pylint: disable=no-member responses.POST, # pylint: disable=no-member self.url_base + self.completion_status_api_path, json=expected_response_body, status=200) responses.add( # pylint: disable=no-member responses.POST, # pylint: disable=no-member self.url_base + self.oauth_api_path, json=self.expected_token_response_body, status=200) expected_response = 200, json.dumps(expected_response_body) sap_client = SAPSuccessFactorsAPIClient(self.enterprise_config) actual_response = sap_client.send_completion_status( self.user_type, json.dumps(payload)) assert actual_response == expected_response assert len(responses.calls) == 3 # pylint: disable=no-member assert responses.calls[ 0].request.url == self.url_base + self.oauth_api_path # pylint: disable=no-member assert responses.calls[ 1].request.url == self.url_base + self.oauth_api_path # pylint: disable=no-member expected_url = self.url_base + self.completion_status_api_path assert responses.calls[2].request.url == expected_url # pylint: disable=no-member
def __init__(self, enterprise_configuration): """ The base init function that initializes a SAPSuccessFactorsAPIClient for subsequent calls. Args: enterprise_configuration (SAPSuccessFactorsEnterpriseCustomerConfiguration): An enterprise customers's configuration model for connecting with SAP SuccessFactors """ self.enterprise_configuration = enterprise_configuration self.client = SAPSuccessFactorsAPIClient(enterprise_configuration)
def test_sap_api_connection_error(self): """ ``create_content_metadata`` should raise ClientError when API request fails with a connection error. """ responses.add(responses.POST, self.url_base + self.oauth_api_path, json=self.expected_token_response_body, status=200) expected_course_response_body = self.content_payload expected_course_response_body[ "@odata.context"] = "$metadata#OcnCourses/$entity" responses.add(responses.POST, self.url_base + self.course_api_path, body=requests.exceptions.RequestException()) with raises(ClientError): sap_client = SAPSuccessFactorsAPIClient(self.enterprise_config) sap_client.create_content_metadata(self.content_payload)
def test_get_oauth_access_token_response_missing_fields(): with raises(requests.RequestException): oauth_api_path = "learning/oauth-api/rest/v1/token" url_base = "http://test.successfactors.com/" client_id = "client_id" client_secret = "client_secret" company_id = "company_id" user_id = "user_id" SAPSuccessFactorsGlobalConfiguration.objects.create( completion_status_api_path="", course_api_path="", oauth_api_path=oauth_api_path) responses.add( # pylint: disable=no-member responses.POST, # pylint: disable=no-member url_base + oauth_api_path, json={"issuedFor": "learning_public_api"}) SAPSuccessFactorsAPIClient.get_oauth_access_token( url_base, client_id, client_secret, company_id, user_id)
def test_get_oauth_access_token(self): expected_response = (self.access_token, NOW + datetime.timedelta(seconds=self.expires_in)) responses.add(responses.POST, self.url_base + self.oauth_api_path, json=self.expected_token_response_body, status=200) actual_response = SAPSuccessFactorsAPIClient.get_oauth_access_token( self.url_base, self.client_id, self.client_secret, self.company_id, self.user_id, self.user_type) assert actual_response == expected_response assert len(responses.calls) == 1 assert responses.calls[ 0].request.url == self.url_base + self.oauth_api_path
def has_access_token(self, obj): """ Confirms the presence and validity of the access token for the SAP SuccessFactors client instance Returns: a bool value indicating the presence of the access token Args: obj: The instance of SAPSuccessFactorsEnterpriseCustomerConfiguration being rendered with this admin form. """ try: access_token, expires_at = SAPSuccessFactorsAPIClient.get_oauth_access_token( obj.sapsf_base_url, obj.key, obj.secret, obj.sapsf_company_id, obj.sapsf_user_id, obj.user_type) except (RequestException, ValueError): return False return bool(access_token and expires_at)
def test_get_oauth_access_token(self): expected_response = ( self.access_token, datetime.datetime.utcfromtimestamp(self.expires_in + int(time.time()))) responses.add( # pylint: disable=no-member responses.POST, # pylint: disable=no-member self.url_base + self.oauth_api_path, json=self.expected_token_response_body, status=200) actual_response = SAPSuccessFactorsAPIClient.get_oauth_access_token( self.url_base, self.client_id, self.client_secret, self.company_id, self.user_id, self.user_type) assert actual_response == expected_response assert len(responses.calls) == 1 # pylint: disable=no-member assert responses.calls[ 0].request.url == self.url_base + self.oauth_api_path # pylint: disable=no-member
def test_content_import(self, client_method): responses.add(responses.POST, self.url_base + self.oauth_api_path, json=self.expected_token_response_body, status=200) expected_course_response_body = self.content_payload expected_course_response_body[ "@odata.context"] = "$metadata#OcnCourses/$entity" responses.add(responses.POST, self.url_base + self.course_api_path, json=expected_course_response_body, status=200) sap_client = SAPSuccessFactorsAPIClient(self.enterprise_config) getattr(sap_client, client_method)(self.content_payload) assert len(responses.calls) == 2 assert responses.calls[ 0].request.url == self.url_base + self.oauth_api_path assert responses.calls[ 1].request.url == self.url_base + self.course_api_path
def test_init_no_config(self): with raises(ValueError): SAPSuccessFactorsAPIClient(None)