Skip to content

Commit 4aa6724

Browse files
PR feedback
1 parent c4e81c2 commit 4aa6724

6 files changed

Lines changed: 36 additions & 19 deletions

File tree

backend/compact-connect/lambdas/python/common/cc_common/data_model/data_client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,7 +1065,7 @@ def _get_privilege_update_records_directly(
10651065

10661066
return [PrivilegeUpdateData.from_database_record(item) for item in response_items]
10671067

1068-
@logger_inject_kwargs(logger, 'compact', 'provider_id', 'detail', 'jurisdiction', 'license_type')
1068+
@logger_inject_kwargs(logger, 'compact', 'provider_id', 'detail', 'jurisdiction', 'license_type_abbr')
10691069
def get_privilege_data(
10701070
self,
10711071
*,
@@ -1117,7 +1117,7 @@ def get_privilege_data(
11171117

11181118
return result
11191119

1120-
@logger_inject_kwargs(logger, 'compact', 'provider_id', 'jurisdiction', 'license_type')
1120+
@logger_inject_kwargs(logger, 'compact', 'provider_id', 'jurisdiction', 'license_type_abbr')
11211121
def deactivate_privilege(
11221122
self, *, compact: str, provider_id: str, jurisdiction: str, license_type_abbr: str, deactivation_details: dict
11231123
) -> None:

backend/compact-connect/lambdas/python/disaster-recovery/handlers/rollback_license_upload.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def from_dict(cls, data: dict) -> 'RollbackResults':
181181
RevertedLicense(
182182
jurisdiction=reverted_license['jurisdiction'],
183183
license_type=reverted_license['licenseType'],
184-
revision_id=uuid4(),
184+
revision_id=reverted_license['revisionId'],
185185
action=reverted_license['action'],
186186
)
187187
for reverted_license in summary.get('licensesReverted', [])
@@ -190,7 +190,7 @@ def from_dict(cls, data: dict) -> 'RollbackResults':
190190
RevertedPrivilege(
191191
jurisdiction=reverted_privilege['jurisdiction'],
192192
license_type=reverted_privilege['licenseType'],
193-
revision_id=uuid4(),
193+
revision_id=reverted_privilege['revisionId'],
194194
action=reverted_privilege['action'],
195195
)
196196
for reverted_privilege in summary.get('privilegesReverted', [])
@@ -723,7 +723,7 @@ def add_delete(pk: str, sk: str, update_record: bool):
723723
IneligibleUpdate(
724724
record_type='privilegeUpdate',
725725
type_of_update=privilege_update.updateType,
726-
update_time=privilege_update.dateOfUpdate.isoformat(),
726+
update_time=privilege_update.createDate.isoformat(),
727727
license_type=privilege_update.licenseType,
728728
# include privilege jurisdiction in reason
729729
reason=f"Privilege in jurisdiction '{privilege_update.jurisdiction}' was updated "
@@ -736,7 +736,7 @@ def add_delete(pk: str, sk: str, update_record: bool):
736736
IneligibleUpdate(
737737
record_type='privilegeUpdate',
738738
type_of_update=privilege_update.updateType,
739-
update_time=privilege_update.dateOfUpdate.isoformat(),
739+
update_time=privilege_update.createDate.isoformat(),
740740
license_type=privilege_update.licenseType,
741741
# include privilege jurisdiction in reason
742742
reason=f"Privilege in jurisdiction '{privilege_update.jurisdiction}' was deactivated "
@@ -839,6 +839,11 @@ def add_delete(pk: str, sk: str, update_record: bool):
839839
)
840840
# license was not first uploaded during the upload window, revert it to last previous state before the upload
841841
else:
842+
# if the provider is ineligible for rollback, the list of license updates may be empty, and we need to
843+
# defensively check for that here and continue to the next license
844+
if not license_updates_in_window:
845+
continue
846+
842847
# Find the earliest update in the window to get the previous state
843848
license_updates_in_window.sort(key=lambda x: x.createDate)
844849
earliest_update_in_window = license_updates_in_window[0]
@@ -1037,7 +1042,7 @@ def _write_results_to_s3(key: str, results: RollbackResults):
10371042
)
10381043
logger.info('Results written to S3', bucket=config.disaster_recovery_results_bucket_name, key=key)
10391044
# handle json serialization errors
1040-
except json.JSONDecodeError as e:
1045+
except TypeError as e:
10411046
logger.error(f'Error writing results to S3: {str(e)}')
10421047
raise
10431048
# handle other errors by logging the full object and raising the exception

backend/compact-connect/lambdas/python/disaster-recovery/tests/function/test_rollback_license_upload.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,14 @@ def test_rollback_handles_pagination_when_provider_id_present_in_event_input(sel
10881088
self.assertEqual(0, result_first['providersFailed'])
10891089
self.assertEqual(mock_second_provider_id, result_first['continueFromProviderId'])
10901090

1091+
# Verify: S3 results contain first provider with revision id
1092+
s3_key = f'licenseUploadRollbacks/{MOCK_EXECUTION_NAME}/results.json'
1093+
s3_obj = self.config.s3_client.get_object(Bucket=self.config.disaster_recovery_results_bucket_name, Key=s3_key)
1094+
first_results_data = json.loads(s3_obj['Body'].read().decode('utf-8'))
1095+
1096+
# grab the revision id from the results which we will use when asserting on the final object
1097+
revision_id = first_results_data['revertedProviderSummaries'][0]['licensesReverted'][0]['revisionId']
1098+
10911099
# Execute: Second invocation (continue from where we left off)
10921100
# Reset mock time for second invocation
10931101
mock_time.time.side_effect = [0, 1] # Won't timeout this time
@@ -1117,7 +1125,7 @@ def test_rollback_handles_pagination_when_provider_id_present_in_event_input(sel
11171125
'action': 'REVERT',
11181126
'jurisdiction': 'oh',
11191127
'licenseType': 'speech-language pathologist',
1120-
'revisionId': ANY,
1128+
'revisionId': revision_id,
11211129
}
11221130
],
11231131
'privilegesReverted': [],
@@ -1132,6 +1140,7 @@ def test_rollback_handles_pagination_when_provider_id_present_in_event_input(sel
11321140
'action': 'REVERT',
11331141
'jurisdiction': 'oh',
11341142
'licenseType': 'speech-language pathologist',
1143+
# unknown random UUID, we won't check for it here
11351144
'revisionId': ANY,
11361145
}
11371146
],

backend/compact-connect/lambdas/python/migration/migrate_update_sort_keys/main.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def on_create(self, properties: dict) -> None:
1818

1919
def on_update(self, properties: dict) -> None:
2020
"""
21-
No-op on delete.
21+
No-op on update.
2222
"""
2323

2424
def on_delete(self, _properties: dict) -> CustomResourceResponse | None:
@@ -33,9 +33,10 @@ def on_delete(self, _properties: dict) -> CustomResourceResponse | None:
3333
def do_migration(_properties: dict) -> None:
3434
"""
3535
This migration performs the following:
36-
- Scans the provider table for all privilege update records
37-
- For each update record, adds effectiveDate and createDate equal to that updates dateOfUpdate
38-
- Handles batching for cases where there are more than 100 records to update
36+
- Scans the provider table for all update records
37+
- For each update record, load the records and serialize it again,
38+
so the schema classes will generate the new sort key patterns
39+
- Recreate the records by deleting the update records with the old sort key and storing the migrated records.
3940
"""
4041
logger.info('Starting update record sort key migration')
4142

backend/compact-connect/lambdas/python/provider-data-v1/tests/function/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,10 @@ def create_provider_table(self):
166166
{'AttributeName': 'licenseUploadDateGSIPK', 'KeyType': 'HASH'},
167167
{'AttributeName': 'licenseUploadDateGSISK', 'KeyType': 'RANGE'},
168168
],
169-
'Projection': {'ProjectionType': 'KEYS_ONLY'},
169+
'Projection': {
170+
'ProjectionType': 'INCLUDE',
171+
'NonKeyAttributes': ['providerId'],
172+
},
170173
},
171174
],
172175
)

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ def wait_for_all_providers_created(staff_headers: dict, expected_count: int, max
178178

179179
last_key = None
180180
page_num = 1
181-
all_provider_ids = []
181+
all_provider_ids: set[str] = set()
182182
while time.time() - start_time < max_wait_time:
183183
# Collect all providers across all pages
184184
while True:
@@ -203,9 +203,9 @@ def wait_for_all_providers_created(staff_headers: dict, expected_count: int, max
203203
providers = response_data.get('providers', [])
204204
pagination = response_data.get('pagination', {})
205205

206-
# Collect provider IDs from this page
206+
# Collect provider IDs from this page and add to set
207207
page_provider_ids = [p['providerId'] for p in providers]
208-
all_provider_ids.extend(page_provider_ids)
208+
all_provider_ids.update(page_provider_ids)
209209

210210
logger.info(
211211
f'Page {page_num}: Found {len(page_provider_ids)} providers '
@@ -227,7 +227,7 @@ def wait_for_all_providers_created(staff_headers: dict, expected_count: int, max
227227

228228
if num_found >= expected_count:
229229
logger.info(f'All {expected_count} providers found!')
230-
return all_provider_ids # Return only the expected count
230+
return list(all_provider_ids) # Return only the expected count
231231

232232
elapsed = time.time() - start_time
233233
if elapsed < max_wait_time:
@@ -325,7 +325,6 @@ def get_rollback_results_from_s3(results_s3_key: str):
325325
Retrieve rollback results from S3.
326326
327327
:param results_s3_key: S3 URI or key to the results file
328-
:param bucket_name: S3 bucket name
329328
:return: Parsed results data
330329
"""
331330
s3_client = boto3.client('s3')
@@ -632,7 +631,6 @@ def rollback_license_upload_smoke_test():
632631
street_address='123 Test Street',
633632
)
634633
first_upload_end_time = datetime.now(tz=UTC)
635-
636634
logger.info(
637635
f'First upload time window: {first_upload_start_time.isoformat()} to {first_upload_end_time.isoformat()}'
638636
)
@@ -641,6 +639,7 @@ def rollback_license_upload_smoke_test():
641639
logger.info('=' * 80)
642640
logger.info('Waiting for first upload providers and license records to be created...')
643641
logger.info('=' * 80)
642+
time.sleep(10)
644643
wait_for_all_providers_created(staff_headers, len(uploaded_licenses))
645644
logger.info('✅ All first upload license records have been created')
646645

0 commit comments

Comments
 (0)