From 7493b9c3d6d0ec7844ac43a01d626972d508df9d Mon Sep 17 00:00:00 2001 From: Philip Kalinsky Date: Thu, 30 Jan 2020 14:48:16 -0500 Subject: [PATCH] premium product purchase unit tests. --- atst/domain/csp/cloud/azure_cloud_provider.py | 20 +++- atst/domain/csp/cloud/mock_cloud_provider.py | 15 ++- atst/domain/csp/cloud/models.py | 27 +----- tests/domain/cloud/test_azure_csp.py | 92 +++++++++++++++++++ 4 files changed, 121 insertions(+), 33 deletions(-) diff --git a/atst/domain/csp/cloud/azure_cloud_provider.py b/atst/domain/csp/cloud/azure_cloud_provider.py index 2b50028f..b0e2de86 100644 --- a/atst/domain/csp/cloud/azure_cloud_provider.py +++ b/atst/domain/csp/cloud/azure_cloud_provider.py @@ -506,12 +506,21 @@ class AzureCloudProvider(CloudProviderInterface): "Could not resolve token for aad premium product purchase" ) - create_product_purchase_body = payload.dict(by_alias=True) + payload_as_dict = payload.dict(by_alias=True) + + create_product_purchase_body = { + "type": "AADPremium", + "sku": "AADP1", + "productProperties": { + "beneficiaryTenantId": payload_as_dict["productProperties"]["beneficiaryTenantId"], + }, + "quantity": payload_as_dict.get("quantity"), + } create_product_purchase_headers = { "Authorization": f"Bearer {sp_token}", } - product_purchase_url = f"https://management.azure.com//providers/Microsoft.Billing/billingAccounts/{payload.billing_account_name}/billingProfiles/{payload.billing_profile_name}/products?api-version=2019-10-01-preview" + product_purchase_url = f"https://management.azure.com/providers/Microsoft.Billing/billingAccounts/{payload.billing_account_name}/billingProfiles/{payload.billing_profile_name}/products?api-version=2019-10-01-preview" result = self.sdk.requests.post( product_purchase_url, @@ -524,7 +533,7 @@ class AzureCloudProvider(CloudProviderInterface): return self._ok(ProductPurchaseCSPResult(**result.headers)) elif result.status_code == 200: # NB: Swagger docs imply call can sometimes resolve immediately - return self._ok(ProductPurchaseCSPResult(**result.json())) + return self._ok(ProductPurchaseVerificationCSPResult(**result.json())) else: return self._error(result.json()) @@ -535,7 +544,7 @@ class AzureCloudProvider(CloudProviderInterface): sp_token = self._get_sp_token(payload.creds) if sp_token is None: raise AuthenticationException( - "Could not resolve token for task order billing validation" + "Could not resolve token for aad premium product purchase validation" ) auth_header = { @@ -545,12 +554,13 @@ class AzureCloudProvider(CloudProviderInterface): result = self.sdk.requests.get( payload.product_purchase_verify_url, headers=auth_header ) + premium_purchase_date = result.json()["product"]["properties"]["purchaseDate"] if result.status_code == 202: # 202 has location/retry after headers return self._ok(ProductPurchaseCSPResult(**result.headers)) elif result.status_code == 200: - return self._ok(ProductPurchaseVerificationCSPResult(**result.json())) + return self._ok(ProductPurchaseVerificationCSPResult(premium_purchase_date=premium_purchase_date)) else: return self._error(result.json()) diff --git a/atst/domain/csp/cloud/mock_cloud_provider.py b/atst/domain/csp/cloud/mock_cloud_provider.py index d69b7ff0..4ef72fb9 100644 --- a/atst/domain/csp/cloud/mock_cloud_provider.py +++ b/atst/domain/csp/cloud/mock_cloud_provider.py @@ -282,15 +282,22 @@ class MockCloudProvider(CloudProviderInterface): ) - def create_product_purchase(self, payload: ProductPurchaseCSPPayload): + def create_product_purchase( + self, payload: ProductPurchaseCSPPayload + ): self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) self._maybe_raise(self.SERVER_FAILURE_PCT, self.SERVER_EXCEPTION) self._maybe_raise(self.UNAUTHORIZED_RATE, self.AUTHORIZATION_EXCEPTION) return ProductPurchaseCSPResult( - **{"Location": "https://somelocation", "Retry-After": "10"} + **dict( + product_purchase_verify_url="https://zombo.com", + product_purchase_retry_after=10, + ) ) + + def create_product_purchase_verification( self, payload: ProductPurchaseVerificationCSPPayload ): @@ -299,11 +306,9 @@ class MockCloudProvider(CloudProviderInterface): self._maybe_raise(self.UNAUTHORIZED_RATE, self.AUTHORIZATION_EXCEPTION) return ProductPurchaseVerificationCSPResult( - **{ - } + **dict(premium_purchase_date="2020-01-30T18:57:05.981Z") ) - def create_or_update_user(self, auth_credentials, user_info, csp_role_id): self._authorize(auth_credentials) diff --git a/atst/domain/csp/cloud/models.py b/atst/domain/csp/cloud/models.py index ad9d171e..d119b7eb 100644 --- a/atst/domain/csp/cloud/models.py +++ b/atst/domain/csp/cloud/models.py @@ -342,25 +342,15 @@ class KeyVaultCredentials(BaseModel): return values -class AadPremiumProductParameter(AliasModel): + +class ProductPurchaseCSPPayload(BaseCSPPayload): type: str sku: str quantity: int productProperties: Dict - - #{ - # "type": "string", - # "sku": "string", - # "quantity": 0, - # "productProperties": { - # "beneficiaryTenantId": "string" - # } - #} - -class ProductPurchaseCSPPayload(BaseCSPPayload): billing_account_name: str billing_profile_name: str - parameters: List[AadPremiumProductParameter] + class ProductPurchaseCSPResult(AliasModel): product_purchase_verify_url: str @@ -378,13 +368,4 @@ class ProductPurchaseVerificationCSPPayload(BaseCSPPayload): class ProductPurchaseVerificationCSPResult(AliasModel): - billing_profile_id: str - billing_profile_name: str - billing_profile_enabled_plan_details: BillingProfileEnabledPlanDetails - - class Config: - fields = { - "billing_profile_id": "id", - "billing_profile_name": "name", - "billing_profile_enabled_plan_details": "properties", - } + premium_purchase_date: str diff --git a/tests/domain/cloud/test_azure_csp.py b/tests/domain/cloud/test_azure_csp.py index 39fa2f77..a59a51ea 100644 --- a/tests/domain/cloud/test_azure_csp.py +++ b/tests/domain/cloud/test_azure_csp.py @@ -18,6 +18,10 @@ from atst.domain.csp.cloud.models import ( BillingProfileTenantAccessCSPResult, BillingProfileVerificationCSPPayload, BillingProfileVerificationCSPResult, + ProductPurchaseCSPPayload, + ProductPurchaseCSPResult, + ProductPurchaseVerificationCSPPayload, + ProductPurchaseVerificationCSPResult, TaskOrderBillingCreationCSPPayload, TaskOrderBillingCreationCSPResult, TaskOrderBillingVerificationCSPPayload, @@ -335,6 +339,7 @@ def test_create_task_order_billing_creation(mock_azure: AzureCloudProvider): result = mock_azure.create_task_order_billing_creation(payload) body: TaskOrderBillingCreationCSPResult = result.get("body") + assert ( body.task_order_billing_verify_url == "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/operationResults/patchBillingProfile_KQWI-W2SU-BG7-TGB:02715576-4118-466c-bca7-b1cd3169ff46?api-version=2019-10-01-preview" @@ -435,3 +440,90 @@ def test_create_billing_instruction(mock_azure: AzureCloudProvider): result = mock_azure.create_billing_instruction(payload) body: BillingInstructionCSPResult = result.get("body") assert body.reported_clin_name == "TO1:CLIN001" + + +def test_create_product_purchase(mock_azure: AzureCloudProvider): + mock_azure.sdk.adal.AuthenticationContext.return_value.context.acquire_token_with_client_credentials.return_value = { + "accessToken": "TOKEN" + } + + mock_result = Mock() + mock_result.status_code = 202 + mock_result.headers = { + "Location": "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/operationResults/patchBillingProfile_KQWI-W2SU-BG7-TGB:02715576-4118-466c-bca7-b1cd3169ff46?api-version=2019-10-01-preview", + "Retry-After": "10", + } + + mock_azure.sdk.requests.post.return_value = mock_result + + payload = ProductPurchaseCSPPayload( + **dict( + creds=creds, + type="AADPremium", + sku="AADP1", + productProperties={ + "beneficiaryTenantId": str(uuid4()), + }, + quantity=4, + billing_account_name="7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31", + billing_profile_name="KQWI-W2SU-BG7-TGB", + ) + ) + + result = mock_azure.create_product_purchase(payload) + body: ProductPurchaseCSPResult = result.get("body") + assert ( + body.product_purchase_verify_url == "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/operationResults/patchBillingProfile_KQWI-W2SU-BG7-TGB:02715576-4118-466c-bca7-b1cd3169ff46?api-version=2019-10-01-preview" + ) + +def test_create_product_purchase_verification(mock_azure): + mock_azure.sdk.adal.AuthenticationContext.return_value.context.acquire_token_with_client_credentials.return_value = { + "accessToken": "TOKEN" + } + + mock_result = Mock() + mock_result.status_code = 200 + mock_result.json.return_value = { + "status": "string", + "product": { + "id": "string", + "name": "string", + "type": "string", + "properties": { + "displayName": "string", + "purchaseDate": "2020-01-30T18:57:05.981Z", + "productTypeId": "string", + "productType": "string", + "status": "Active", + "endDate": "2020-01-30T18:57:05.981Z", + "billingFrequency": "OneTime", + "lastCharge": { + "currency": "string", + "value": 0 + }, + "lastChargeDate": "2020-01-30T18:57:05.981Z", + "quantity": 0, + "skuId": "string", + "skuDescription": "string", + "availabilityId": "string", + "parentProductId": "string", + "invoiceSectionId": "string", + "invoiceSectionDisplayName": "string", + "billingProfileId": "string", + "billingProfileDisplayName": "string" + } + } + } + + mock_azure.sdk.requests.get.return_value = mock_result + + payload = ProductPurchaseVerificationCSPPayload( + **dict( + creds=creds, + product_purchase_verify_url="https://management.azure.com/providers/Microsoft.Billing/billingAccounts/7c89b735-b22b-55c0-ab5a-c624843e8bf6:de4416ce-acc6-44b1-8122-c87c4e903c91_2019-05-31/operationResults/createBillingProfile_478d5706-71f9-4a8b-8d4e-2cbaca27a668?api-version=2019-10-01-preview", + ) + ) + + result = mock_azure.create_product_purchase_verification(payload) + body: ProductPurchaseVerificationCSPResult = result.get("body") + assert body.premium_purchase_date == "2020-01-30T18:57:05.981Z"