diff --git a/scripts/get_s3_permissions.py b/scripts/get_s3_permissions.py index 626ded1d6..bbd08a66b 100644 --- a/scripts/get_s3_permissions.py +++ b/scripts/get_s3_permissions.py @@ -49,6 +49,44 @@ def add_test_files(folder, file_name, local_path): json.dump(PointerTypes.list(), f) +def _write_permission_file(folder_path, ods_code, pointer_types): + folder_path.mkdir(parents=True, exist_ok=True) + with open(folder_path / f"{ods_code}.json", "w") as f: + json.dump({"types": pointer_types}, f) + + +def add_feature_test_files(local_path): + """Bake in v2 permissions for the feature test application so that the + v2 permissions model can be proven via feature tests without + requiring a dynamic layer rebuild between test setup and test execution. + """ + + print("Adding feature test v2 permissions to temporary directory...") + permissions = { + "consumer": [ + ( + "z00z-y11y-x22x", + "RX898", + [PointerTypes.MENTAL_HEALTH_PLAN.value], + ), # http://snomed.info/sct|736253002 + ], + "producer": [ + ( + "z00z-y11y-x22x", + "RX898", + [PointerTypes.EOL_CARE_PLAN.value], + ), # http://snomed.info/sct|736373009 + ], + } + [ + _write_permission_file( + Path.joinpath(local_path, actor_type, app_id), ods_code, pointer_types + ) + for actor_type, entries in permissions.items() + for app_id, ods_code, pointer_types in entries + ] + + def download_files(s3_client, bucket_name, local_path, file_names, folders): print(f"Downloading {len(file_names)} S3 files to temporary directory...") local_path = Path(local_path) @@ -65,6 +103,7 @@ def download_files(s3_client, bucket_name, local_path, file_names, folders): s3_client.download_file(bucket_name, file_name, str(file_path)) add_test_files("K6PerformanceTest", "Y05868.json", local_path) + add_feature_test_files(local_path) def main(use_shared_resources: str, env: str, workspace: str, path_to_store: str): diff --git a/terraform/account-wide-infrastructure/modules/permissions-store-bucket/s3.tf b/terraform/account-wide-infrastructure/modules/permissions-store-bucket/s3.tf index ab7fe77aa..2c7f43d1e 100644 --- a/terraform/account-wide-infrastructure/modules/permissions-store-bucket/s3.tf +++ b/terraform/account-wide-infrastructure/modules/permissions-store-bucket/s3.tf @@ -60,3 +60,13 @@ resource "aws_s3_bucket_versioning" "authorization-store" { status = "Enabled" } } +# Need to pull these into state if they already exist +resource "aws_s3_object" "consumer-object" { + bucket = aws_s3_bucket.authorization-store.id + key = "consumer/" +} + +resource "aws_s3_object" "producer-object" { + bucket = aws_s3_bucket.authorization-store.id + key = "producer/" +} diff --git a/tests/features/consumer/readDocumentReference-failure.feature b/tests/features/consumer/readDocumentReference-failure.feature index f6ef1e0f4..dd37af613 100644 --- a/tests/features/consumer/readDocumentReference-failure.feature +++ b/tests/features/consumer/readDocumentReference-failure.feature @@ -6,7 +6,7 @@ Feature: Consumer - readDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' reads a DocumentReference with ID 'X26-000000000-000000000' + When consumer v1 'RX898' reads a DocumentReference with ID 'X26-000000000-000000000' Then the response status code is 404 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: @@ -33,7 +33,7 @@ Feature: Consumer - readDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' reads a DocumentReference with ID 'X26`DROP TABLE 'pointers';--Something-000000000-000000000' + When consumer v1 'RX898' reads a DocumentReference with ID 'X26`DROP TABLE 'pointers';--Something-000000000-000000000' Then the response status code is 404 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: @@ -58,7 +58,7 @@ Feature: Consumer - readDocumentReference - Failure Scenarios Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API And the organisation 'RX898' is authorised to access pointer types: | system | value | - When consumer 'RX898' reads a DocumentReference with ID 'X26-000000000-000000000' + When consumer v1 'RX898' reads a DocumentReference with ID 'X26-000000000-000000000' Then the response status code is 403 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: @@ -95,7 +95,7 @@ Feature: Consumer - readDocumentReference - Failure Scenarios | url | https://example.org/my-doc.pdf | | custodian | 02V | | author | 02V | - When consumer 'RX898' reads a DocumentReference with ID '02V-1111111111-ReadDocRefNoAuthForType' + When consumer v1 'RX898' reads a DocumentReference with ID '02V-1111111111-ReadDocRefNoAuthForType' Then the response status code is 403 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: @@ -120,7 +120,7 @@ Feature: Consumer - readDocumentReference - Failure Scenarios Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API And the organisation 'RX898' is authorised to access pointer types: | system | value | - When consumer 'RX898' reads a DocumentReference with ID 'X26-000000000-000000000' + When consumer v1 'RX898' reads a DocumentReference with ID 'X26-000000000-000000000' Then the response status code is 403 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: @@ -157,7 +157,7 @@ Feature: Consumer - readDocumentReference - Failure Scenarios | url | https://example.org/my-doc.pdf | | custodian | 02V | | author | 02V | - When consumer 'RX898' reads a DocumentReference with ID '02V-1111111111-ReadDocRefNoAuthForTypeS3' + When consumer v1 'RX898' reads a DocumentReference with ID '02V-1111111111-ReadDocRefNoAuthForTypeS3' Then the response status code is 403 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: diff --git a/tests/features/consumer/readDocumentReference-success.feature b/tests/features/consumer/readDocumentReference-success.feature index 9a3c81d55..5de6b44cd 100644 --- a/tests/features/consumer/readDocumentReference-success.feature +++ b/tests/features/consumer/readDocumentReference-success.feature @@ -16,7 +16,7 @@ Feature: Consumer - readDocumentReference - Success Scenarios | url | https://example.org/my-doc.pdf | | custodian | RX898 | | author | RX898 | - When consumer 'RX898' reads a DocumentReference with ID 'RX898-9999999999-ReadDocRefSameCustodian' + When consumer v1 'RX898' reads a DocumentReference with ID 'RX898-9999999999-ReadDocRefSameCustodian' Then the response status code is 200 And the response is a DocumentReference with JSON value: """ @@ -133,7 +133,7 @@ Feature: Consumer - readDocumentReference - Success Scenarios | url | https://example.org/my-doc.pdf | | custodian | X26 | | author | RX898 | - When consumer 'RX898' reads a DocumentReference with ID 'X26-9999999999-ReadDocRefDiffCustodian' + When consumer v1 'RX898' reads a DocumentReference with ID 'X26-9999999999-ReadDocRefDiffCustodian' Then the response status code is 200 And the response is a DocumentReference with JSON value: """ @@ -250,5 +250,5 @@ Feature: Consumer - readDocumentReference - Success Scenarios | url | https://example.org/my-doc.pdf | | custodian | RX898\|001 | | author | RX898 | - When consumer 'RX898' reads a DocumentReference with ID 'RX898%7C001-1234567890-ReadDocRefUrlEncoded' + When consumer v1 'RX898' reads a DocumentReference with ID 'RX898%7C001-1234567890-ReadDocRefUrlEncoded' Then the response status code is 200 diff --git a/tests/features/consumer/searchDocumentReference-failure.feature b/tests/features/consumer/searchDocumentReference-failure.feature index 6113b714c..48d0e7882 100644 --- a/tests/features/consumer/searchDocumentReference-failure.feature +++ b/tests/features/consumer/searchDocumentReference-failure.feature @@ -5,7 +5,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | extra | parameter | @@ -33,7 +33,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | Then the response status code is 400 And the response is an OperationOutcome with 1 issue @@ -59,7 +59,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | type | http://incorrect.info/sct\|736253002 | @@ -87,7 +87,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | type | http://snomed.info/sct\|887701000000100 | @@ -115,7 +115,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 123 | Then the response status code is 400 @@ -141,7 +141,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API And the organisation 'RX898' is authorised to access pointer types: | system | value | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | Then the response status code is 403 @@ -166,7 +166,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API And the organisation 'RX898' is authorised to access pointer types: | system | value | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | category | http://snomed.info/sct\|734163000 | @@ -204,7 +204,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios | url | https://example.org/my-doc.pdf | | custodian | 8FW23 | | author | 8FW23 | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | category | http://snomed.info/sct\|1102421000000108 | @@ -227,7 +227,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios | url | https://example.org/my-doc.pdf | | custodian | 8FW23 | | author | 8FW23 | - When consumer 'Z26' searches for DocumentReferences with parameters: + When consumer v1 'Z26' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | type | 736253002 | @@ -254,7 +254,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | category | http://incorrect.info/sct\|736253002 | @@ -282,7 +282,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | category | http://snomed.info/sct\|734163000,http://snomed.info/sct\|invalid | diff --git a/tests/features/consumer/searchDocumentReference-success.feature b/tests/features/consumer/searchDocumentReference-success.feature index a35fa3273..b3d9c4f7b 100644 --- a/tests/features/consumer/searchDocumentReference-success.feature +++ b/tests/features/consumer/searchDocumentReference-success.feature @@ -16,7 +16,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc.pdf | | custodian | 02V | | author | 02V | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | Then the response status code is 200 @@ -53,7 +53,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | custodian | 02V | | author | 02V | | identifier | 02V.123456789 | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | Then the response status code is 200 @@ -90,7 +90,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc.pdf | | custodian | 02V | | author | 02V | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | custodian | 02V | @@ -138,7 +138,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc.pdf | | custodian | DK94 | | author | DK94 | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | custodian | 02V | @@ -186,7 +186,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc.pdf | | custodian | 02V | | author | 02V | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | custodian | 02V | @@ -245,7 +245,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc-3.pdf | | custodian | 02V | | author | 02V | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | Then the response status code is 200 @@ -298,8 +298,8 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc.pdf | | custodian | DK94 | | author | N64 | - When producer 'DK94' requests to delete DocumentReference with id 'DK94-111-DeleteDocRefTest1' - And consumer 'RX898' searches for DocumentReferences with parameters: + When producer v1 'DK94' requests to delete DocumentReference with id 'DK94-111-DeleteDocRefTest1' + And consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | custodian | RX898 | @@ -348,7 +348,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc-3.pdf | | custodian | 02V | | author | 02V | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | category | http://snomed.info/sct\|734163000 | @@ -409,7 +409,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc-3.pdf | | custodian | 02V | | author | 02V | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | category | http://snomed.info/sct\|1102421000000108 | @@ -450,7 +450,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc-3.pdf | | custodian | 02V | | author | 02V | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | _summary | count | @@ -510,7 +510,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc-4.pdf | | custodian | 02V | | author | 02V | - When consumer 'RX898' searches for DocumentReferences with parameters: + When consumer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | | category | http://snomed.info/sct\|734163000,http://snomed.info/sct\|823651000000106 | diff --git a/tests/features/consumer/searchPostDocumentReference-failure.feature b/tests/features/consumer/searchPostDocumentReference-failure.feature index 2aa60a5b1..53fd41d39 100644 --- a/tests/features/consumer/searchPostDocumentReference-failure.feature +++ b/tests/features/consumer/searchPostDocumentReference-failure.feature @@ -5,7 +5,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | | extra | parameter | @@ -33,7 +33,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | Then the response status code is 400 And the response is an OperationOutcome with 1 issue @@ -59,7 +59,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | | type | http://incorrect.info/sct\|736253002 | @@ -87,7 +87,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | | type | http://snomed.info/sct\|887701000000100 | @@ -115,7 +115,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 123 | Then the response status code is 400 @@ -141,7 +141,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API And the organisation 'RX898' is authorised to access pointer types: | system | value | - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | Then the response status code is 403 @@ -175,7 +175,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios | url | https://example.org/my-doc.pdf | | custodian | 8FW23 | | author | 8FW23 | - When consumer 'X26' searches for DocumentReferences using POST with request body: + When consumer v1 'X26' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | | type | 736253002 | @@ -199,7 +199,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios Scenario: Search rejects request if the organisation has no registered pointer types Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | Then the response status code is 403 @@ -225,7 +225,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | | category | http://incorrect.info/sct\|736253002 | @@ -253,7 +253,7 @@ Feature: Consumer - searchDocumentReference - Failure Scenarios And the organisation 'RX898' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | | category | http://snomed.info/sct\|734163000,http://snomed.info/sct\|invalid | diff --git a/tests/features/consumer/searchPostDocumentReference-success.feature b/tests/features/consumer/searchPostDocumentReference-success.feature index c8fcecaa5..af09f03d6 100644 --- a/tests/features/consumer/searchPostDocumentReference-success.feature +++ b/tests/features/consumer/searchPostDocumentReference-success.feature @@ -16,7 +16,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc.pdf | | custodian | 8FW23 | | author | 8FW23 | - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | Then the response status code is 200 @@ -52,7 +52,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc.pdf | | custodian | RX898 | | author | RX898 | - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | | custodian | RX898 | @@ -111,7 +111,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc-3.pdf | | custodian | X26 | | author | X26 | - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | Then the response status code is 200 @@ -180,7 +180,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc-3.pdf | | custodian | X26 | | author | X26 | - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | Then the response status code is 200 @@ -232,8 +232,8 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc.pdf | | custodian | DK94 | | author | N64 | - When producer 'DK94' requests to delete DocumentReference with id 'DK94-111-DeleteDocRefTest1' - And consumer 'RX898' searches for DocumentReferences using POST with request body: + When producer v1 'DK94' requests to delete DocumentReference with id 'DK94-111-DeleteDocRefTest1' + And consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | | custodian | RX898 | @@ -282,7 +282,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc-3.pdf | | custodian | x26 | | author | x26 | - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | | category | http://snomed.info/sct\|734163000 | @@ -353,7 +353,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc-3.pdf | | custodian | x26 | | author | x26 | - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | | _summary | count | @@ -412,7 +412,7 @@ Feature: Consumer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc-4.pdf | | custodian | X26 | | author | X26 | - When consumer 'RX898' searches for DocumentReferences using POST with request body: + When consumer v1 'RX898' searches for DocumentReferences using POST with request body: | key | value | | subject | 9278693472 | | category | http://snomed.info/sct\|734163000,http://snomed.info/sct\|823651000000106 | diff --git a/tests/features/consumer/status-success.feature b/tests/features/consumer/status-success.feature deleted file mode 100644 index c4f2cc781..000000000 --- a/tests/features/consumer/status-success.feature +++ /dev/null @@ -1 +0,0 @@ -# Status returns 200 diff --git a/tests/features/consumer/v2-permissions-by-pointer-type.feature b/tests/features/consumer/v2-permissions-by-pointer-type.feature new file mode 100644 index 000000000..7c5fe6bbd --- /dev/null +++ b/tests/features/consumer/v2-permissions-by-pointer-type.feature @@ -0,0 +1,212 @@ +Feature: Consumer v2 permissions by pointer type - Success and Failure Scenarios + For the v2 permissions model, permissions are resolved from a JSON file stored in the + nrlf_permissions Lambda layer. Permissions for the feature tests are baked into the layer + by `scripts/get_s3_permissions.py` at build time, so no dynamic seeding step is required for + success scenarios. + + Background: + Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API + + Scenario: V2 Permissions with access for pointer type - readDocumentReference + Given a DocumentReference resource exists with values: + | property | value | + | id | RX898-9999999999-ReadDocRefV2SameCustodian | + | subject | 9999999999 | + | status | current | + | type | 736253002 | + | category | 734163000 | + | contentType | application/pdf | + | url | https://example.org/my-doc.pdf | + | custodian | RX898 | + | author | RX898 | + When consumer v2 'RX898' reads a DocumentReference with ID 'RX898-9999999999-ReadDocRefV2SameCustodian' + Then the response status code is 200 + And the response is a DocumentReference with JSON value: + """ + { + "resourceType": "DocumentReference", + "id": "RX898-9999999999-ReadDocRefV2SameCustodian", + "status": "current", + "type": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "736253002", + "display": "Mental health crisis plan" + } + ] + }, + "category": [ + { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "734163000", + "display": "Care plan" + } + ] + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "9999999999" + } + }, + "custodian": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "RX898" + } + }, + "author": [ + { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "RX898" + } + } + ], + "content": [ + { + "attachment": { + "contentType": "application/pdf", + "url": "https://example.org/my-doc.pdf" + }, + "format": { + "system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLFormatCode", + "code": "urn:nhs-ic:unstructured", + "display": "Unstructured Document" + }, + "extension": [ + { + "url": "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-ContentStability", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLContentStability", + "code": "static", + "display": "Static" + } + ] + } + }, + { + "url": "https://fhir.nhs.uk/England/StructureDefinition/Extension-England-NRLRetrievalMechanism", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/England/CodeSystem/England-NRLRetrievalMechanism", + "code": "Direct", + "display": "Direct" + } + ] + } + } + ] + } + ], + "context": { + "practiceSetting": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "788007007", + "display": "General practice service" + } + ] + } + } + } + """ + + Scenario: V2 permissions with access for pointer type retrieves expected document references - searchPostDocumentReference + Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API + And a DocumentReference resource exists with values: + | property | value | + | id | X26-1111111111-SearchMultipleRefTest1 | + | subject | 9278693472 | + | status | current | + | type | 736253002 | + | category | 734163000 | + | contentType | application/pdf | + | url | https://example.org/my-doc-1.pdf | + | custodian | X26 | + | author | X26 | + And a DocumentReference resource exists with values: + | property | value | + | id | X26-1111111111-SearchMultipleRefTest2 | + | subject | 9278693472 | + | status | current | + | type | 736253002 | + | category | 734163000 | + | contentType | application/pdf | + | url | https://example.org/my-doc-2.pdf | + | custodian | X26 | + | author | X26 | + And a DocumentReference resource exists with values: + | property | value | + | id | X26-1111111111-SearchMultipleRefTestDifferentType | + | subject | 9278693472 | + | status | current | + | type | 887701000000100 | + | category | 734163000 | + | contentType | application/pdf | + | url | https://example.org/my-doc-3.pdf | + | custodian | X26 | + | author | X26 | + When consumer v2 'RX898' searches for DocumentReferences using POST with request body: + | key | value | + | subject | 9278693472 | + Then the response status code is 200 + And the response is a searchset Bundle + And the Bundle has a total of 2 + And the Bundle has 2 entries + And the Bundle contains an DocumentReference with values + | property | value | + | id | X26-1111111111-SearchMultipleRefTest1 | + | subject | 9278693472 | + | status | current | + | type | 736253002 | + | category | 734163000 | + | contentType | application/pdf | + | url | https://example.org/my-doc-1.pdf | + | custodian | X26 | + | author | X26 | + And the Bundle contains an DocumentReference with values + | property | value | + | id | X26-1111111111-SearchMultipleRefTest2 | + | subject | 9278693472 | + | status | current | + | type | 736253002 | + | category | 734163000 | + | contentType | application/pdf | + | url | https://example.org/my-doc-2.pdf | + | custodian | X26 | + | author | X26 | + And the Bundle does not contain a DocumentReference with ID 'X26-1111111111-SearchMultipleRefTestDifferentType' + + Scenario: V2 permissions with no access for pointer type - searchDocumentReference + Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API + When consumer v2 'RX898' searches for DocumentReferences with parameters: + | parameter | value | + | subject | 9278693472 | + | type | http://snomed.info/sct\|887701000000100 | + Then the response status code is 400 + And the response is an OperationOutcome with 1 issue + And the OperationOutcome contains the issue: + """ + { + "severity": "error", + "code": "code-invalid", + "details": { + "coding": [{ + "system": "https://fhir.nhs.uk/CodeSystem/Spine-ErrorOrWarningCode", + "code": "INVALID_CODE_SYSTEM", + "display": "Invalid code system" + }] + }, + "diagnostics": "Invalid query parameter (The provided type does not match the allowed types for this organisation)", + "expression": ["type"] + } + """ diff --git a/tests/features/producer/createDocumentReference-failure.feature b/tests/features/producer/createDocumentReference-failure.feature index ff1d2bfda..905bea341 100644 --- a/tests/features/producer/createDocumentReference-failure.feature +++ b/tests/features/producer/createDocumentReference-failure.feature @@ -16,7 +16,7 @@ Feature: Producer - createDocumentReference - Failure Scenarios And the organisation 'ANGY1' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When producer 'ANGY1' creates a DocumentReference with values: + When producer v1 'ANGY1' creates a DocumentReference with values: | property | value | | subject | 9999999999 | | status | current | @@ -53,7 +53,7 @@ Feature: Producer - createDocumentReference - Failure Scenarios And the organisation 'ANGY1' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When producer 'ANGY1' creates a DocumentReference with values: + When producer v1 'ANGY1' creates a DocumentReference with values: | property | value | | subject | 1234567890 | | status | current | @@ -212,7 +212,7 @@ Feature: Producer - createDocumentReference - Failure Scenarios | url | https://example.org/my-doc.pdf | | custodian | N0TANGY | | author | HAR1 | - When producer 'ANGY1' creates a DocumentReference with values: + When producer v1 'ANGY1' creates a DocumentReference with values: | property | value | | subject | 9278693472 | | status | current | @@ -263,7 +263,7 @@ Feature: Producer - createDocumentReference - Failure Scenarios Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API And the organisation 'ANGY1' is authorised to access pointer types: | system | value | - When producer 'ANGY1' creates a DocumentReference with values: + When producer v1 'ANGY1' creates a DocumentReference with values: | property | value | | subject | 9999999999 | | status | current | @@ -298,7 +298,7 @@ Feature: Producer - createDocumentReference - Failure Scenarios | system | value | | http://snomed.info/sct | 1363501000000100 | | http://snomed.info/sct | 736253002 | - When producer 'X26' creates a DocumentReference with values: + When producer v1 'X26' creates a DocumentReference with values: | property | value | | subject | 9999999999 | | type | 736253002 | @@ -335,7 +335,7 @@ Feature: Producer - createDocumentReference - Failure Scenarios And the organisation 'ANGY1' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When producer 'ANGY1' creates a DocumentReference with values: + When producer v1 'ANGY1' creates a DocumentReference with values: | property | value | | subject | 9999999999 | | status | current | @@ -373,7 +373,7 @@ Feature: Producer - createDocumentReference - Failure Scenarios | system | value | | http://snomed.info/sct | 1363501000000100 | | http://snomed.info/sct | 736253002 | - When producer 'X26' creates a DocumentReference with values: + When producer v1 'X26' creates a DocumentReference with values: | property | value | | subject | 9999999999 | | status | current | @@ -544,7 +544,7 @@ Feature: Producer - createDocumentReference - Failure Scenarios And the organisation 'ANGY1' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When producer 'ANGY1' creates a DocumentReference with values: + When producer v1 'ANGY1' creates a DocumentReference with values: | property | value | | subject | 9278693472 | | status | current | @@ -581,7 +581,7 @@ Feature: Producer - createDocumentReference - Failure Scenarios And the organisation 'ANGY1' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When producer 'ANGY1' creates a DocumentReference with values: + When producer v1 'ANGY1' creates a DocumentReference with values: | property | value | | subject | 9999999999 | | status | current | @@ -620,7 +620,7 @@ Feature: Producer - createDocumentReference - Failure Scenarios | system | value | | https://nicip.nhs.uk | MAULR | | https://nicip.nhs.uk | MAXIB | - When producer 'ANGY1' creates a DocumentReference with values: + When producer v1 'ANGY1' creates a DocumentReference with values: | property | value | | subject | 9999999999 | | status | current | @@ -665,7 +665,7 @@ Feature: Producer - createDocumentReference - Failure Scenarios | system | value | | http://snomed.info/sct | 1363501000000100 | | http://snomed.info/sct | 736253002 | - When producer 'X26' creates a DocumentReference with values: + When producer v1 'X26' creates a DocumentReference with values: | property | value | | subject | 9999999999 | | status | current | @@ -814,7 +814,7 @@ Feature: Producer - createDocumentReference - Failure Scenarios And the organisation 'ANGY1' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When producer 'ANGY1' creates a DocumentReference with values: + When producer v1 'ANGY1' creates a DocumentReference with values: | property | value | | subject | 9999999999 | | status | current | diff --git a/tests/features/producer/createDocumentReference-success.feature b/tests/features/producer/createDocumentReference-success.feature index e7ea87d8c..03f4f65c7 100644 --- a/tests/features/producer/createDocumentReference-success.feature +++ b/tests/features/producer/createDocumentReference-success.feature @@ -5,7 +5,7 @@ Feature: Producer - createDocumentReference - Success Scenarios And the organisation 'ANGY1' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When producer 'ANGY1' creates a DocumentReference with values: + When producer v1 'ANGY1' creates a DocumentReference with values: | property | value | | subject | 9278693472 | | status | current | @@ -110,7 +110,7 @@ Feature: Producer - createDocumentReference - Success Scenarios | custodian | ANGY1 | | author | HAR1 | | practiceSetting | 788002001 | - When producer 'ANGY1' creates a DocumentReference with values: + When producer v1 'ANGY1' creates a DocumentReference with values: | property | value | | subject | 9278693472 | | status | current | @@ -161,7 +161,7 @@ Feature: Producer - createDocumentReference - Success Scenarios And the organisation 'ANGY1' is authorised to access pointer types: | system | value | | http://snomed.info/sct | | - When producer 'ANGY1' creates a DocumentReference with values: + When producer v1 'ANGY1' creates a DocumentReference with values: | property | value | | subject | 9278693472 | | status | current | @@ -239,7 +239,7 @@ Feature: Producer - createDocumentReference - Success Scenarios | system | value | | https://nicip.nhs.uk | MAULR | | https://nicip.nhs.uk | MAXIB | - When producer 'ANGY1' creates a DocumentReference with values: + When producer v1 'ANGY1' creates a DocumentReference with values: | property | value | | subject | 9278693472 | | status | current | @@ -282,7 +282,7 @@ Feature: Producer - createDocumentReference - Success Scenarios | author | HAR1 | | url | https://example.org/my-doc.pdf | | practiceSetting | 788002001 | - When producer 'ANGY1' creates a DocumentReference with values: + When producer v1 'ANGY1' creates a DocumentReference with values: | property | value | | subject | 9278693472 | | status | current | @@ -330,7 +330,7 @@ Feature: Producer - createDocumentReference - Success Scenarios And the organisation 'BARS1' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 749001000000101 | - When producer 'BARS1' creates a DocumentReference with values: + When producer v1 'BARS1' creates a DocumentReference with values: | property | value | | subject | 9278693472 | | status | current | diff --git a/tests/features/producer/deleteDocumentReference-failure.feature b/tests/features/producer/deleteDocumentReference-failure.feature index 52fb6c3fc..105398075 100644 --- a/tests/features/producer/deleteDocumentReference-failure.feature +++ b/tests/features/producer/deleteDocumentReference-failure.feature @@ -19,7 +19,7 @@ Feature: Producer - deleteDocumentReference - Failure Scenarios | url | https://example.org/my-doc.pdf | | custodian | OC84 | | author | N64 | - When producer 'DK94' requests to delete DocumentReference with id 'OC84-111-DeleteTest-NotYourPointer' + When producer v1 'DK94' requests to delete DocumentReference with id 'OC84-111-DeleteTest-NotYourPointer' Then the response status code is 403 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: diff --git a/tests/features/producer/deleteDocumentReference-success.feature b/tests/features/producer/deleteDocumentReference-success.feature index 440de277b..f1543a8e5 100644 --- a/tests/features/producer/deleteDocumentReference-success.feature +++ b/tests/features/producer/deleteDocumentReference-success.feature @@ -18,7 +18,7 @@ Feature: Producer - deleteDocumentReference - Success Scenarios | url | https://example.org/my-doc.pdf | | custodian | DK94 | | author | N64 | - When producer 'DK94' requests to delete DocumentReference with id 'DK94-111-DeleteDocRefTest1' + When producer v1 'DK94' requests to delete DocumentReference with id 'DK94-111-DeleteDocRefTest1' Then the response status code is 200 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: @@ -47,7 +47,7 @@ Feature: Producer - deleteDocumentReference - Success Scenarios And the organisation 'DK94' is authorised to access pointer types: | system | value | | http://snomed.info/sct | 736253002 | - When producer 'DK94' requests to delete DocumentReference with id 'DK94-000-NoPointerHere' + When producer v1 'DK94' requests to delete DocumentReference with id 'DK94-000-NoPointerHere' Then the response status code is 200 And the response is an OperationOutcome with 1 issue And the OperationOutcome contains the issue: diff --git a/tests/features/producer/searchDocumentReference-failure.feature b/tests/features/producer/searchDocumentReference-failure.feature deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/features/producer/searchDocumentReference-success.feature b/tests/features/producer/searchDocumentReference-success.feature index 2fe5e31df..c8823bce5 100644 --- a/tests/features/producer/searchDocumentReference-success.feature +++ b/tests/features/producer/searchDocumentReference-success.feature @@ -27,7 +27,7 @@ Feature: Producer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc.pdf | | custodian | RX898 | | author | X26 | - When producer 'RX898' searches for DocumentReferences with parameters: + When producer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | subject | 9278693472 | Then the response status code is 200 @@ -86,7 +86,7 @@ Feature: Producer - searchDocumentReference - Success Scenarios | url | https://example.org/my-doc.pdf | | custodian | RX898 | | author | X26 | - When producer 'RX898' searches for DocumentReferences with parameters: + When producer v1 'RX898' searches for DocumentReferences with parameters: | parameter | value | | pointer_type | 736253002 | | subject | 9999999999 | diff --git a/tests/features/producer/searchPostDocumentReference-failure.feature b/tests/features/producer/searchPostDocumentReference-failure.feature deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/features/producer/searchPostDocumentReference-success.feature b/tests/features/producer/searchPostDocumentReference-success.feature deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/features/producer/v2-permissions-by-pointer-type.feature b/tests/features/producer/v2-permissions-by-pointer-type.feature new file mode 100644 index 000000000..673be9d48 --- /dev/null +++ b/tests/features/producer/v2-permissions-by-pointer-type.feature @@ -0,0 +1,197 @@ +Feature: Producer v2 permissions by pointer type - Success and Failure Scenarios + For the v2 permissions model, permissions are resolved from a JSON file stored in the + nrlf_permissions Lambda layer. Permissions for the feature tests are baked into the layer by + `scripts/get_s3_permissions.py` at build time, so no dynamic seeding step is required for + success scenarios. + + Background: + Given the application 'DataShare' (ID 'z00z-y11y-x22x') is registered to access the API + + Scenario: V2 Permissions with access for pointer type - createDocumentReference + When producer v2 'RX898' creates a DocumentReference with values: + | property | value | + | subject | 9278693472 | + | status | current | + | type | 736373009 | + | category | 734163000 | + | custodian | RX898 | + | author | HAR1 | + | url | https://example.org/my-doc.pdf | + | practiceSetting | 788002001 | + Then the response status code is 201 + And the response is an OperationOutcome with 1 issue + And the OperationOutcome contains the issue: + """ + { + "severity": "information", + "code": "informational", + "details": { + "coding": [ + { + "system": "https://fhir.nhs.uk/ValueSet/NRL-ResponseCode", + "code": "RESOURCE_CREATED", + "display": "Resource created" + } + ] + }, + "diagnostics": "The document has been created" + } + """ + And the response has a Location header + And the Location header starts with '/DocumentReference/RX898-' + And the resource in the Location header exists with values: + | property | value | + | subject | 9278693472 | + | status | current | + | type | 736373009 | + | category | 734163000 | + | custodian | RX898 | + | author | HAR1 | + | url | https://example.org/my-doc.pdf | + | practiceSetting | 788002001 | + + Scenario: V2 Permissions with no access for pointer type - createDocumentReference + When producer v2 'RX898' creates a DocumentReference with values: + | property | value | + | subject | 9278693472 | + | status | current | + | type | 736253002 | + | category | 734163000 | + | custodian | RX898 | + | author | HAR1 | + | url | https://example.org/my-doc.pdf | + | practiceSetting | 788002001 | + Then the response status code is 403 + And the response is an OperationOutcome with 1 issue + And the OperationOutcome contains the issue: + """ + { + "severity": "error", + "code": "forbidden", + "details": { + "coding": [ + { + "system": "https://fhir.nhs.uk/CodeSystem/Spine-ErrorOrWarningCode", + "code": "AUTHOR_CREDENTIALS_ERROR", + "display": "Author credentials error" + } + ] + }, + "diagnostics": "The type of the provided DocumentReference is not in the list of allowed types for this organisation", + "expression": [ + "type.coding[0].code" + ] + } + """ + + Scenario: V2 Permissions with access for pointer type - deleteDocumentReference + Given a DocumentReference resource exists with values + | property | value | + | id | RX898-111-DeleteDocRefTest1 | + | subject | 9278693472 | + | status | current | + | type | 736373009 | + | category | 734163000 | + | contentType | application/pdf | + | url | https://example.org/my-doc.pdf | + | custodian | RX898 | + | author | RX898 | + When producer v2 'RX898' requests to delete DocumentReference with id 'RX898-111-DeleteDocRefTest1' + Then the response status code is 200 + And the response is an OperationOutcome with 1 issue + And the OperationOutcome contains the issue: + """ + { + "severity": "information", + "code": "informational", + "details": { + "coding": [ + { + "system": "https://fhir.nhs.uk/ValueSet/NRL-ResponseCode", + "code": "RESOURCE_DELETED", + "display": "Resource deleted" + } + ] + }, + "diagnostics": "The requested DocumentReference has been deleted" + } + """ + And the resource with id 'RX898-111-DeleteDocRefTest1' does not exist + + Scenario: V2 Permissions with no access for pointer type - searchDocumentReference + Given a DocumentReference resource exists with values: + | property | value | + | id | RX898-1111111111-SearchNHSDocRefTest1 | + | subject | 9999999999 | + | status | current | + | type | 736373009 | + | category | 734163000 | + | contentType | application/pdf | + | url | https://example.org/my-doc.pdf | + | custodian | RX898 | + | author | X26 | + And a DocumentReference resource exists with values: + | property | value | + | id | SG4-1111111111-SearchNHSDocRefTest3 | + | subject | 9999999999 | + | status | current | + | type | 1363501000000100 | + | category | 734163000 | + | contentType | application/pdf | + | url | https://example.org/my-doc.pdf | + | custodian | SG4 | + | author | X26 | + When producer v2 'RX898' searches for DocumentReferences with parameters: + | parameter | value | + | subject | 9999999999 | + Then the response status code is 200 + And the response is a searchset Bundle + And the Bundle has a total of 1 + And the Bundle has 1 entry + And the Bundle contains an DocumentReference with values + | property | value | + | id | RX898-1111111111-SearchNHSDocRefTest1 | + | subject | 9999999999 | + | status | current | + | type | 736373009 | + | category | 734163000 | + | contentType | application/pdf | + | url | https://example.org/my-doc.pdf | + | custodian | RX898 | + | author | X26 | + And the Bundle does not contain a DocumentReference with ID 'SG4-1111111111-SearchNHSDocRefTest3' + + Scenario: V2 Permissions with no access for org - searchDocumentReference + Given a DocumentReference resource exists with values: + | property | value | + | id | RX898-1111111111-SearchNHSDocRefTest1 | + | subject | 9999999999 | + | status | current | + | type | 736373009 | + | category | 734163000 | + | contentType | application/pdf | + | url | https://example.org/my-doc.pdf | + | custodian | RX898 | + | author | X26 | + When producer v2 'N00RG1' searches for DocumentReferences with parameters: + | parameter | value | + | subject | 9999999999 | + Then the response status code is 403 + And the response is an OperationOutcome with 1 issue + And the OperationOutcome contains the issue: + """ + { + "severity": "error", + "code": "forbidden", + "details": { + "coding": [ + { + "system": "https://fhir.nhs.uk/CodeSystem/Spine-ErrorOrWarningCode", + "code": "ACCESS DENIED", + "display": "Access has been denied to process this request" + } + ] + }, + "diagnostics": "Your organisation 'N00RG1' does not have permission to access this resource. Contact the onboarding team." + } + """ diff --git a/tests/features/steps/2_request.py b/tests/features/steps/2_request.py index 304228fec..733988d83 100644 --- a/tests/features/steps/2_request.py +++ b/tests/features/steps/2_request.py @@ -24,9 +24,11 @@ def consumer_count_document_references_step(context: Context, ods_code: str): context.response = client.count(items) -@when("consumer '{ods_code}' searches for DocumentReferences with parameters") -def consumer_search_document_reference_step(context: Context, ods_code: str): - client = consumer_client_from_context(context, ods_code) +@when("consumer {version} '{ods_code}' searches for DocumentReferences with parameters") +def consumer_search_document_reference_step( + context: Context, version: str, ods_code: str +): + client = consumer_client_from_context(context, ods_code, v2=(version == "v2")) if not context.table: raise ValueError("No search query table provided") @@ -46,10 +48,12 @@ def consumer_search_document_reference_step(context: Context, ods_code: str): @when( - "consumer '{ods_code}' searches for DocumentReferences using POST with request body" + "consumer {version} '{ods_code}' searches for DocumentReferences using POST with request body" ) -def consumer_search_post_document_reference_step(context: Context, ods_code: str): - client = consumer_client_from_context(context, ods_code) +def consumer_search_post_document_reference_step( + context: Context, version: str, ods_code: str +): + client = consumer_client_from_context(context, ods_code, v2=(version == "v2")) if not context.table: raise ValueError("No search query table provided") @@ -68,17 +72,19 @@ def consumer_search_post_document_reference_step(context: Context, ods_code: str ) -@when("consumer '{ods_code}' reads a DocumentReference with ID '{doc_ref_id}'") +@when( + "consumer {version} '{ods_code}' reads a DocumentReference with ID '{doc_ref_id}'" +) def consumer_read_document_reference_step( - context: Context, ods_code: str, doc_ref_id: str + context: Context, version: str, ods_code: str, doc_ref_id: str ): - client = consumer_client_from_context(context, ods_code) + client = consumer_client_from_context(context, ods_code, v2=(version == "v2")) context.response = client.read(doc_ref_id) -@when("producer '{ods_code}' creates a DocumentReference with values") -def create_post_document_reference_step(context: Context, ods_code: str): - client = producer_client_from_context(context, ods_code) +@when("producer {version} '{ods_code}' creates a DocumentReference with values") +def create_post_document_reference_step(context: Context, version: str, ods_code: str): + client = producer_client_from_context(context, ods_code, v2=(version == "v2")) if not context.table: raise ValueError("No document reference data table provided") @@ -215,10 +221,12 @@ def update_put_document_reference_step( @when( - "producer '{ods_code}' requests to delete DocumentReference with id '{doc_ref_id}'" + "producer {version} '{ods_code}' requests to delete DocumentReference with id '{doc_ref_id}'" ) -def delete_document_reference_step(context: Context, ods_code: str, doc_ref_id: str): - client = producer_client_from_context(context, ods_code) +def delete_document_reference_step( + context: Context, version: str, ods_code: str, doc_ref_id: str +): + client = producer_client_from_context(context, ods_code, v2=(version == "v2")) context.response = client.delete(doc_ref_id) @@ -230,9 +238,11 @@ def producer_read_document_reference_step( context.response = client.read(doc_ref_id) -@when("producer '{ods_code}' searches for DocumentReferences with parameters") -def producer_search_document_reference_step(context: Context, ods_code: str): - client = producer_client_from_context(context, ods_code) +@when("producer {version} '{ods_code}' searches for DocumentReferences with parameters") +def producer_search_document_reference_step( + context: Context, version: str, ods_code: str +): + client = producer_client_from_context(context, ods_code, v2=(version == "v2")) if not context.table: raise ValueError("No search query table provided") diff --git a/tests/features/utils/api_client.py b/tests/features/utils/api_client.py index 4c8f8a8cc..3b00c5938 100644 --- a/tests/features/utils/api_client.py +++ b/tests/features/utils/api_client.py @@ -33,11 +33,11 @@ def _config_from_context(context: Context, ods_code: str): ) -def consumer_client_from_context(context: Context, ods_code: str): +def consumer_client_from_context(context: Context, ods_code: str, v2: bool = False): client_config = _config_from_context(context, ods_code) - return ConsumerTestClient(config=client_config) + return ConsumerTestClient(config=client_config, use_v2=v2) -def producer_client_from_context(context: Context, ods_code: str): +def producer_client_from_context(context: Context, ods_code: str, v2: bool = False): client_config = _config_from_context(context, ods_code) - return ProducerTestClient(config=client_config) + return ProducerTestClient(config=client_config, use_v2=v2) diff --git a/tests/utilities/api_clients.py b/tests/utilities/api_clients.py index bb522cbe3..85cf41d36 100644 --- a/tests/utilities/api_clients.py +++ b/tests/utilities/api_clients.py @@ -68,7 +68,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: class ConsumerTestClient: - def __init__(self, config: ClientConfig): + def __init__(self, config: ClientConfig, use_v2: bool = False): self.config = config self.api_url = f"{self.config.base_url}consumer{self.config.api_path}" @@ -78,17 +78,26 @@ def __init__(self, config: ClientConfig): } if self.config.client_cert: - connection_metadata = self.config.connection_metadata.model_dump( - by_alias=True - ) - client_rp_details = connection_metadata.pop("client_rp_details") - self.request_headers.update( - { - "NHSD-Connection-Metadata": json.dumps(connection_metadata), - "NHSD-Client-RP-Details": json.dumps(client_rp_details), - "NHSD-Correlation-Id": "test-correlation-id", - } - ) + if use_v2: + self.request_headers.update( + { + "NHSD-End-User-Organisation-ODS": self.config.connection_metadata.ods_code, + "NHSD-NRL-App-Id": self.config.connection_metadata.nrl_app_id, + "NHSD-Correlation-Id": "test-correlation-id", + } + ) + else: + connection_metadata = self.config.connection_metadata.model_dump( + by_alias=True + ) + client_rp_details = connection_metadata.pop("client_rp_details") + self.request_headers.update( + { + "NHSD-Connection-Metadata": json.dumps(connection_metadata), + "NHSD-Client-RP-Details": json.dumps(client_rp_details), + "NHSD-Correlation-Id": "test-correlation-id", + } + ) self.request_headers.update(self.config.custom_headers) @@ -210,7 +219,7 @@ def read_capability_statement(self) -> Response: class ProducerTestClient: - def __init__(self, config: ClientConfig): + def __init__(self, config: ClientConfig, use_v2: bool = False): self.config = config self.api_url = f"{self.config.base_url}producer{self.config.api_path}" @@ -220,17 +229,26 @@ def __init__(self, config: ClientConfig): } if self.config.client_cert: - connection_metadata = self.config.connection_metadata.model_dump( - by_alias=True - ) - client_rp_details = connection_metadata.pop("client_rp_details") - self.request_headers.update( - { - "NHSD-Connection-Metadata": json.dumps(connection_metadata), - "NHSD-Client-RP-Details": json.dumps(client_rp_details), - "NHSD-Correlation-Id": "test-correlation-id", - } - ) + if use_v2: + self.request_headers.update( + { + "NHSD-End-User-Organisation-ODS": self.config.connection_metadata.ods_code, + "NHSD-NRL-App-Id": self.config.connection_metadata.nrl_app_id, + "NHSD-Correlation-Id": "test-correlation-id", + } + ) + else: + connection_metadata = self.config.connection_metadata.model_dump( + by_alias=True + ) + client_rp_details = connection_metadata.pop("client_rp_details") + self.request_headers.update( + { + "NHSD-Connection-Metadata": json.dumps(connection_metadata), + "NHSD-Client-RP-Details": json.dumps(client_rp_details), + "NHSD-Correlation-Id": "test-correlation-id", + } + ) self.request_headers.update(self.config.custom_headers)