Skip to content

Commit 87ff589

Browse files
Update load test script to use opaque data
1 parent c3e689e commit 87ff589

File tree

3 files changed

+100
-118
lines changed

3 files changed

+100
-118
lines changed

backend/compact-connect/tests/smoke/load_test_privilege_purchasing.py

Lines changed: 16 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
# ruff: noqa: BLE001 allowing broad exception catching for load testing script
22
#!/usr/bin/env python3
3-
import random
43
import time
54

65
import requests
76
from config import config, logger
8-
from faker import Faker
97
from smoke_common import (
108
SmokeTestFailureException,
119
call_provider_users_me_endpoint,
10+
generate_opaque_data,
1211
get_license_type_abbreviation,
1312
get_provider_user_auth_headers_cached,
1413
)
@@ -24,11 +23,6 @@
2423
# and the 'Transaction IP Velocity Filter', which you can do through the Account Settings under the
2524
# 'Fraud Detection Suite'
2625

27-
name_faker = Faker(['en_US'])
28-
faker = Faker(['en_US'])
29-
30-
AMEX_CARD_NUMBER = '370000000000002'
31-
3226
# List of valid test card numbers from Authorize.net documentation
3327
# https://developer.authorize.net/hello_world/testing_guide.html
3428
TEST_CARD_NUMBERS = [
@@ -38,14 +32,12 @@
3832
'5424000000000015', # Mastercard
3933
'2223000010309703', # Mastercard
4034
'2223000010309711', # Mastercard
41-
AMEX_CARD_NUMBER, # American Express
4235
'6011000000000012', # Discover
43-
'3088000000000017', # JCB
4436
]
4537

4638

47-
def delete_existing_privileges():
48-
"""Delete all existing privileges for the current user."""
39+
def deactivate_existing_privileges():
40+
"""Deactivate all existing privileges for the current user by setting administratorSetStatus to 'inactive'."""
4941
provider_data = call_provider_users_me_endpoint()
5042
privileges = provider_data.get('privileges')
5143
if not privileges:
@@ -59,12 +51,13 @@ def delete_existing_privileges():
5951
license_type_abbreviation = get_license_type_abbreviation(privilege['licenseType'])
6052
privilege_pk = f'{compact}#PROVIDER#{provider_id}'
6153
privilege_sk = f'{compact}#PROVIDER#privilege/{privilege["jurisdiction"]}/{license_type_abbreviation}#'
62-
logger.info(f'Deleting privilege record:\n{privilege_pk}\n{privilege_sk}')
63-
dynamodb_table.delete_item(
64-
Key={
65-
'pk': privilege_pk,
66-
'sk': privilege_sk,
67-
}
54+
logger.info(f'Deactivating privilege record:\n{privilege_pk}\n{privilege_sk}')
55+
56+
# Update the privilege record to set administratorSetStatus to 'inactive'
57+
dynamodb_table.update_item(
58+
Key={'pk': privilege_pk, 'sk': privilege_sk},
59+
UpdateExpression='SET administratorSetStatus = :status',
60+
ExpressionAttributeValues={':status': 'inactive'},
6861
)
6962
# give dynamodb time to propagate
7063
time.sleep(0.5)
@@ -111,25 +104,11 @@ def get_required_attestations(provider_data: dict) -> list[dict]:
111104

112105
def purchase_privilege(jurisdiction: str, card_number: str, attestations: list[dict], license_type: str) -> str:
113106
"""Purchase a privilege for the given jurisdiction using the specified card number."""
107+
# Generate opaque data using the card number
108+
payment_nonce = generate_opaque_data(card_number)
109+
114110
post_body = {
115-
'orderInformation': {
116-
'card': {
117-
'number': card_number,
118-
# this needs to be a random 3-digit number for everything but American Express,
119-
# which is 4 digits
120-
'cvv': str(random.randint(100, 999))
121-
if card_number != AMEX_CARD_NUMBER
122-
else str(random.randint(1000, 9999)),
123-
'expiration': '2050-12',
124-
},
125-
'billing': {
126-
'zip': '44628',
127-
'firstName': name_faker.first_name(),
128-
'lastName': name_faker.last_name(),
129-
'streetAddress': faker.street_address(),
130-
'state': faker.state_abbr(include_territories=False, include_freely_associated_states=False),
131-
},
132-
},
111+
'orderInformation': {'opaqueData': payment_nonce},
133112
'selectedJurisdictions': [jurisdiction],
134113
'attestations': attestations,
135114
'licenseType': license_type,
@@ -165,8 +144,8 @@ def run_load_test(num_iterations: int):
165144
logger.info(f'Starting iteration {iteration + 1} of {num_iterations}')
166145

167146
try:
168-
# Delete existing privileges
169-
delete_existing_privileges()
147+
# Deactivate existing privileges
148+
deactivate_existing_privileges()
170149

171150
# Use different card numbers for each jurisdiction
172151
card_index = iteration % len(TEST_CARD_NUMBERS)

backend/compact-connect/tests/smoke/purchasing_privileges_smoke_tests.py

Lines changed: 3 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#!/usr/bin/env python3
2-
import json
32
import time
4-
import uuid
53
from datetime import UTC, datetime
64

75
import requests
@@ -17,6 +15,7 @@
1715
from smoke_common import (
1816
SmokeTestFailureException,
1917
call_provider_users_me_endpoint,
18+
generate_opaque_data,
2019
get_provider_user_auth_headers_cached,
2120
load_smoke_test_env,
2221
)
@@ -28,8 +27,8 @@
2827

2928

3029
def _generate_post_body(attestations_from_system, license_type):
31-
# Generate a payment nonce for testing
32-
payment_nonce = _generate_opaque_data()
30+
# Generate a payment nonce for testing using the default test card
31+
payment_nonce = generate_opaque_data('4111111111111111')
3332

3433
return {
3534
'orderInformation': {'opaqueData': payment_nonce},
@@ -255,83 +254,6 @@ def test_purchasing_privilege(delete_current_privilege: bool = True):
255254
logger.info(f'Successfully purchased privilege record: {matching_privilege}')
256255

257256

258-
def _generate_opaque_data():
259-
"""
260-
Generate a payment nonce using Authorize.Net's Secure Payment Container API.
261-
This allows us to create payment nonces programmatically for testing.
262-
"""
263-
264-
# Call the purchase privilege options endpoint and extract the api login id and
265-
# public key from the compact configuration object that is returned.
266-
headers = get_provider_user_auth_headers_cached()
267-
response = requests.get(
268-
url=f'{config.api_base_url}/v1/purchases/privileges/options',
269-
headers=headers,
270-
timeout=10,
271-
)
272-
273-
if response.status_code != 200:
274-
raise SmokeTestFailureException(f'Failed to get purchase privilege options. Response: {response.json()}')
275-
276-
response_body = response.json()
277-
compact_data = next((item for item in response_body['items'] if item.get('type') == 'compact'), None)
278-
279-
if not compact_data:
280-
raise SmokeTestFailureException('No compact data found in purchase privilege options response')
281-
282-
if 'paymentProcessorPublicFields' not in compact_data:
283-
raise SmokeTestFailureException('No paymentProcessorPublicFields found in compact data')
284-
285-
payment_fields = compact_data['paymentProcessorPublicFields']
286-
api_login_id = payment_fields.get('apiLoginId')
287-
public_client_key = payment_fields.get('publicClientKey')
288-
289-
if not api_login_id or not public_client_key:
290-
raise SmokeTestFailureException(f'Missing credentials in paymentProcessorPublicFields: {payment_fields}')
291-
292-
# Generate the payment nonce using the secure payment container API
293-
unique_id = str(uuid.uuid4())
294-
295-
# Create the secure payment container request
296-
request_data = {
297-
'securePaymentContainerRequest': {
298-
'merchantAuthentication': {
299-
'name': api_login_id,
300-
'clientKey': public_client_key, # Use the public client key
301-
},
302-
'refId': '12345',
303-
'data': {
304-
'type': 'TOKEN',
305-
'id': unique_id,
306-
'token': {
307-
'cardNumber': '4111111111111111', # Visa test card
308-
'expirationDate': '122030',
309-
'cardCode': '999',
310-
'fullName': 'SmokeTest User',
311-
},
312-
},
313-
}
314-
}
315-
316-
# Make the API request
317-
test_url = 'https://apitest.authorize.net/xml/v1/request.api'
318-
headers = {'Content-Type': 'application/json'}
319-
response = requests.post(test_url, json=request_data, headers=headers, timeout=30)
320-
321-
if response.status_code == 200:
322-
response_data = json.loads(response.content.decode('utf-8-sig'))
323-
324-
# Extract the payment nonce from the response
325-
# The exact structure may vary, but it should contain the opaque data
326-
if 'opaqueData' in response_data:
327-
logger.info('Generated opaque data.')
328-
return response_data['opaqueData']
329-
logger.error(f'No opaqueData in response: {response_data}')
330-
raise SmokeTestFailureException(f'No opaqueData in response: {response_data}')
331-
logger.error(f'Failed to generate payment nonce: {response.status_code} - {response.text}')
332-
raise SmokeTestFailureException(f'Failed to generate payment nonce: {response.status_code} - {response.text}')
333-
334-
335257
if __name__ == '__main__':
336258
# Load environment variables from smoke_tests_env.json
337259
load_smoke_test_env()

backend/compact-connect/tests/smoke/smoke_common.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22
import os
33
import sys
4+
import uuid
45

56
import boto3
67
import requests
@@ -237,3 +238,83 @@ def get_all_provider_database_records():
237238
)
238239

239240
return query_result['Items']
241+
242+
243+
def generate_opaque_data(card_number: str):
244+
"""
245+
Generate a payment nonce using Authorize.Net's Secure Payment Container API.
246+
This allows us to create payment nonces programmatically for testing.
247+
248+
:param card_number: The test card number to use for generating the opaque data
249+
:return: The opaque data object containing the payment nonce
250+
"""
251+
252+
# Call the purchase privilege options endpoint and extract the api login id and
253+
# public key from the compact configuration object that is returned.
254+
headers = get_provider_user_auth_headers_cached()
255+
response = requests.get(
256+
url=f'{config.api_base_url}/v1/purchases/privileges/options',
257+
headers=headers,
258+
timeout=10,
259+
)
260+
261+
if response.status_code != 200:
262+
raise SmokeTestFailureException(f'Failed to get purchase privilege options. Response: {response.json()}')
263+
264+
response_body = response.json()
265+
compact_data = next((item for item in response_body['items'] if item.get('type') == 'compact'), None)
266+
267+
if not compact_data:
268+
raise SmokeTestFailureException('No compact data found in purchase privilege options response')
269+
270+
if 'paymentProcessorPublicFields' not in compact_data:
271+
raise SmokeTestFailureException('No paymentProcessorPublicFields found in compact data')
272+
273+
payment_fields = compact_data['paymentProcessorPublicFields']
274+
api_login_id = payment_fields.get('apiLoginId')
275+
public_client_key = payment_fields.get('publicClientKey')
276+
277+
if not api_login_id or not public_client_key:
278+
raise SmokeTestFailureException(f'Missing credentials in paymentProcessorPublicFields: {payment_fields}')
279+
280+
# Generate the payment nonce using the secure payment container API
281+
unique_id = str(uuid.uuid4())
282+
283+
# Create the secure payment container request
284+
request_data = {
285+
'securePaymentContainerRequest': {
286+
'merchantAuthentication': {
287+
'name': api_login_id,
288+
'clientKey': public_client_key, # Use the public client key
289+
},
290+
'refId': '12345',
291+
'data': {
292+
'type': 'TOKEN',
293+
'id': unique_id,
294+
'token': {
295+
'cardNumber': card_number,
296+
'expirationDate': '122030',
297+
'cardCode': '999',
298+
'fullName': 'SmokeTest User',
299+
},
300+
},
301+
}
302+
}
303+
304+
# Make the API request
305+
test_url = 'https://apitest.authorize.net/xml/v1/request.api'
306+
headers = {'Content-Type': 'application/json'}
307+
response = requests.post(test_url, json=request_data, headers=headers, timeout=30)
308+
309+
if response.status_code == 200:
310+
response_data = json.loads(response.content.decode('utf-8-sig'))
311+
312+
# Extract the payment nonce from the response
313+
# The exact structure may vary, but it should contain the opaque data
314+
if 'opaqueData' in response_data:
315+
logger.info('Generated opaque data.')
316+
return response_data['opaqueData']
317+
logger.error(f'No opaqueData in response: {response_data}')
318+
raise SmokeTestFailureException(f'No opaqueData in response: {response_data}')
319+
logger.error(f'Failed to generate payment nonce: {response.status_code} - {response.text}')
320+
raise SmokeTestFailureException(f'Failed to generate payment nonce: {response.status_code} - {response.text}')

0 commit comments

Comments
 (0)