-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: basics of business logic for customer provisioning
ENT-10071
- Loading branch information
1 parent
a951ee9
commit 2f0c282
Showing
7 changed files
with
340 additions
and
19 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
Tests for the provisioning views. | ||
""" | ||
import uuid | ||
from unittest import mock | ||
|
||
import ddt | ||
from edx_rbac.constants import ALL_ACCESS_CONTEXT | ||
|
@@ -43,11 +44,6 @@ class TestProvisioningAuth(APITest): | |
{'system_wide_role': SYSTEM_ENTERPRISE_ADMIN_ROLE, 'context': ALL_ACCESS_CONTEXT}, | ||
status.HTTP_403_FORBIDDEN, | ||
), | ||
# Even operators can't provision | ||
( | ||
{'system_wide_role': SYSTEM_ENTERPRISE_OPERATOR_ROLE, 'context': ALL_ACCESS_CONTEXT}, | ||
status.HTTP_403_FORBIDDEN, | ||
), | ||
# No JWT based auth, no soup for you. | ||
( | ||
None, | ||
|
@@ -66,15 +62,26 @@ def test_provisioning_create_view_forbidden(self, role_context_dict, expected_re | |
response = self.client.post(PROVISIONING_CREATE_ENDPOINT) | ||
assert response.status_code == expected_response_code | ||
|
||
def test_provisioning_create_allowed_for_provisioning_admins(self): | ||
@ddt.data( | ||
( | ||
{'system_wide_role': SYSTEM_ENTERPRISE_OPERATOR_ROLE, 'context': ALL_ACCESS_CONTEXT}, | ||
status.HTTP_201_CREATED, | ||
), | ||
( | ||
{'system_wide_role': SYSTEM_ENTERPRISE_PROVISIONING_ADMIN_ROLE, 'context': ALL_ACCESS_CONTEXT}, | ||
status.HTTP_201_CREATED, | ||
), | ||
) | ||
@ddt.unpack | ||
@mock.patch('enterprise_access.apps.api.v1.views.provisioning.provisioning_api') | ||
def test_provisioning_create_allowed_for_provisioning_admins( | ||
self, role_context_dict, expected_response_code, mock_provisioning_api, | ||
): | ||
""" | ||
Tests that we get expected 200 response for the provisioning create view when | ||
the requesting user has the correct system role and provides a valid request payload. | ||
""" | ||
self.set_jwt_cookie([{ | ||
'system_wide_role': SYSTEM_ENTERPRISE_PROVISIONING_ADMIN_ROLE, | ||
'context': ALL_ACCESS_CONTEXT, | ||
}]) | ||
self.set_jwt_cookie([role_context_dict]) | ||
|
||
request_payload = { | ||
"enterprise_customer": { | ||
|
@@ -89,4 +96,115 @@ def test_provisioning_create_allowed_for_provisioning_admins(self): | |
], | ||
} | ||
response = self.client.post(PROVISIONING_CREATE_ENDPOINT, data=request_payload) | ||
assert response.status_code == expected_response_code | ||
|
||
mock_provisioning_api.get_or_create_enterprise_customer.assert_called_once_with( | ||
**request_payload['enterprise_customer'], | ||
) | ||
|
||
created_customer = mock_provisioning_api.get_or_create_enterprise_customer.return_value | ||
mock_provisioning_api.get_or_create_enterprise_admin_users.assert_called_once_with( | ||
enterprise_customer_uuid=created_customer['uuid'], | ||
user_emails=['[email protected]'], | ||
) | ||
|
||
|
||
@ddt.ddt | ||
class TestProvisioningEndToEnd(APITest): | ||
""" | ||
Tests end-to-end calls to provisioning endpoints through mocked-out calls | ||
to downstream services. | ||
""" | ||
def setUp(self): | ||
super().setUp() | ||
self.set_jwt_cookie([ | ||
{ | ||
'system_wide_role': SYSTEM_ENTERPRISE_PROVISIONING_ADMIN_ROLE, | ||
'context': ALL_ACCESS_CONTEXT, | ||
}, | ||
]) | ||
|
||
@ddt.data( | ||
# Data representing the state where a net-new customer is created. | ||
{ | ||
'existing_customer_data': None, | ||
'created_customer_data': { | ||
'name': 'Test Customer', | ||
'slug': 'test-customer', | ||
'country': 'US', | ||
'uuid': TEST_ENTERPRISE_UUID, | ||
}, | ||
'expected_get_customer_kwargs': { | ||
'enterprise_customer_slug': 'test-customer', | ||
}, | ||
'create_customer_called': True, | ||
'expected_create_customer_kwargs': { | ||
'name': 'Test Customer', | ||
'slug': 'test-customer', | ||
'country': 'US', | ||
}, | ||
}, | ||
# Data representing the state where a customer with the given slug exists. | ||
{ | ||
'existing_customer_data': { | ||
'name': 'Test Customer', | ||
'slug': 'test-customer', | ||
'country': 'US', | ||
'uuid': TEST_ENTERPRISE_UUID, | ||
}, | ||
'created_customer_data': None, | ||
'expected_get_customer_kwargs': { | ||
'enterprise_customer_slug': 'test-customer', | ||
}, | ||
'create_customer_called': False, | ||
'expected_create_customer_kwargs': None | ||
}, | ||
) | ||
@mock.patch('enterprise_access.apps.provisioning.api.LmsApiClient') | ||
def test_get_or_create_customer_and_admins_created(self, test_data, mock_lms_api_client): | ||
""" | ||
Tests cases where admins don't exist and customer is fetched or created. | ||
""" | ||
mock_client = mock_lms_api_client.return_value | ||
mock_client.get_enterprise_customer_data.return_value = test_data['existing_customer_data'] | ||
mock_client.get_enterprise_admin_users.return_value = [] | ||
mock_client.get_enterprise_pending_admin_users.return_value = [] | ||
|
||
if test_data['created_customer_data']: | ||
mock_client.create_enterprise_customer.return_value = test_data['created_customer_data'] | ||
|
||
mock_client.create_enterprise_admin_user.side_effect = [ | ||
{'user_email': '[email protected]', 'enterprise_customer_uuid': TEST_ENTERPRISE_UUID}, | ||
{'user_email': '[email protected]', 'enterprise_customer_uuid': TEST_ENTERPRISE_UUID}, | ||
] | ||
|
||
request_payload = { | ||
"enterprise_customer": { | ||
'name': 'Test Customer', | ||
'slug': 'test-customer', | ||
'country': 'US', | ||
}, | ||
"pending_admins": [ | ||
{"user_email": "[email protected]"}, | ||
{"user_email": "[email protected]"}, | ||
], | ||
} | ||
response = self.client.post(PROVISIONING_CREATE_ENDPOINT, data=request_payload) | ||
assert response.status_code == status.HTTP_201_CREATED | ||
|
||
mock_client.get_enterprise_customer_data.assert_called_once_with( | ||
**test_data['expected_get_customer_kwargs'], | ||
) | ||
if test_data['create_customer_called']: | ||
mock_client.create_enterprise_customer.assert_called_once_with( | ||
**test_data['expected_create_customer_kwargs'], | ||
) | ||
else: | ||
self.assertFalse(mock_client.create_enterprise_customer.called) | ||
|
||
mock_client.get_enterprise_admin_users.assert_called_once_with(TEST_ENTERPRISE_UUID) | ||
mock_client.get_enterprise_pending_admin_users.assert_called_once_with(TEST_ENTERPRISE_UUID) | ||
mock_client.create_enterprise_admin_user.assert_has_calls([ | ||
mock.call(TEST_ENTERPRISE_UUID, '[email protected]'), | ||
mock.call(TEST_ENTERPRISE_UUID, '[email protected]'), | ||
], any_order=True) |
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 |
---|---|---|
|
@@ -216,6 +216,43 @@ def test_create_enterprise_customer_data(self, mock_oauth_client, mock_json): | |
timeout=settings.LMS_CLIENT_TIMEOUT, | ||
) | ||
|
||
@mock.patch('requests.Response.json') | ||
@mock.patch('enterprise_access.apps.api_client.base_oauth.OAuthAPIClient') | ||
def test_get_enterprise_pending_admin_users(self, mock_oauth_client, mock_json): | ||
""" | ||
Test that we can use the LmsApiClient to fetch existing pending admin records. | ||
""" | ||
customer_uuid = str(uuid4()) | ||
|
||
mock_response_payload_results = [{ | ||
'id': 1, | ||
'enterprise_customer': customer_uuid, | ||
'user_email': '[email protected]', | ||
}] | ||
mock_response_payload = { | ||
'count': 1, | ||
'results': mock_response_payload_results, | ||
} | ||
mock_json.return_value = mock_response_payload | ||
|
||
mock_get = mock_oauth_client.return_value.get | ||
|
||
mock_get.return_value = requests.Response() | ||
mock_get.return_value.status_code = 200 | ||
|
||
client = LmsApiClient() | ||
response_payload = client.get_enterprise_pending_admin_users(customer_uuid) | ||
|
||
self.assertEqual(response_payload, mock_response_payload_results) | ||
expected_url = ( | ||
'http://edx-platform.example.com/enterprise/api/v1/pending-enterprise-admin/' | ||
f'?enterprise_customer={customer_uuid}' | ||
) | ||
mock_get.assert_called_once_with( | ||
expected_url, | ||
timeout=settings.LMS_CLIENT_TIMEOUT, | ||
) | ||
|
||
@mock.patch('requests.Response.json') | ||
@mock.patch('enterprise_access.apps.api_client.base_oauth.OAuthAPIClient') | ||
def test_create_enterprise_admin_user(self, mock_oauth_client, mock_json): | ||
|
@@ -316,6 +353,31 @@ def test_create_enterprise_admin_error(self, mock_oauth_client): | |
timeout=settings.LMS_CLIENT_TIMEOUT, | ||
) | ||
|
||
@mock.patch('enterprise_access.apps.api_client.base_oauth.OAuthAPIClient') | ||
def test_get_enterprise_pending_admin_error(self, mock_oauth_client): | ||
""" | ||
Tests that we raise an exception appropriately when listing pending | ||
admin records with the LmsApiClient(). | ||
""" | ||
customer_uuid = str(uuid4()) | ||
mock_get = mock_oauth_client.return_value.get | ||
|
||
mock_get.side_effect = requests.exceptions.HTTPError('whoopsie') | ||
mock_get.return_value.status_code = 400 | ||
|
||
client = LmsApiClient() | ||
with self.assertRaises(requests.exceptions.HTTPError): | ||
client.get_enterprise_pending_admin_users(customer_uuid) | ||
|
||
expected_url = ( | ||
'http://edx-platform.example.com/enterprise/api/v1/pending-enterprise-admin/' | ||
f'?enterprise_customer={customer_uuid}' | ||
) | ||
mock_get.assert_called_once_with( | ||
expected_url, | ||
timeout=settings.LMS_CLIENT_TIMEOUT, | ||
) | ||
|
||
@mock.patch('enterprise_access.apps.api_client.base_oauth.OAuthAPIClient') | ||
def test_unlink_users_from_enterprise(self, mock_oauth_client): | ||
""" | ||
|
Empty file.
Oops, something went wrong.