From 8fb67621405443097a71c7095c8c18b58caa947d Mon Sep 17 00:00:00 2001 From: CDR-AndrewG <89497569+CDR-AndrewG@users.noreply.github.com> Date: Tue, 22 Aug 2023 11:12:36 +1000 Subject: [PATCH 1/3] Synchronise main and develop commit history (#72) From 8eac54229dd53de4f0d76608ad2f120ec68c5d1c Mon Sep 17 00:00:00 2001 From: CDR-AmirM <88067035+CDR-AmirM@users.noreply.github.com> Date: Tue, 28 Nov 2023 16:02:51 +1100 Subject: [PATCH 2/3] v1.2.5 release (#74) Co-authored-by: CDR Open Source Co-authored-by: CDR-EvanR <134671449+CDR-EvanR@users.noreply.github.com> Co-authored-by: CDR-FarooqK <110141673+CDR-FarooqK@users.noreply.github.com> --- .azuredevops/pipelines/build-no-tests.yml | 2 +- .azuredevops/pipelines/build-v2.yml | 124 +- .github/workflows/codeql-analysis.yml | 8 +- .github/workflows/docker.yml | 9 + .github/workflows/dotnet.yml | 26 +- .github/workflows/sonarcloud-analysis.yml | 13 +- CHANGELOG.md | 7 +- CODE_OF_CONDUCT.md | 6 +- Help/azurefunctions/HELP.md | 4 +- Help/container/HELP.md | 2 +- README.md | 46 +- SECURITY.md | 38 + Source/.dockerignore | 3 +- Source/CDR.DCR/CDR.DCR.csproj | 6 +- .../CDR.DataRecipient.API.Logger.csproj | 6 +- .../AATestPlaywrightInstallation.cs | 2 +- Source/CDR.DataRecipient.E2ETests/BaseTest.cs | 379 +++++- .../CDR.DataRecipient.E2ETests/BaseTest_v2.cs | 558 --------- .../CDR.DataRecipient.E2ETests/BaseTest_v3.cs | 789 ------------ .../CDR.DataRecipient.E2ETests.csproj | 6 +- .../Fixtures/TestFixture.cs | 2 +- .../Infrastructure/AccessToken.cs | 2 +- .../US23863_MDR_E2ETests.cs | 972 ++++++--------- .../US23863_MDR_E2ETests_v2.cs | 1064 ----------------- .../US23863_MDR_E2ETests_v3.cs | 994 --------------- .../US23863_MDR_E2ETests_v4.cs | 734 ------------ .../US46331_MDR_E2ETests_ParFapi.cs | 2 +- .../US46352_MDR_E2ETests_AuthCodeFlowJarm.cs | 2 +- .../CDR.DataRecipient.IntegrationTests.csproj | 7 +- .../US61217_MDR_UserInfo.cs | 57 + .../CDR.DataRecipient.Repository.SQL.csproj | 6 +- .../CDR.DataRecipient.SDK.csproj | 6 +- .../CDR.DataRecipient.SDK/Models/UserInfo.cs | 2 +- .../Services/BaseService.cs | 2 +- .../CDR.DataRecipient.Web.csproj | 6 +- .../CDR.DataRecipient.csproj | 6 +- .../CDR.DiscoverDataHolders.csproj | 6 +- .../DockerCompose/docker-compose.E2ETests.yml | 55 + .../docker-compose.IntegrationTests.yml | 53 + .../docker-compose.TestsBase.yml} | 42 +- .../docker-compose.UnitTests.yml | 4 +- Source/docker-compose.IntegrationTests.yml | 142 --- 42 files changed, 1026 insertions(+), 5174 deletions(-) create mode 100644 SECURITY.md delete mode 100644 Source/CDR.DataRecipient.E2ETests/BaseTest_v2.cs delete mode 100644 Source/CDR.DataRecipient.E2ETests/BaseTest_v3.cs delete mode 100644 Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests_v2.cs delete mode 100644 Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests_v3.cs delete mode 100644 Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests_v4.cs create mode 100644 Source/CDR.DataRecipient.IntegrationTests/US61217_MDR_UserInfo.cs create mode 100644 Source/DockerCompose/docker-compose.E2ETests.yml create mode 100644 Source/DockerCompose/docker-compose.IntegrationTests.yml rename Source/{docker-compose.E2ETests.yml => DockerCompose/docker-compose.TestsBase.yml} (57%) rename Source/{ => DockerCompose}/docker-compose.UnitTests.yml (97%) delete mode 100644 Source/docker-compose.IntegrationTests.yml diff --git a/.azuredevops/pipelines/build-no-tests.yml b/.azuredevops/pipelines/build-no-tests.yml index 7dc9ddc..0a5cf0d 100644 --- a/.azuredevops/pipelines/build-no-tests.yml +++ b/.azuredevops/pipelines/build-no-tests.yml @@ -66,7 +66,7 @@ steps: displayName: 'Install dotnet-ef' condition: always() inputs: - script: 'dotnet tool install --global dotnet-ef' + script: 'dotnet tool install --version 7.0.13 --global dotnet-ef' - task: CmdLine@2 displayName: 'Check dotnet-ef version' diff --git a/.azuredevops/pipelines/build-v2.yml b/.azuredevops/pipelines/build-v2.yml index e08653c..b129292 100644 --- a/.azuredevops/pipelines/build-v2.yml +++ b/.azuredevops/pipelines/build-v2.yml @@ -8,6 +8,7 @@ variables: containerTag: develop baseSourceDirectory: $(Build.SourcesDirectory)/Source + dockerComposeDirectory: $(baseSourceDirectory)/DockerCompose trigger: - develop @@ -51,7 +52,7 @@ jobs: docker pull $(AcrBaseUrl).azurecr.io/mock-data-holder-energy:$(containerTag) docker tag $(AcrBaseUrl).azurecr.io/mock-register:$(containerTag) mock-register:latest docker tag $(AcrBaseUrl).azurecr.io/mock-data-holder:$(containerTag) mock-data-holder:latest - docker tag $(AcrBaseUrl).azurecr.io/mock-data-holder-energy:$(containerTag) mock-data-holder-energy:latest + docker tag $(AcrBaseUrl).azurecr.io/mock-data-holder-energy:$(containerTag) mock-data-holder-energy:latest # List docker images - task: Docker@2 @@ -61,48 +62,37 @@ jobs: command: images # Run unit tests - - task: DockerCompose@0 - displayName: Unit tests - Up - inputs: - action: Run a Docker Compose command - dockerComposeFile: $(baseSourceDirectory)/docker-compose.UnitTests.yml - dockerComposeCommand: up --abort-on-container-exit --exit-code-from mock-data-recipient-unit-tests + - script: | + docker compose --file $(dockerComposeDirectory)/docker-compose.UnitTests.yml up --abort-on-container-exit --exit-code-from mock-data-recipient-unit-tests + displayName: Unit Tests - Up + condition: always() # Remove unit tests - - task: DockerCompose@0 - displayName: Unit tests - Down - condition: always() - inputs: - action: Run a Docker Compose command - dockerComposeFile: $(baseSourceDirectory)/docker-compose.UnitTests.yml - dockerComposeCommand: down + - script: | + docker compose --file $(dockerComposeDirectory)/docker-compose.UnitTests.yml down + displayName: 'Unit Tests - Down' + condition: always() # Run integration tests - - task: DockerCompose@0 + - script: | + docker compose --file $(dockerComposeDirectory)/docker-compose.IntegrationTests.yml up --abort-on-container-exit --exit-code-from mock-data-recipient-integration-tests displayName: Integration tests - Up condition: always() - inputs: - action: Run a Docker Compose command - dockerComposeFile: $(baseSourceDirectory)/docker-compose.IntegrationTests.yml - dockerComposeCommand: up --abort-on-container-exit --exit-code-from mock-data-recipient-integration-tests # Output Docker Logs - script: | - docker logs mock-register - docker logs mock-data-holder - docker logs mock-data-holder-energy - docker logs mock-data-recipient + docker logs mock-register-mdr-int + docker logs mock-data-holder-mdr-int + docker logs mock-data-holder-energy-mdr-int + docker logs mock-data-recipient-mdr-int displayName: 'Output Docker Logs' condition: always() # Remove integration tests - - task: DockerCompose@0 - displayName: Integration tests - Down - condition: always() - inputs: - action: Run a Docker Compose command - dockerComposeFile: $(baseSourceDirectory)/docker-compose.IntegrationTests.yml - dockerComposeCommand: down + - script: | + docker compose --file $(dockerComposeDirectory)/docker-compose.IntegrationTests.yml down + displayName: 'Integration tests - Down' + condition: always() # Surface Integration tests TRX results to Devops - task: PublishTestResults@2 @@ -111,37 +101,31 @@ jobs: inputs: testResultsFormat: 'VSTest' testResultsFiles: '**/results.trx' - searchFolder: $(baseSourceDirectory)/_temp/mock-data-recipient-integration-tests/testresults + searchFolder: $(dockerComposeDirectory)/_temp/mock-data-recipient-integration-tests/testresults mergeTestResults: true testRunTitle: 'mock-data-recipient-Integration-tests' publishRunAttachments: true # Run e2e tests - - task: DockerCompose@0 + - script: | + docker compose --file $(dockerComposeDirectory)/docker-compose.E2ETests.yml up --abort-on-container-exit --exit-code-from mock-data-recipient-e2e-tests displayName: E2E tests - Up condition: always() - inputs: - action: Run a Docker Compose command - dockerComposeFile: $(baseSourceDirectory)/docker-compose.E2ETests.yml - dockerComposeCommand: up --abort-on-container-exit --exit-code-from mock-data-recipient-e2e-tests # Output Docker Logs - script: | - docker logs mock-register - docker logs mock-data-holder - docker logs mock-data-holder-energy - docker logs mock-data-recipient + docker logs mock-register-mdr-e2e + docker logs mock-data-holder-mdr-e2e + docker logs mock-data-holder-energy-mdr-e2e + docker logs mock-data-recipient-mdr-e2e displayName: 'Output Docker Logs' condition: always() # Remove e2e tests - - task: DockerCompose@0 - displayName: E2E tests - Down - condition: always() - inputs: - action: Run a Docker Compose command - dockerComposeFile: $(baseSourceDirectory)/docker-compose.E2ETests.yml - dockerComposeCommand: down + - script: | + docker compose --file $(dockerComposeDirectory)/docker-compose.E2ETests.yml down + displayName: 'E2E tests - Down' + condition: always() # Surface E2E tests TRX results to Devops - task: PublishTestResults@2 @@ -150,7 +134,7 @@ jobs: inputs: testResultsFormat: 'VSTest' testResultsFiles: '**/results.trx' - searchFolder: $(baseSourceDirectory)/_temp/mock-data-recipient-e2e-tests/testresults + searchFolder: $(dockerComposeDirectory)/_temp/mock-data-recipient-e2e-tests/testresults mergeTestResults: true testRunTitle: 'mock-data-recipient-E2E-tests' publishRunAttachments: true @@ -173,36 +157,8 @@ jobs: path: $(build.artifactstagingdirectory) artifact: Container Images - # FIXME - MJS - See dockercompose, volume no longer mapped as 1001:121 (vsts:docker) in build pipeline and causes issue with chown in dockerfile (appuser:appgroup), ie stops register from starting because of different user - # # Publish mock-register logs - # - publish: $(baseSourceDirectory)/_temp/mock-register/tmp - # displayName: Publish MockRegister logs - # condition: always() - # artifact: Mock-Register - Logs - - # FIXME - MJS - See dockercompose, volume no longer mapped as 1001:121 (vsts:docker) in build pipeline and causes issue with chown in dockerfile (appuser:appgroup), ie stops register from starting because of different user - # # Publish mock-data-holder logs - # - publish: $(baseSourceDirectory)/_temp/mock-data-holder/tmp - # displayName: Publish MockDataHolder logs - # condition: always() - # artifact: Mock-Data-Holder - Logs - - # FIXME - MJS - See dockercompose, volume no longer mapped as 1001:121 (vsts:docker) in build pipeline and causes issue with chown in dockerfile (appuser:appgroup), ie stops register from starting because of different user - # # Publish mock-data-holder-energy logs - # - publish: $(baseSourceDirectory)/_temp/mock-data-holder-energy/tmp - # displayName: Publish MockDataHolder-Energy logs - # condition: always() - # artifact: Mock-Data-Holder-Energy - Logs - - # FIXME - MJS - See dockercompose, volume no longer mapped as 1001:121 (vsts:docker) in build pipeline and causes issue with chown in dockerfile (appuser:appgroup), ie stops register from starting because of different user - # # Publish mock-data-recipient logs - # - publish: $(baseSourceDirectory)/_temp/mock-data-recipient/tmp - # displayName: Publish MockDataRecipient logs - # condition: always() - # artifact: Mock-Data-Recipient - Logs - # Publish mock-data-recipient unit tests results - - publish: $(baseSourceDirectory)/_temp/mock-data-recipient-unit-tests/testresults + - publish: $(dockerComposeDirectory)/_temp/mock-data-recipient-unit-tests/testresults displayName: Publish unit tests condition: always() artifact: Mock-Data-Recipient - Unit tests @@ -210,14 +166,14 @@ jobs: # Run trx formatter to output .MD and .CSV - script: | docker run \ - -v=$(baseSourceDirectory)/_temp/mock-data-recipient-integration-tests/testresults/results.trx:/app/results.trx:ro \ - -v=$(baseSourceDirectory)/_temp/mock-data-recipient-integration-tests/testresults/formatted/:/app/out/:rw \ + -v=$(dockerComposeDirectory)/_temp/mock-data-recipient-integration-tests/testresults/results.trx:/app/results.trx:ro \ + -v=$(dockerComposeDirectory)/_temp/mock-data-recipient-integration-tests/testresults/formatted/:/app/out/:rw \ $(AcrBaseUrl).azurecr.io/trx-formatter -i results.trx -t "MDR" --outputprefix "MDR" -o out/ displayName: 'Run trx-formatter for integration tests' condition: always() # Publish mock-data-recipient integration tests results - - publish: $(baseSourceDirectory)/_temp/mock-data-recipient-integration-tests/testresults + - publish: $(dockerComposeDirectory)/_temp/mock-data-recipient-integration-tests/testresults displayName: Publish integration tests condition: always() artifact: Mock-Data-Recipient - Integration tests @@ -225,14 +181,14 @@ jobs: # Run trx formatter to output .MD and .CSV - script: | docker run \ - -v=$(baseSourceDirectory)/_temp/mock-data-recipient-e2e-tests/testresults/results.trx:/app/results.trx:ro \ - -v=$(baseSourceDirectory)/_temp/mock-data-recipient-e2e-tests/testresults/formatted/:/app/out/:rw \ + -v=$(dockerComposeDirectory)/_temp/mock-data-recipient-e2e-tests/testresults/results.trx:/app/results.trx:ro \ + -v=$(dockerComposeDirectory)/_temp/mock-data-recipient-e2e-tests/testresults/formatted/:/app/out/:rw \ $(AcrBaseUrl).azurecr.io/trx-formatter -i results.trx -t "MDR-E2E" --outputprefix "MDR-E2E" -o out/ displayName: 'Run trx-formatter for E2E tests' condition: always() # Publish mock-data-recipient e2e tests results - - publish: $(baseSourceDirectory)/_temp/mock-data-recipient-e2e-tests/testresults + - publish: $(dockerComposeDirectory)/_temp/mock-data-recipient-e2e-tests/testresults displayName: Publish e2e tests condition: always() artifact: Mock-Data-Recipient - E2E tests @@ -249,7 +205,7 @@ jobs: displayName: 'Install dotnet-ef' condition: always() inputs: - script: 'dotnet tool install --global dotnet-ef' + script: 'dotnet tool install --version 7.0.13 --global dotnet-ef' - task: CmdLine@2 displayName: 'Check dotnet-ef version' diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 45de3e7..eb3bd9e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -59,7 +59,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -70,9 +70,9 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 - # ℹ️ Command-line programs to run using the OS shell. + # ℹ️ Command-line programs to run using the OS shell # 📚 https://git.io/JvXDl # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines @@ -84,4 +84,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 66754d8..4cce631 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -78,3 +78,12 @@ jobs: - name: Image digest run: echo ${{ steps.docker_build.outputs.digest }} + + - name: Docker Hub Description + if: ${{ github.repository_owner == 'ConsumerDataRight' && github.ref_name == 'main' }} + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + repository: ${{ env.DOCKER_IMAGE }} + enable-url-completion: true diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 0f9fd61..43666af 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -101,12 +101,12 @@ jobs: # Run integration tests - name: Run integration tests run: | - docker-compose -f './mock-data-recipient/Source/docker-compose.IntegrationTests.yml' up --abort-on-container-exit --exit-code-from mock-data-recipient-integration-tests + docker compose -f './mock-data-recipient/Source/DockerCompose/docker-compose.IntegrationTests.yml' up --abort-on-container-exit --exit-code-from mock-data-recipient-integration-tests # Remove integration tests - name: Remove integration tests run: | - docker-compose -f './mock-data-recipient/Source/docker-compose.IntegrationTests.yml' down + docker compose -f './mock-data-recipient/Source/DockerCompose/docker-compose.IntegrationTests.yml' down # List docker images - name: List Docker images @@ -121,12 +121,12 @@ jobs: # Run e2e tests - name: Run e2e tests run: | - docker-compose -f './mock-data-recipient/Source/docker-compose.E2ETests.yml' up --abort-on-container-exit --exit-code-from mock-data-recipient-e2e-tests + docker compose -f './mock-data-recipient/Source/DockerCompose/docker-compose.E2ETests.yml' up --abort-on-container-exit --exit-code-from mock-data-recipient-e2e-tests # Remove e2e tests - name: Remove e2e tests run: | - docker-compose -f './mock-data-recipient/Source/docker-compose.E2ETests.yml' down + docker compose -f './mock-data-recipient/Source/DockerCompose/docker-compose.E2ETests.yml' down # Build mock-data-recipient-unit-tests image - name: Build the mock-data-recipient-unit-tests image @@ -136,12 +136,12 @@ jobs: # Run unit tests - name: Run unit tests run: | - docker-compose -f './mock-data-recipient/Source/docker-compose.UnitTests.yml' up --abort-on-container-exit --exit-code-from mock-data-recipient-unit-tests + docker compose -f './mock-data-recipient/Source/DockerCompose/docker-compose.UnitTests.yml' up --abort-on-container-exit --exit-code-from mock-data-recipient-unit-tests # Remove unit tests - name: Remove unit tests run: | - docker-compose -f './mock-data-recipient/Source/docker-compose.UnitTests.yml' down + docker compose -f './mock-data-recipient/Source/DockerCompose/docker-compose.UnitTests.yml' down # Archive unit test results - name: Archive unit test results @@ -149,7 +149,7 @@ jobs: if: always() with: name: unit-test-results - path: ${{ github.workspace }}/mock-data-recipient/Source/_temp/mock-data-recipient-unit-tests/testresults + path: ${{ github.workspace }}/mock-data-recipient/Source/DockerCompose/_temp/mock-data-recipient-unit-tests/testresults # Archive integration test results - name: Archive integration test results @@ -157,7 +157,7 @@ jobs: if: always() with: name: integration-test-results - path: ${{ github.workspace }}/mock-data-recipient/Source/_temp/mock-data-recipient-integration-tests/testresults + path: ${{ github.workspace }}/mock-data-recipient/Source/DockerCompose/_temp/mock-data-recipient-integration-tests/testresults # Archive e2e test results - name: Archive e2e test results @@ -165,7 +165,7 @@ jobs: if: always() with: name: e2e-test-results - path: ${{ github.workspace }}/mock-data-recipient/Source/_temp/mock-data-recipient-e2e-tests/testresults + path: ${{ github.workspace }}/mock-data-recipient/Source/DockerCompose/_temp/mock-data-recipient-e2e-tests/testresults # Archive mock data recipient logs - name: Archive mock data recipient logs @@ -173,7 +173,7 @@ jobs: if: always() with: name: integration-test-artifacts - path: ${{ github.workspace }}/mock-data-recipient/Source/_temp/mock-data-recipient/tmp + path: ${{ github.workspace }}/mock-data-recipient/Source/DockerCompose/_temp/mock-data-recipient/tmp # Archive mock data holder logs - name: Archive mock data holder logs @@ -181,7 +181,7 @@ jobs: if: always() with: name: integration-test-artifacts - path: ${{ github.workspace }}/mock-data-recipient/Source/_temp/mock-data-holder/tmp + path: ${{ github.workspace }}/mock-data-recipient/Source/DockerCompose/_temp/mock-data-holder/tmp # Archive mock data holder energy logs - name: Archive mock data holder energy logs @@ -189,7 +189,7 @@ jobs: if: always() with: name: integration-test-artifacts - path: ${{ github.workspace }}/mock-data-recipient/Source/_temp/mock-data-holder-energy/tmp + path: ${{ github.workspace }}/mock-data-recipient/Source/DockerCompose/_temp/mock-data-holder-energy/tmp # Archive mock register logs - name: Archive mock register logs @@ -197,4 +197,4 @@ jobs: if: always() with: name: integration-test-artifacts - path: ${{ github.workspace }}/mock-data-recipient/Source/_temp/mock-register/tmp + path: ${{ github.workspace }}/mock-data-recipient/Source/DockerCompose/_temp/mock-register/tmp diff --git a/.github/workflows/sonarcloud-analysis.yml b/.github/workflows/sonarcloud-analysis.yml index 9f24148..e4b9503 100644 --- a/.github/workflows/sonarcloud-analysis.yml +++ b/.github/workflows/sonarcloud-analysis.yml @@ -31,17 +31,18 @@ jobs: runs-on: windows-latest steps: - - name: Set up JDK 11 - uses: actions/setup-java@v1 + - name: Set up JDK 17 + uses: actions/setup-java@v3 if: ${{ env.sonarSecret != 0 }} # Only run scan if secret use is allowed - requires secrets to run successfully with: - java-version: 1.11 - - uses: actions/checkout@v2 + java-version: 17 + distribution: 'zulu' # Alternative distribution options are available. + - uses: actions/checkout@v3 if: ${{ env.sonarSecret != 0 }} # Only run scan if secret use is allowed - requires secrets to run successfully with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - name: Cache SonarCloud packages - uses: actions/cache@v2.1.6 + uses: actions/cache@v3 if: ${{ env.sonarSecret != 0 }} # Only run scan if secret use is allowed - requires secrets to run successfully with: path: ~\sonar\cache @@ -49,7 +50,7 @@ jobs: restore-keys: ${{ runner.os }}-sonar - name: Cache SonarCloud scanner id: cache-sonar-scanner - uses: actions/cache@v2.1.6 + uses: actions/cache@v3 if: ${{ env.sonarSecret != 0 }} # Only run scan if secret use is allowed - requires secrets to run successfully with: path: .\.sonar\scanner diff --git a/CHANGELOG.md b/CHANGELOG.md index 0803f22..9a1cdb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,16 @@ # Changelog All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [1.2.5] - 2023-11-29 +### Fixed +- Refactored code and minor bug fixes +- The address property in the userinfo endpoint structure is updated from string to object. [Mock Data Recipient Issue 67](https://github.com/ConsumerDataRight/mock-data-recipient/issues/67) + ## [1.2.4] - 2023-08-22 ### Fixed - Refactored code and fixed code smells diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 9768323..7501fdc 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -115,8 +115,8 @@ the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.0, available at -[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0]. +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. @@ -126,7 +126,7 @@ For answers to common questions about this code of conduct, see the FAQ at at [https://www.contributor-covenant.org/translations][translations]. [homepage]: https://www.contributor-covenant.org -[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html [Mozilla CoC]: https://github.com/mozilla/diversity [FAQ]: https://www.contributor-covenant.org/faq [translations]: https://www.contributor-covenant.org/translations diff --git a/Help/azurefunctions/HELP.md b/Help/azurefunctions/HELP.md index afae373..b2c3431 100644 --- a/Help/azurefunctions/HELP.md +++ b/Help/azurefunctions/HELP.md @@ -44,8 +44,8 @@ azurite --silent --location c:\azurite --debug c:\azurite\debug.log ``` -navigate to .\mock-data-holder-energy\Source\CDR.GetDataRecipients
-func start --verbose
+navigate to .\mock-data-holder\Source\CDR.GetDataRecipients +func start --verbose ```
diff --git a/Help/container/HELP.md b/Help/container/HELP.md index 8d1c390..b233ddc 100644 --- a/Help/container/HELP.md +++ b/Help/container/HELP.md @@ -24,7 +24,7 @@ docker pull consumerdataright/mock-data-recipient:0.5.0 ## Run a multi-container Mock CDR Ecosystem -Multiple containers can be run concurrently to simulate a CDR ecosystem. The [Mock Register](https://github.com/ConsumerDataRight/mock-register), [Mock Data Holder](https://github.com/ConsumerDataRight/mock-data-holder), [Mock Data Holder Energy](https://github.com/ConsumerDataRight/mock-data-holder-energy) and [Mock Data Recipient](https://github.com/ConsumerDataRight/mock-data-recipient) containers can be run by using the `docker-compose.yml` file. +Multiple containers can be run concurrently to simulate a CDR ecosystem. The [Mock Register](https://github.com/ConsumerDataRight/mock-register), Banking and Energy [Mock Data Holders](https://github.com/ConsumerDataRight/mock-data-holder) and [Mock Data Recipient](https://github.com/ConsumerDataRight/mock-data-recipient) containers can be run by using the `docker-compose.yml` file. The Mock CDR Ecosystem relies on SQL Server for data persistence so the container has a dependency on the SQL Server container image provided by Microsoft. diff --git a/README.md b/README.md index f0acd06..4fc95c1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ -![Consumer Data Right Logo](https://raw.githubusercontent.com/ConsumerDataRight/mock-data-recipient/main/cdr-logo.png) +![Consumer Data Right Logo](./cdr-logo.png?raw=true) -[![Consumer Data Standards v1.25.0](https://img.shields.io/badge/Consumer%20Data%20Standards-v1.25.0-blue.svg)](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.25.0/#introduction) -[![Conformance Test Suite 3.2](https://img.shields.io/badge/Conformance%20Test%20Suite-v3.2-darkblue.svg)](https://www.cdr.gov.au/for-providers/conformance-test-suite-data-recipients) +[![Consumer Data Standards v1.27.0](https://img.shields.io/badge/Consumer%20Data%20Standards-v1.27.0-blue.svg)](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.27.0/#introduction) [![made-with-dotnet](https://img.shields.io/badge/Made%20with-.NET-1f425Ff.svg)](https://dotnet.microsoft.com/) [![made-with-csharp](https://img.shields.io/badge/Made%20with-C%23-1f425Ff.svg)](https://docs.microsoft.com/en-us/dotnet/csharp/) [![MIT License](https://img.shields.io/github/license/ConsumerDataRight/mock-data-recipient)](./LICENSE) @@ -14,12 +13,11 @@ This repository contains a mock implementation of a Data Recipient and is offere ## Mock Data Recipient - Alignment The Mock Data Recipient in this release: -* aligns to [v1.25.0](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.25.0/#introduction) of the [Consumer Data Standards](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.25.0/#introduction); -* passed v3.2 of the [Conformance Test Suite for Data Recipients](https://www.cdr.gov.au/for-providers/conformance-test-suite-data-recipients); and +* aligns to [v1.27.0](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.27.0/#introduction) of the [Consumer Data Standards](https://consumerdatastandardsaustralia.github.io/standards-archives/standards-1.27.0/#introduction); * can connect to and complete authentication against both [FAPI 1.0 Migration Phase 2 and Phase 3](https://consumerdatastandardsaustralia.github.io/standards/#authentication-flows) compliant data holders. ## Getting Started -The Mock Data Recipient uses the [Mock Register](https://github.com/ConsumerDataRight/mock-register), the [Mock Data Holder](https://github.com/ConsumerDataRight/mock-data-holder) and the [Mock Data Holder Energy](https://github.com/ConsumerDataRight/mock-data-holder-energy). You can swap out any of the Mock Data Holders, Mock Data Register and Mock Data Recipient solutions with a solution of your own. +The Mock Data Recipient uses the [Mock Register](https://github.com/ConsumerDataRight/mock-register) and the Banking and Energy [Mock Data Holders](https://github.com/ConsumerDataRight/mock-data-holder). You can swap out any of the Mock Data Holders, Mock Data Register and Mock Data Recipient solutions with a solution of your own. There are a number of ways that the artefacts within this project can be used: 1. Build and deploy the source code @@ -37,9 +35,9 @@ git clone https://github.com/ConsumerDataRight/mock-data-recipient.git Set your debug profile to CDR.DataRecipient.Web ```` -To get help on launching and debugging the solution, see the [help guide](https://github.com/ConsumerDataRight/mock-data-recipient/blob/main/Help/debugging/HELP.md). +To get help on launching and debugging the solution, see the [help guide](./Help/debugging/HELP.md). -If you would like to contribute features or fixes back to the Mock Data Recipient repository, consult the [contributing guidelines](https://github.com/ConsumerDataRight/mock-data-recipient/blob/main/CONTRIBUTING.md). +If you would like to contribute features or fixes back to the Mock Data Recipient repository, consult the [contributing guidelines](./CONTRIBUTING.md). ### Use the pre-built image @@ -51,28 +49,28 @@ A version of the Mock Data Recipient is built into a single Docker image that is docker pull consumerdataright/mock-data-recipient ``` -To get help on launching and debugging the solutions as containers and switching out your solution(s), see the [help guide](https://github.com/ConsumerDataRight/mock-data-recipient/blob/main/Help/container/HELP.md). +To get help on launching and debugging the solutions as containers and switching out your solution(s), see the [help guide](./Help/container/HELP.md). #### Certificate Management -Consult the [Certificate Management](https://github.com/ConsumerDataRight/mock-data-recipient/blob/main/CertificateManagement/README.md) documentation for more information about how certificates are used for the Mock Data Recipient. +Consult the [Certificate Management](./CertificateManagement/README.md) documentation for more information about how certificates are used for the Mock Data Recipient. ### Use the docker compose file to run a multi-container mock CDR Ecosystem -The [docker compose file](https://github.com/ConsumerDataRight/mock-data-recipient/blob/main/Source/DockerCompose/docker-compose.yml) can be used to run multiple containers from the Mock CDR Ecosystem. +The [docker compose file](./Source/DockerCompose/docker-compose.yml) can be used to run multiple containers from the Mock CDR Ecosystem. -**Note:** the [docker compose file](https://github.com/ConsumerDataRight/mock-data-recipient/blob/main/Source/DockerCompose/docker-compose.yml) utilises the Microsoft SQL Server Image from Docker Hub. The Microsoft EULA for the Microsoft SQL Server Image must be accepted to use the [docker compose file](https://github.com/ConsumerDataRight/mock-data-recipient/blob/main/Source/DockerCompose/docker-compose.yml). See the Microsoft SQL Server Image on Docker Hub for more information. +**Note:** the [docker compose file](./Source/DockerCompose/docker-compose.yml) utilises the Microsoft SQL Server Image from Docker Hub. The Microsoft EULA for the Microsoft SQL Server Image must be accepted to use the [docker compose file](./Source/DockerCompose/docker-compose.yml). See the Microsoft SQL Server Image on Docker Hub for more information. -To get help on launching and debugging the solutions as containers and switching out your solution(s), see the [help guide](https://github.com/ConsumerDataRight/mock-data-recipient/blob/main/Help/container/HELP.md). +To get help on launching and debugging the solutions as containers and switching out your solution(s), see the [help guide](./Help/container/HELP.md). ## Mock Data Recipient - Architecture The following diagram outlines the high level architecture of the Mock Data Recipient: -[Mock Data Recipient - Architecture](https://raw.githubusercontent.com/ConsumerDataRight/mock-data-recipient/main/mock-data-recipient-architecture.png) +[Mock Data Recipient - Architecture](./mock-data-recipient-architecture.png?raw=true) Dynamic Client Registration Interface: -[Dynamic Client Registration Interface](https://raw.githubusercontent.com/ConsumerDataRight/mock-data-recipient/main/mock-data-recipient-dcr-architecture.png) +[Dynamic Client Registration Interface](./mock-data-recipient-dcr-architecture.png?raw=true) ## Mock Data Recipient - Components The Mock Data Recipient contains the following components: @@ -92,7 +90,7 @@ The Mock Data Recipient contains the following components: - Azure Functions - Azure Functions that can automate the continuous Get Data Holders discovery and Dynamic Client Registration process. - For each Data Holder retrieved from the Register, a message will be added to the DynamicClietnRegistration queue. A function listening to the queue, will pick up the message and attempt to register the Data Recipient with the Data Holder. - - To get help on the Azure Functions, see the [help guide](https://github.com/ConsumerDataRight/mock-data-recipient/blob/main/Help/azurefunctions/HELP.md). + - To get help on the Azure Functions, see the [help guide](./Help/azurefunctions/HELP.md). - Repository - A SQL repository is included that contains local data used within the Mock Data Recipient. - Includes the following collections: @@ -108,21 +106,23 @@ The following technologies have been used to build the Mock Data Recipient: # Testing The Mock Data Recipient has been built as a test harness to demonstrate the interactions between the Register and Data Holders. The Mock Data Recipient allows the end user to test the various interactions by changing input values, executing and viewing the response. -The Mock Data Recipient requires a [Mock Register](https://github.com/ConsumerDataRight/mock-register), -a [Mock Data Holder](https://github.com/ConsumerDataRight/mock-data-holder) and -a [Mock Data Holder Energy](https://github.com/ConsumerDataRight/mock-data-holder-energy) to completely mimic the CDR Ecosystem. - You can [swap out](https://github.com/ConsumerDataRight/mock-data-recipient/blob/main/Help/container/HELP.md) any of the Mock Data Holders, Mock Data Register and Mock Data Recipient solutions with a solution of your own. +The Mock Data Recipient requires a [Mock Register](https://github.com/ConsumerDataRight/mock-register) +and a Banking and Energy [Mock Data Holder](https://github.com/ConsumerDataRight/mock-data-holder) to completely mimic the CDR Ecosystem. + You can [swap out](./Help/container/HELP.md) any of the Mock Data Holders, Mock Data Register and Mock Data Recipient solutions with a solution of your own. Consents and Authorisation flow of FAPI 1.0 Migration Phase 1 is no longer supported. Use the Pushed Authorisation Request (PAR) flow when testing against data holders that have implemented FAPI 1.0 Migration Phase 2 or Phase 3. # Contribute -We encourage contributions from the community. See our [contributing guidelines](https://github.com/ConsumerDataRight/mock-data-recipient/blob/main/CONTRIBUTING.md). +We encourage contributions from the community. See our [contributing guidelines](./CONTRIBUTING.md). # Code of Conduct -This project has adopted the **Contributor Covenant**. For more information see the [code of conduct](https://github.com/ConsumerDataRight/mock-data-recipient/blob/main/CODE_OF_CONDUCT.md). +This project has adopted the **Contributor Covenant**. For more information see the [code of conduct](./CODE_OF_CONDUCT.md). + +# Security Policy +See our [security policy](./SECURITY.md) for information on security controls, reporting a vulnerability and supported versions. # License -[MIT License](https://github.com/ConsumerDataRight/mock-data-recipient/blob/main/LICENSE) +[MIT License](./LICENSE) # Notes The Mock Data Recipient is provided as a development tool only. It conforms to the Consumer Data Standards. \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..084cf77 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,38 @@ +# Security Policy +If you have discovered a potential security vulnerability within the [Consumer Data Right GitHub Organisation](https://github.com/ConsumerDataRight) or [Consumer Data Right Sandbox](https://cdrsandbox.gov.au/) +operated by the ACCC, we encourage you to disclose it to us as quickly as possible and in a responsible manner in accordance with our [Responsible disclosure of security vulnerabilities policy](https://www.cdr.gov.au/resources/responsible-disclosure-security-vulnerabilities-policy). + +Visit our [Responsible disclosure of security vulnerabilities policy](https://www.cdr.gov.au/resources/responsible-disclosure-security-vulnerabilities-policy) for: + - A full view of our Responsible disclosure of security vulnerabilities policy + - Your responsibilities if you find a vulnerability + - Steps required for reporting a vulnerability + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 1.2.x | :white_check_mark: | +| 1.1.x | :x: | +| 1.0.x | :x: | + + +## Reporting a Vulnerability +Visit our [Responsible disclosure of security vulnerabilities policy](https://www.cdr.gov.au/resources/responsible-disclosure-security-vulnerabilities-policy) for steps required for reporting a vulnerability. + + +## What controls are in place +### SonarCloud +Code repositories in [Consumer Data Right GitHub Organisation](https://github.com/ConsumerDataRight) utilise [SonarCloud](https://docs.sonarcloud.io/). Whenever a code change is made to this repository, GitHub actions are used to scan the code using SonarCloud. +The SonarCloud results are then assessed. High impact issues, that are not false positives, will be remediated. + - [mock-register results](https://sonarcloud.io/project/overview?id=ConsumerDataRight_mock-register) + - [mock-data-holder results](https://sonarcloud.io/project/overview?id=ConsumerDataRight_mock-data-holder) + - [mock-data-holder-energy results](https://sonarcloud.io/project/overview?id=ConsumerDataRight_mock-data-holder-energy) + - [mock-data-recipient results](https://sonarcloud.io/project/overview?id=ConsumerDataRight_mock-data-recipient) + - [authorisation-server results](https://sonarcloud.io/project/overview?id=ConsumerDataRight_authorisation-server) + - [mock-solution-test-automation results](https://sonarcloud.io/project/overview?id=ConsumerDataRight_mock-solution-test-automation) + +### GitHub Security Features +Code repositories in [Consumer Data Right GitHub Organisation](https://github.com/ConsumerDataRight) utilise [GitHub security features](https://docs.github.com/en/code-security/getting-started/github-security-features). + +### Keeping up to date +Code repositories in [Consumer Data Right GitHub Organisation](https://github.com/ConsumerDataRight) are routinely updated with new features and dependency updates. \ No newline at end of file diff --git a/Source/.dockerignore b/Source/.dockerignore index 742d166..b5e44e0 100644 --- a/Source/.dockerignore +++ b/Source/.dockerignore @@ -23,4 +23,5 @@ **/secrets.dev.yaml **/values.dev.yaml LICENSE -README.md \ No newline at end of file +README.md +_temp/ \ No newline at end of file diff --git a/Source/CDR.DCR/CDR.DCR.csproj b/Source/CDR.DCR/CDR.DCR.csproj index 31682a6..7d979dd 100644 --- a/Source/CDR.DCR/CDR.DCR.csproj +++ b/Source/CDR.DCR/CDR.DCR.csproj @@ -3,9 +3,9 @@ net6.0 v4 <_FunctionsSkipCleanOutput>true - 1.2.4 - 1.2.4 - 1.2.4 + 1.2.5 + 1.2.5 + 1.2.5 diff --git a/Source/CDR.DataRecipient.API.Logger/CDR.DataRecipient.API.Logger.csproj b/Source/CDR.DataRecipient.API.Logger/CDR.DataRecipient.API.Logger.csproj index 1323b0e..2d62a1a 100644 --- a/Source/CDR.DataRecipient.API.Logger/CDR.DataRecipient.API.Logger.csproj +++ b/Source/CDR.DataRecipient.API.Logger/CDR.DataRecipient.API.Logger.csproj @@ -4,9 +4,9 @@ net6.0 enable enable - 1.2.4 - 1.2.4 - 1.2.4 + 1.2.5 + 1.2.5 + 1.2.5 diff --git a/Source/CDR.DataRecipient.E2ETests/AATestPlaywrightInstallation.cs b/Source/CDR.DataRecipient.E2ETests/AATestPlaywrightInstallation.cs index 67c8c34..33670eb 100644 --- a/Source/CDR.DataRecipient.E2ETests/AATestPlaywrightInstallation.cs +++ b/Source/CDR.DataRecipient.E2ETests/AATestPlaywrightInstallation.cs @@ -5,7 +5,7 @@ namespace CDR.DataRecipient.E2ETests { - public class AATestPlaywrightInstallation : BaseTest_v3, IClassFixture + public class AATestPlaywrightInstallation : BaseTest, IClassFixture { [Fact] public async Task ShouldDisplayGoogleHomePage() diff --git a/Source/CDR.DataRecipient.E2ETests/BaseTest.cs b/Source/CDR.DataRecipient.E2ETests/BaseTest.cs index e39627b..8b5fb34 100644 --- a/Source/CDR.DataRecipient.E2ETests/BaseTest.cs +++ b/Source/CDR.DataRecipient.E2ETests/BaseTest.cs @@ -1,7 +1,4 @@ -#undef DEPRECATED // instead see BaseTest_v2 -#if DEPRECATED - -// #define TEST_DEBUG_MODE // Run Playwright in non-headless mode for debugging purposes (ie show a browser) +#define TEST_DEBUG_MODE // Run Playwright in non-headless mode for debugging purposes (ie show a browser) // In docker (Ubuntu container) Playwright will fail if running in non-headless mode, so we ensure TEST_DEBUG_MODE is undef'ed #if !DEBUG @@ -12,11 +9,13 @@ using System.IO; using System.Text.RegularExpressions; using System.Threading.Tasks; +using CDR.DataRecipient.E2ETests.Pages; using FluentAssertions; using FluentAssertions.Execution; using Microsoft.Data.SqlClient; using Microsoft.Extensions.Configuration; using Microsoft.Playwright; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Xunit; @@ -31,11 +30,15 @@ namespace CDR.DataRecipient.E2ETests [DisplayTestMethodName] public class BaseTest { + static public bool RUNNING_IN_CONTAINER => Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER")?.ToUpper() == "TRUE"; + // Customers public const string CUSTOMERID_BANKING = "jwilson"; - public const string CUSTOMERACCOUNTS_BANKING = "Personal Loan xxx-xxx xxxxx987,Transactions and Savings Account xxx-xxx xxxxx988"; + //public const string CUSTOMERACCOUNTS_BANKING = "Personal Loan xxx-xxx xxxxx987,Transactions and Savings Account xxx-xxx xxxxx988"; + public const string CUSTOMERACCOUNTS_BANKING = "Personal Loan,Transactions and Savings Account"; + public const string CUSTOMERID_ENERGY = "mmoss"; - public const string CUSTOMERACCOUNTS_ENERGY = "'ELECTRICITY ACCOUNT','ELECTRICITY ACCOUNT 2',ELECTRICITY ACCOUNT 3,ELECTRICITY ACCOUNT 4,ELECTRICITY ACCOUNT 5,ELECTRICITY ACCOUNT 6,ELECTRICITY ACCOUNT 7,ELECTRICITY ACCOUNT 8,ELECTRICITY ACCOUNT 9,ELECTRICITY ACCOUNT 10,ELECTRICITY ACCOUNT 11,ELECTRICITY ACCOUNT 12,ELECTRICITY ACCOUNT 13,ELECTRICITY ACCOUNT 14,ELECTRICITY ACCOUNT 15,ELECTRICITY ACCOUNT 16,ELECTRICITY ACCOUNT 17,ELECTRICITY ACCOUNT 18,ELECTRICITY ACCOUNT 19,ELECTRICITY ACCOUNT 20,ELECTRICITY ACCOUNT 21"; + public const string CUSTOMERACCOUNTS_ENERGY = "ELECTRICITY ACCOUNT,ELECTRICITY ACCOUNT 2,ELECTRICITY ACCOUNT 3,ELECTRICITY ACCOUNT 4,ELECTRICITY ACCOUNT 5,ELECTRICITY ACCOUNT 6,ELECTRICITY ACCOUNT 7,ELECTRICITY ACCOUNT 8,ELECTRICITY ACCOUNT 9,ELECTRICITY ACCOUNT 10,ELECTRICITY ACCOUNT 11,ELECTRICITY ACCOUNT 12,ELECTRICITY ACCOUNT 13,ELECTRICITY ACCOUNT 14,ELECTRICITY ACCOUNT 15,ELECTRICITY ACCOUNT 16,ELECTRICITY ACCOUNT 17,ELECTRICITY ACCOUNT 18,ELECTRICITY ACCOUNT 19,ELECTRICITY ACCOUNT 20,ELECTRICITY ACCOUNT 21"; // Data Holder public const string DH_BRANDID = "804fc2fb-18a7-4235-9a49-2af393d18bc7"; @@ -49,7 +52,7 @@ public class BaseTest static public string REGISTER_MTLS_BaseURL => Configuration["MTLS_BaseURL"] ?? throw new Exception($"{nameof(REGISTER_MTLS_BaseURL)} - configuration setting not found"); - static public string REGISTER_IDENTITYSERVER_URL = REGISTER_MTLS_BaseURL + "/idp/connect/token"; + public static readonly string REGISTER_IDENTITYSERVER_URL = REGISTER_MTLS_BaseURL + "/idp/connect/token"; // Client certificates protected const string CERTIFICATE_FILENAME = "Certificates/client.pfx"; @@ -58,6 +61,7 @@ public class BaseTest public const string JWT_CERTIFICATE_FILENAME = "Certificates/jwks.pfx"; public const string JWT_CERTIFICATE_PASSWORD = "#M0ckDataRecipient#"; + public const string SHARING_DURATION = "100000"; public bool CreateMedia { get; set; } = true; @@ -126,29 +130,91 @@ protected BaseTest() } private bool inArrange = false; - protected delegate Task ArrangeDelegate(); - protected async Task Arrange(ArrangeDelegate arrange) + protected delegate Task ArrangeDelegate(IPage page); + protected async Task ArrangeAsync(string testName, ArrangeDelegate arrange) { if (inArrange) return; inArrange = true; + + static void DeleteFile(string filename) + { + if (File.Exists(filename)) + { + File.Delete(filename); + } + } + + if (CreateMedia == true) + { + // Remove video/screens if they exist + DeleteFile($"{MEDIAFOLDER}/{testName}-arrange.webm"); + } + try { - CreateMedia = false; + // Setup Playwright + using var playwright = await Playwright.CreateAsync(); + + // Setup browser + await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions + { + SlowMo = 250, +#if TEST_DEBUG_MODE + Headless = false, + Timeout = 5000 // DEBUG - 5 seconds +#endif + }); + + // Setup browser context + var context = await browser.NewContextAsync(new BrowserNewContextOptions + { + IgnoreHTTPSErrors = true, + RecordVideoDir = CreateMedia == true ? $"{MEDIAFOLDER}" : null, + ViewportSize = new ViewportSize + { + Width = 1200, + Height = 1600 + } + }); + + string? videoPath = null; + var page = await context.NewPageAsync(); try { - // PatchRegister(); // No longer needed - seed data is correct - PurgeMDR(); - PurgeMDHIdentityServer(); - PurgeMDHEnergyIdentityServer(); - PurgeMDH(); - PurgeMDHE(); - await arrange(); + + page.Close += async (_, page) => + { + // Page is closed, so save videoPath + if (CreateMedia == true) + { + if (page.Video != null) + { + videoPath = await page.Video.PathAsync(); + } + } + }; + + using (new AssertionScope()) + { + page.SetDefaultTimeout(TEST_TIMEOUT); + await arrange(page); + } } finally { - CreateMedia = CREATE_MEDIA; + + await context.CloseAsync(); + await browser.CloseAsync(); + // Rename video file + if (CreateMedia == true) + { + if (videoPath != null) + { + File.Move(videoPath, $"{MEDIAFOLDER}/{testName}-arrange.webm"); + } + } } } finally @@ -161,10 +227,7 @@ protected async Task Arrange(ArrangeDelegate arrange) protected delegate Task CleanupDelegate(IPage page); protected async Task CleanupAsync(CleanupDelegate cleanup) { - if (inArrange) // shouldn't cleanup if arranging - return; - - if (inCleanup) + if (inArrange || inCleanup) return; inCleanup = true; @@ -464,42 +527,10 @@ public static void PurgeMDR() Purge(mdrConnection, "Registration"); } - public static void PurgeMDH() - { - // using var mdhConnection = new SqlConnection(BaseTest.DATAHOLDER_CONNECTIONSTRING); - // mdhConnection.Open(); - // Purge(mdhConnection, "Brand"); - // Purge(mdhConnection, "SoftwareProduct"); - } - - public static void PurgeMDHE() - { - // using var mdheConnection = new SqlConnection(BaseTest.DATAHOLDER_ENERGY_CONNECTIONSTRING); - // mdheConnection.Open(); - // Purge(mdheConnection, "Brand"); - // Purge(mdheConnection, "SoftwareProduct"); - } - - // public static void PurgeMDR_CDRArrangements() - // { - // using var mdrConnection = new SqlConnection(BaseTest.DATARECIPIENT_CONNECTIONSTRING); - // mdrConnection.Open(); - // Purge(mdrConnection, "CdrArrangement"); - // } - private static void PurgeIdentityServer(string connectionString) { using var identityServerConnection = new SqlConnection(connectionString); identityServerConnection.Open(); - - // Purge(identityServerConnection, "ApiResourceClaims"); - // Purge(identityServerConnection, "ApiResourceProperties"); - // Purge(identityServerConnection, "ApiResources"); - // Purge(identityServerConnection, "ApiResourceScopes"); - // Purge(identityServerConnection, "ApiResourceSecrets"); - // Purge(identityServerConnection, "ApiScopeClaims"); - // Purge(identityServerConnection, "ApiScopeProperties"); - // Purge(identityServerConnection, "ApiScopes"); Purge(identityServerConnection, "ClientClaims"); Purge(identityServerConnection, "ClientCorsOrigins"); Purge(identityServerConnection, "ClientGrantTypes"); @@ -510,10 +541,6 @@ private static void PurgeIdentityServer(string connectionString) Purge(identityServerConnection, "Clients"); Purge(identityServerConnection, "ClientScopes"); Purge(identityServerConnection, "ClientSecrets"); - // Purge(identityServerConnection, "DeviceCodes"); - // Purge(identityServerConnection, "IdentityResourceClaims"); - // Purge(identityServerConnection, "IdentityResourceProperties"); - // Purge(identityServerConnection, "IdentityResources"); Purge(identityServerConnection, "PersistedGrants"); } @@ -526,7 +553,237 @@ public static void PurgeMDHEnergyIdentityServer() { PurgeIdentityServer(BaseTest.DATAHOLDER_ENERGY_IDENTITYSERVER_CONNECTIONSTRING); } - } -} -#endif \ No newline at end of file + static protected async Task DataHolders_Discover(IPage page, string industry = "ALL", string version = "2", int? expectedRecords = 32, string? expectedError = null) + { + // Arrange - Goto home page, click menu button, check page loaded + await page.GotoAsync(WEB_URL); + await page.Locator("a >> text=Discover Data Holders").ClickAsync(); + await page.Locator("h2 >> text=Discover Data Holders").TextContentAsync(); + + // Arrange - Set industry + if (String.IsNullOrEmpty(industry)) // Clear industry + { + await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new SelectOptionValue[] { }); + } + else + { + await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new[] { industry switch + { + // "" => "", // Doesn't work for clearing, use SelectOptionAsync(new SelectOptionValue[] { }) instead (see above) + "ALL" => "0", + "BANKING" => "1", + "ENERGY" => "2", + "TELCO" => "3", + _ => throw new ArgumentOutOfRangeException($"{nameof(industry)}") + }}); + } + + // Arrange - Set version + await page.Locator("input[name=\"Version\"]").FillAsync(version); + + // Act - Click Refresh button + await page.Locator(@"h5:has-text(""Refresh Data Holders"") ~ div.card-body >> input:has-text(""Refresh"")").ClickAsync(); + + // Assert - Check refresh was successful + var footer = page.Locator(@"h5:has-text(""Refresh Data Holders"") ~ div.card-footer"); + var text = await footer.InnerTextAsync(); + if (expectedError != null) + { + text.Should().Be(expectedError); + } + else + { + if (expectedRecords != -1) // -1 = don't bother checking + { + text.Should().Be($"OK: {expectedRecords} data holder brands added. 0 data holder brands updated."); + } + } + } + + static protected async Task SSA_Get(IPage page, string industry, string version, string drBrandId, string drSoftwareProductId, string expectedMessage) + { + // Arrange - Goto home page, click menu button, check page loaded + await page.GotoAsync(WEB_URL); + await page.Locator("a >> text=Get SSA").ClickAsync(); + await page.Locator("h2 >> text=Get Software Statement Assertion").TextContentAsync(); + + // Set version + await page.Locator("input[name=\"Version\"]").FillAsync(version); + // Set brandId + await page.Locator("input[name=\"BrandId\"]").FillAsync(drBrandId); + // Set softwareProductId + await page.Locator("input[name=\"SoftwareProductId\"]").FillAsync(drSoftwareProductId); + // Set industry + await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new[] { industry switch + { + // "" => "", // Doesn't work for clearing, use SelectOptionAsync(new SelectOptionValue[] { }) instead (see above) + "ALL" => "0", + "BANKING" => "1", + "ENERGY" => "2", + "TELCO" => "3", + _ => throw new ArgumentOutOfRangeException($"{nameof(industry)}") + }}); + + // Act - Click Refresh button + await page.Locator(@"h5:has-text(""Get SSA"") ~ div.card-body >> input:has-text(""Get SSA"")").ClickAsync(); + + // Assert - Check refresh was successful, card-footer should be showing OK - SSA Generated + var footer = page.Locator(@"h5:has-text(""Get SSA"") ~ div.card-footer"); + var text = await footer.InnerTextAsync(); + text.Should().StartWith(expectedMessage); + } + + // Create Client Registration returning DH client ID of client that was registered + static protected async Task ClientRegistration_Create(IPage page, + string dhBrandId, + string drBrandId, + string drSoftwareProductId, + string? jarmSigningAlgo = null, + string responseTypes = "code id_token", + string? jarmEncrypAlg = null, + string? jarmEncryptEnc = null) + { + // Arrange - Goto home page, click menu button, check page loaded + await page.GotoAsync(WEB_URL); + await page.Locator("a >> text=Dynamic Client Registration").ClickAsync(); + await page.Locator("h2 >> text=Dynamic Client Registration").TextContentAsync(); + + // Set data holder brand id + await page.Locator("select[name=\"DataHolderBrandId\"]").SelectOptionAsync(new[] { dhBrandId }); + + // Assert - Check software product id + (await page.Locator("input[name=\"SoftwareProductId\"]").InputValueAsync()).Should().Be(drSoftwareProductId); + + await page.Locator("input[name=\"ResponseTypes\"]").FillAsync(responseTypes); + + if (jarmSigningAlgo != null) + { + await page.Locator("input[name=\"AuthorizationSignedResponseAlg\"]").FillAsync(jarmSigningAlgo); + } + if (jarmEncrypAlg != null) + { + await page.Locator("input[name=\"AuthorizationEncryptedResponseAlg\"]").FillAsync(jarmEncrypAlg); + } + if (jarmEncryptEnc != null) + { + await page.Locator("input[name=\"AuthorizationEncryptedResponseEnc\"]").FillAsync(jarmEncryptEnc); + } + + // Act - Click create button + await page.Locator(@"h5:has-text(""Create Client Registration"") ~ div.card-body >> input:has-text(""Register"")").ClickAsync(); + + // Assert - Check client was registered + await page.Locator(@"h5:has-text(""Create Client Registration"") ~ div.card-footer:has-text(""Created - Registered"")").TextContentAsync(); + + // Assert - Get json result + var json = await page.Locator(@"h5:has-text(""Create Client Registration"") ~ div.card-footer >> pre").InnerTextAsync(); + + // Deserialise response and return DH client id + DCRResponse dcrResponse = JsonConvert.DeserializeObject(json) ?? throw new NullReferenceException(nameof(json)); + return dcrResponse.ClientId ?? throw new NullReferenceException(nameof(dcrResponse.ClientId)); + } + + static protected async Task ConsentAndAuthorisation2(IPage page, string customerId = CUSTOMERID_BANKING, string customerAccounts = CUSTOMERACCOUNTS_BANKING) + { + + ConsentAndAuthorisationPages consentAndAuthorisationPages = new ConsentAndAuthorisationPages(page); + + await consentAndAuthorisationPages.EnterCustomerId(customerId); + await consentAndAuthorisationPages.ClickContinue(); + + await consentAndAuthorisationPages.EnterOtp("000789"); + await consentAndAuthorisationPages.ClickContinue(); + + await consentAndAuthorisationPages.SelectAccounts(customerAccounts); + await consentAndAuthorisationPages.ClickContinue(); + + await consentAndAuthorisationPages.ClickAuthorise(); + + // Assert - Check callback is shown and get arrangement ID + await page.Locator("text=Consent and Authorisation - Callback").TextContentAsync(); + + return new ConsentAndAuthorisationResponse + { + IDToken = await page.Locator(@"dt:has-text(""Id Token"") + dd ").TextContentAsync(), + AccessToken = await page.Locator(@"dt:has-text(""Access Token"") + dd ").TextContentAsync(), + RefreshToken = await page.Locator(@"dt:has-text(""Refresh Token"") + dd ").TextContentAsync(), + ExpiresIn = await page.Locator(@"dt:has-text(""Expires In"") + dd ").TextContentAsync(), + Scope = await page.Locator(@"dt:has-text(""Scope"") + dd ").TextContentAsync(), + TokenType = await page.Locator(@"dt:has-text("" Token Type"") + dd ").TextContentAsync(), + CDRArrangementID = await page.Locator(@"dt:has-text(""CDR Arrangement Id"") + dd ").TextContentAsync() + }; + } + + static protected async Task NewConsentAndAuthorisationWithPAR( + IPage page, + string dhClientId, + string customerId = CUSTOMERID_BANKING, + string customerAccounts = CUSTOMERACCOUNTS_BANKING, + string dhBrandId = DH_BRANDID) + { + // Arrange - Goto home page, click menu button, check page loaded + await page.GotoAsync(WEB_URL); + ParPage parPage = new ParPage(page); + await parPage.GotoPar(); + await parPage.CompleteParForm(dhClientId, dhBrandId, sharingDuration: SHARING_DURATION); + await parPage.ClickInitiatePar(); + await parPage.ClickAuthorizeUrl(); + + return await ConsentAndAuthorisation2(page, customerId, customerAccounts); + } + + private class DCRResponse + { + [JsonProperty("client_id")] + public string? ClientId { get; set; } + } + static protected async Task ClientRegistration_Delete(IPage page) + { + await page.GotoAsync(WEB_URL); + await page.Locator("a >> text=Dynamic Client Registration").ClickAsync(); + await page.Locator("h2 >> text=Dynamic Client Registration").TextContentAsync(); + await page.Locator("text=Delete").ClickAsync(); + await page.Locator("text=No existing registrations found.").TextContentAsync(); + } + static protected async Task Consents_DeleteLocal(IPage page) + { + await TestInfo(page, "Delete (local)", "Delete Arrangement", "204"); + } + public static async Task TestInfo(IPage page, string menuText, string modalTitle, string expectedStatusCode, (string name, string? value)[]? expectedPayload = null) + { + // Arrange - Goto home page, click menu button, check page loaded + await page.GotoAsync(WEB_URL); + await page.Locator("a >> text=Consents").ClickAsync(); + await page.Locator("h2 >> text=Consents").TextContentAsync(); + + // Act - Click actions button and submenu item + await page.Locator("button:has-text(\"Actions\")").ClickAsync(); + await page.Locator($"a >> text={menuText}").ClickAsync(); + + // Act - Check modal opens + await page.Locator($"div#modal-info >> h5.modal-title >> text={modalTitle}").TextContentAsync(); + + // Assert - Check statuscode + var statusCode = await page.Locator(@$"div#modal-info >> div.modal-statusCode >> text={expectedStatusCode}").TextContentAsync(); + statusCode.Should().Be(expectedStatusCode); + + // Assert - Check payload is what's expected + if (expectedPayload != null) + { + var payload = await page.Locator(@"div#modal-info >> pre.modal-payload").TextContentAsync(); + Assert_Json2(payload, expectedPayload); + } + } + public class ConsentAndAuthorisationResponse + { + public string? IDToken { get; init; } + public string? AccessToken { get; init; } + public string? RefreshToken { get; init; } + public string? ExpiresIn { get; init; } + public string? Scope { get; init; } + public string? TokenType { get; init; } + public string? CDRArrangementID { get; init; } + } + } +} \ No newline at end of file diff --git a/Source/CDR.DataRecipient.E2ETests/BaseTest_v2.cs b/Source/CDR.DataRecipient.E2ETests/BaseTest_v2.cs deleted file mode 100644 index 8991cb9..0000000 --- a/Source/CDR.DataRecipient.E2ETests/BaseTest_v2.cs +++ /dev/null @@ -1,558 +0,0 @@ -#undef DEPRECATED // instead see BaseTest_v3 -#if DEPRECATED - -#define TEST_DEBUG_MODE // Run Playwright in non-headless mode for debugging purposes (ie show a browser) - -// In docker (Ubuntu container) Playwright will fail if running in non-headless mode, so we ensure TEST_DEBUG_MODE is undef'ed -#if !DEBUG -#undef TEST_DEBUG_MODE -#endif - -using System; -using System.IO; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using FluentAssertions; -using FluentAssertions.Execution; -using Microsoft.Data.SqlClient; -using Microsoft.Extensions.Configuration; -using Microsoft.Playwright; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Xunit; - -#nullable enable - -namespace CDR.DataRecipient.E2ETests -{ - // Put all tests in same collection because we need them to run sequentially since some tests are mutating DB. - [Collection("E2ETests")] - [TestCaseOrderer("CDR.DataRecipient.E2ETests.XUnit.Orderers.AlphabeticalOrderer", "CDR.DataRecipient.E2ETests")] - [DisplayTestMethodName] - public class BaseTest_v2 - { - static public bool RUNNING_IN_CONTAINER => Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER")?.ToUpper() == "TRUE"; - - // Customers - public const string CUSTOMERID_BANKING = "jwilson"; - public const string CUSTOMERACCOUNTS_BANKING = "Personal Loan xxx-xxx xxxxx987,Transactions and Savings Account xxx-xxx xxxxx988"; - public const string CUSTOMERID_ENERGY = "mmoss"; - public const string CUSTOMERACCOUNTS_ENERGY = "'ELECTRICITY ACCOUNT','ELECTRICITY ACCOUNT 2',ELECTRICITY ACCOUNT 3,ELECTRICITY ACCOUNT 4,ELECTRICITY ACCOUNT 5,ELECTRICITY ACCOUNT 6,ELECTRICITY ACCOUNT 7,ELECTRICITY ACCOUNT 8,ELECTRICITY ACCOUNT 9,ELECTRICITY ACCOUNT 10,ELECTRICITY ACCOUNT 11,ELECTRICITY ACCOUNT 12,ELECTRICITY ACCOUNT 13,ELECTRICITY ACCOUNT 14,ELECTRICITY ACCOUNT 15,ELECTRICITY ACCOUNT 16,ELECTRICITY ACCOUNT 17,ELECTRICITY ACCOUNT 18,ELECTRICITY ACCOUNT 19,ELECTRICITY ACCOUNT 20,ELECTRICITY ACCOUNT 21"; - - // Data Holder - public const string DH_BRANDID = "804fc2fb-18a7-4235-9a49-2af393d18bc7"; - public const string DH_BRANDID_ENERGY = "cfcaf0df-401b-47f2-98af-94787289eca8"; // Mock Data Holder (Energy) - - // Data Recipient - public const string DR_BRANDID = "ffb1c8ba-279e-44d8-96f0-1bc34a6b436f"; - public const string DR_SOFTWAREPRODUCTID = "c6327f87-687a-4369-99a4-eaacd3bb8210"; - - // URLs - static public string REGISTER_MTLS_BaseURL => Configuration["MTLS_BaseURL"] - ?? throw new Exception($"{nameof(REGISTER_MTLS_BaseURL)} - configuration setting not found"); - - static public string REGISTER_IDENTITYSERVER_URL = REGISTER_MTLS_BaseURL + "/idp/connect/token"; - - // Client certificates - protected const string CERTIFICATE_FILENAME = "Certificates/client.pfx"; - protected const string CERTIFICATE_PASSWORD = "#M0ckDataRecipient#"; - - public const string JWT_CERTIFICATE_FILENAME = "Certificates/jwks.pfx"; - public const string JWT_CERTIFICATE_PASSWORD = "#M0ckDataRecipient#"; - - - public bool CreateMedia { get; set; } = true; - - // Test settings. - static public bool CREATE_MEDIA => Configuration.GetValue("CreateMedia", true); - static public int TEST_TIMEOUT => Configuration.GetValue("TestTimeout", 30000); - - // URL of the web UI - static public string WEB_URL => Configuration["Web_URL"] - ?? throw new Exception($"{nameof(WEB_URL)} - configuration setting not found"); - - // Hostnames - static public string HOSTNAME_REGISTER => Configuration["Hostnames:Register"] - ?? throw new Exception($"{nameof(HOSTNAME_REGISTER)} - configuration setting not found"); - static public string HOSTNAME_DATAHOLDER => Configuration["Hostnames:DataHolder"] - ?? throw new Exception($"{nameof(HOSTNAME_DATAHOLDER)} - configuration setting not found"); - static public string HOSTNAME_DATAHOLDER_ENERGY => Configuration["Hostnames:DataHolderEnergy"] - ?? throw new Exception($"{nameof(HOSTNAME_DATAHOLDER_ENERGY)} - configuration setting not found"); - static public string HOSTNAME_DATARECIPIENT => Configuration["Hostnames:DataRecipient"] - ?? throw new Exception($"{nameof(HOSTNAME_DATARECIPIENT)} - configuration setting not found"); - - // Connection strings - static public string DATAHOLDER_CONNECTIONSTRING => Configuration["ConnectionStrings:DataHolder"] - ?? throw new Exception($"{nameof(DATAHOLDER_CONNECTIONSTRING)} - configuration setting not found"); - static public string DATAHOLDER_ENERGY_CONNECTIONSTRING => Configuration["ConnectionStrings:DataHolderEnergy"] - ?? throw new Exception($"{nameof(DATAHOLDER_ENERGY_CONNECTIONSTRING)} - configuration setting not found"); - static public string DATAHOLDER_IDENTITYSERVER_CONNECTIONSTRING => Configuration["ConnectionStrings:DataHolderIdentityServer"] - ?? throw new Exception($"{nameof(DATAHOLDER_IDENTITYSERVER_CONNECTIONSTRING)} - configuration setting not found"); - static public string DATAHOLDER_ENERGY_IDENTITYSERVER_CONNECTIONSTRING => Configuration["ConnectionStrings:DataHolderEnergyIdentityServer"] - ?? throw new Exception($"{nameof(DATAHOLDER_ENERGY_IDENTITYSERVER_CONNECTIONSTRING)} - configuration setting not found"); - static public string REGISTER_CONNECTIONSTRING => Configuration["ConnectionStrings:Register"] - ?? throw new Exception($"{nameof(REGISTER_CONNECTIONSTRING)} - configuration setting not found"); - static public string DATARECIPIENT_CONNECTIONSTRING => Configuration["ConnectionStrings:DataRecipient"] - ?? throw new Exception($"{nameof(DATARECIPIENT_CONNECTIONSTRING)} - configuration setting not found"); - - // Media folder (for videos and screenshots) - static public string MEDIAFOLDER => Configuration["MediaFolder"] - ?? throw new Exception($"{nameof(MEDIAFOLDER)} - configuration setting not found"); - - // Dataholder - Access token lifetime seconds - static public string ACCESSTOKENLIFETIMESECONDS => Configuration["DataHolder:AccessTokenLifetimeSeconds"] - ?? throw new Exception($"{nameof(ACCESSTOKENLIFETIMESECONDS)} - configuration setting not found"); - - static private IConfigurationRoot? configuration; - static protected IConfigurationRoot Configuration - { - get - { - if (configuration == null) - { - configuration = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json") - .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", true) - .Build(); - } - - return configuration; - } - } - - protected BaseTest_v2() - { - // Default from config. - this.CreateMedia = CREATE_MEDIA; - } - - private bool inArrange = false; - protected delegate Task ArrangeDelegate(IPage page); - protected async Task ArrangeAsync(ArrangeDelegate arrange) - { - if (inArrange) - return; - - inArrange = true; - try - { - // Setup Playwright - using var playwright = await Playwright.CreateAsync(); - - // Setup browser - await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions - { - SlowMo = 250, -#if TEST_DEBUG_MODE - Headless = false, - Timeout = 5000 // DEBUG - 5 seconds -#endif - }); - - // Setup browser context - var context = await browser.NewContextAsync(new BrowserNewContextOptions - { - IgnoreHTTPSErrors = true, - RecordVideoDir = null, - ViewportSize = new ViewportSize - { - Width = 1200, - Height = 1600 - } - }); - - try - { - var page = await context.NewPageAsync(); - page.Close += async (_, page) => - { - }; - - using (new AssertionScope()) - { - page.SetDefaultTimeout(TEST_TIMEOUT); - await arrange(page); - } - } - finally - { - await context.CloseAsync(); - await browser.CloseAsync(); - } - } - finally - { - inArrange = false; - } - } - - private bool inCleanup = false; - protected delegate Task CleanupDelegate(IPage page); - protected async Task CleanupAsync(CleanupDelegate cleanup) - { - if (inArrange || inCleanup) - return; - - inCleanup = true; - try - { - // Setup Playwright - using var playwright = await Playwright.CreateAsync(); - - // Setup browser - await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions - { - SlowMo = 250, -#if TEST_DEBUG_MODE - Headless = false, - Timeout = 5000 // DEBUG - 5 seconds -#endif - }); - - // Setup browser context - var context = await browser.NewContextAsync(new BrowserNewContextOptions - { - IgnoreHTTPSErrors = true, - RecordVideoDir = null, - ViewportSize = new ViewportSize - { - Width = 1200, - Height = 1600 - } - }); - - try - { - var page = await context.NewPageAsync(); - page.Close += async (_, page) => - { - }; - - using (new AssertionScope()) - { - page.SetDefaultTimeout(TEST_TIMEOUT); - await cleanup(page); - } - } - finally - { - await context.CloseAsync(); - await browser.CloseAsync(); - } - } - finally - { - inCleanup = false; - } - } - - protected delegate Task TestDelegate(IPage page); - protected async Task TestAsync(string testName, TestDelegate testDelegate) //, bool? CreateMedia = true) - { - _testName = testName; - - static void DeleteFile(string filename) - { - if (File.Exists(filename)) - { - File.Delete(filename); - } - } - - if (CreateMedia == true) - { - // Remove video/screens if they exist - DeleteFile($"{MEDIAFOLDER}/{testName}.webm"); - DeleteFile($"{MEDIAFOLDER}/{testName}.png"); - DeleteFile($"{MEDIAFOLDER}/{testName}-exception.png"); - } - - // Setup Playwright - using var playwright = await Playwright.CreateAsync(); - - // Setup browser - await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions - { - SlowMo = 250, -#if TEST_DEBUG_MODE - Headless = false, - Timeout = 5000 // DEBUG - 5 seconds -#endif - }); - - // Setup browser context - var context = await browser.NewContextAsync(new BrowserNewContextOptions - { - IgnoreHTTPSErrors = true, - RecordVideoDir = CreateMedia == true ? $"{MEDIAFOLDER}" : null, - - //#if !TEST_DEBUG_MODE - ViewportSize = new ViewportSize - { - Width = 1200, - Height = 1600 - } - //#endif - }); - - string? videoPath = null; - try - { - var page = await context.NewPageAsync(); - try - { - page.Close += async (_, page) => - { - // Page is closed, so save videoPath - if (CreateMedia == true) - { - if (page.Video != null) - { - videoPath = await page.Video.PathAsync(); - } - } - }; - - using (new AssertionScope()) - { - page.SetDefaultTimeout(TEST_TIMEOUT); - await testDelegate(page); - } - } - finally - { - // Save a screenshot - if (CreateMedia == true) - { - await ScreenshotAsync(page, ""); - } - } - } - finally - { - // Wait 1 second so that video captures final state of page - await Task.Delay(1000); - - await context.CloseAsync(); - - // Rename video file - if (CreateMedia == true) - { - if (videoPath != null) - { - File.Move(videoPath, $"{MEDIAFOLDER}/{testName}.webm"); - } - } - - await browser.CloseAsync(); - } - } - - private string? _testName; - public async Task ScreenshotAsync(IPage page, string name) - { - await page.ScreenshotAsync(new PageScreenshotOptions { Path = $"{MEDIAFOLDER}/{_testName}{name}.png" }); - } - - protected static string? StripJsonProperty(string? json, string propertyName) - { - if (String.IsNullOrEmpty(json)) - return json; - - return Regex.Replace(json, @$"""{propertyName}"".*", ""); - } - - protected static void Assert_Json(string? expectedJson, string? actualJson) - { - static object? Deserialize(string json) - { - try { return JsonConvert.DeserializeObject(json); } - catch { return null; } - } - - static bool JsonCompare(string json, string jsonToCompare) - { - var jsonToken = JToken.Parse(json); - var jsonToCompareToken = JToken.Parse(jsonToCompare); - return JToken.DeepEquals(jsonToken, jsonToCompareToken); - } - - expectedJson.Should().NotBeNullOrEmpty(); - actualJson.Should().NotBeNullOrEmpty(expectedJson == null ? "" : $"expected {expectedJson}"); - - if (string.IsNullOrEmpty(expectedJson) || string.IsNullOrEmpty(actualJson)) - return; - - object? expectedObject = Deserialize(expectedJson); - expectedObject.Should().NotBeNull($"Error deserializing expected json - '{expectedJson}'"); - - object? actualObject = Deserialize(actualJson); - actualObject.Should().NotBeNull($"Error deserializing actual json - '{actualJson}'"); - - var expectedJsonNormalised = JsonConvert.SerializeObject(expectedObject); - var actualJsonNormalised = JsonConvert.SerializeObject(actualObject); - - JsonCompare(actualJson, expectedJson).Should().BeTrue( - $"\r\nExpected json:\r\n{expectedJsonNormalised}\r\nActual Json:\r\n{actualJsonNormalised}\r\n" - ); - } - - protected const string ASSERT_JSON2_ANYVALUE = "***ANYVALUE***"; - protected static void Assert_Json2(string? actualJson, (string name, string? value)[] expected) - { - actualJson.Should().NotBeNullOrEmpty(); - if (actualJson == null) - return; - - var root = JToken.Parse(actualJson); - - foreach ((var name, var value) in expected) - { - // Assert that json property exists - root[name].Should().NotBeNull($"Missing property '{name}'"); - - // Assert that value matches - if (value != ASSERT_JSON2_ANYVALUE) - { - root.Value(name).Should().Be(value, $"Property '{name}' should be '{value}'"); - } - } - } - - public static void PatchRegister() - { - using var connection = new SqlConnection(BaseTest_v2.REGISTER_CONNECTIONSTRING); - connection.Open(); - - // mock-data-recipient - using var updateCommand = new SqlCommand($@" - update - softwareproduct - set - recipientbaseuri = 'https://{BaseTest_v2.HOSTNAME_DATARECIPIENT}:9001', - revocationuri = 'https://{BaseTest_v2.HOSTNAME_DATARECIPIENT}:9001/revocation', - redirecturis = 'https://{BaseTest_v2.HOSTNAME_DATARECIPIENT}:9001/consent/callback', - jwksuri = 'https://{BaseTest_v2.HOSTNAME_DATARECIPIENT}:9001/jwks' - where - softwareproductid = '{BaseTest_v2.DR_SOFTWAREPRODUCTID}'", - connection); - updateCommand.ExecuteNonQuery(); - - // mock-data-holder - using var updateCommand2 = new SqlCommand($@" - update - endpoint - set - publicbaseuri = 'https://{BaseTest_v2.HOSTNAME_DATAHOLDER}:8000', - resourcebaseuri = 'https://{BaseTest_v2.HOSTNAME_DATAHOLDER}:8002', - infosecbaseuri = 'https://{BaseTest_v2.HOSTNAME_DATAHOLDER}:8001' - where - brandid = '{BaseTest_v2.DH_BRANDID}'", - connection); - updateCommand2.ExecuteNonQuery(); - - // mock-data-holder-energy - using var updateCommand3 = new SqlCommand($@" - update - endpoint - set - publicbaseuri = 'https://{BaseTest_v2.HOSTNAME_DATAHOLDER_ENERGY}:8100', - resourcebaseuri = 'https://{BaseTest_v2.HOSTNAME_DATAHOLDER_ENERGY}:8102', - infosecbaseuri = 'https://{BaseTest_v2.HOSTNAME_DATAHOLDER_ENERGY}:8101' - where - brandid = '{BaseTest_v2.DH_BRANDID_ENERGY}'", - connection); - updateCommand3.ExecuteNonQuery(); - } - - static void Purge(SqlConnection connection, string table) - { - // Delete all rows from table - using var deleteCommand = new SqlCommand($"delete from {table}", connection); - deleteCommand.ExecuteNonQuery(); - - // Check all rows deleted - using var selectCommand = new SqlCommand($"select count(*) from {table}", connection); - var count = Convert.ToInt32(selectCommand.ExecuteScalar()); - if (count != 0) - { - throw new Exception($"Error purging {table}"); - } - } - - public static void PurgeMDR() - { - using var mdrConnection = new SqlConnection(BaseTest_v2.DATARECIPIENT_CONNECTIONSTRING); - mdrConnection.Open(); - - Purge(mdrConnection, "CdrArrangement"); - Purge(mdrConnection, "DataHolderBrand"); - Purge(mdrConnection, "Registration"); - } - - public static void PurgeMDH() - { - // using var mdhConnection = new SqlConnection(BaseTest_v2.DATAHOLDER_CONNECTIONSTRING); - // mdhConnection.Open(); - // Purge(mdhConnection, "Brand"); - // Purge(mdhConnection, "SoftwareProduct"); - } - - public static void PurgeMDHE() - { - // using var mdheConnection = new SqlConnection(BaseTest_v2.DATAHOLDER_ENERGY_CONNECTIONSTRING); - // mdheConnection.Open(); - // Purge(mdheConnection, "Brand"); - // Purge(mdheConnection, "SoftwareProduct"); - } - - // public static void PurgeMDR_CDRArrangements() - // { - // using var mdrConnection = new SqlConnection(BaseTest_v2.DATARECIPIENT_CONNECTIONSTRING); - // mdrConnection.Open(); - // Purge(mdrConnection, "CdrArrangement"); - // } - - private static void PurgeIdentityServer(string connectionString) - { - using var identityServerConnection = new SqlConnection(connectionString); - identityServerConnection.Open(); - - // Purge(identityServerConnection, "ApiResourceClaims"); - // Purge(identityServerConnection, "ApiResourceProperties"); - // Purge(identityServerConnection, "ApiResources"); - // Purge(identityServerConnection, "ApiResourceScopes"); - // Purge(identityServerConnection, "ApiResourceSecrets"); - // Purge(identityServerConnection, "ApiScopeClaims"); - // Purge(identityServerConnection, "ApiScopeProperties"); - // Purge(identityServerConnection, "ApiScopes"); - Purge(identityServerConnection, "ClientClaims"); - Purge(identityServerConnection, "ClientCorsOrigins"); - Purge(identityServerConnection, "ClientGrantTypes"); - Purge(identityServerConnection, "ClientIdPRestrictions"); - Purge(identityServerConnection, "ClientPostLogoutRedirectUris"); - Purge(identityServerConnection, "ClientProperties"); - Purge(identityServerConnection, "ClientRedirectUris"); - Purge(identityServerConnection, "Clients"); - Purge(identityServerConnection, "ClientScopes"); - Purge(identityServerConnection, "ClientSecrets"); - // Purge(identityServerConnection, "DeviceCodes"); - // Purge(identityServerConnection, "IdentityResourceClaims"); - // Purge(identityServerConnection, "IdentityResourceProperties"); - // Purge(identityServerConnection, "IdentityResources"); - Purge(identityServerConnection, "PersistedGrants"); - } - - public static void PurgeMDHIdentityServer() - { - PurgeIdentityServer(BaseTest_v2.DATAHOLDER_IDENTITYSERVER_CONNECTIONSTRING); - } - - public static void PurgeMDHEnergyIdentityServer() - { - PurgeIdentityServer(BaseTest_v2.DATAHOLDER_ENERGY_IDENTITYSERVER_CONNECTIONSTRING); - } - } -} -#endif \ No newline at end of file diff --git a/Source/CDR.DataRecipient.E2ETests/BaseTest_v3.cs b/Source/CDR.DataRecipient.E2ETests/BaseTest_v3.cs deleted file mode 100644 index 75d01de..0000000 --- a/Source/CDR.DataRecipient.E2ETests/BaseTest_v3.cs +++ /dev/null @@ -1,789 +0,0 @@ -#define TEST_DEBUG_MODE // Run Playwright in non-headless mode for debugging purposes (ie show a browser) - -// In docker (Ubuntu container) Playwright will fail if running in non-headless mode, so we ensure TEST_DEBUG_MODE is undef'ed -#if !DEBUG -#undef TEST_DEBUG_MODE -#endif - -using System; -using System.IO; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using CDR.DataRecipient.E2ETests.Pages; -using FluentAssertions; -using FluentAssertions.Execution; -using Microsoft.Data.SqlClient; -using Microsoft.Extensions.Configuration; -using Microsoft.Playwright; -using Microsoft.VisualStudio.TestPlatform.ObjectModel; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Xunit; - -#nullable enable - -namespace CDR.DataRecipient.E2ETests -{ - // Put all tests in same collection because we need them to run sequentially since some tests are mutating DB. - [Collection("E2ETests")] - [TestCaseOrderer("CDR.DataRecipient.E2ETests.XUnit.Orderers.AlphabeticalOrderer", "CDR.DataRecipient.E2ETests")] - [DisplayTestMethodName] - public class BaseTest_v3 - { - static public bool RUNNING_IN_CONTAINER => Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER")?.ToUpper() == "TRUE"; - - // Customers - public const string CUSTOMERID_BANKING = "jwilson"; - //public const string CUSTOMERACCOUNTS_BANKING = "Personal Loan xxx-xxx xxxxx987,Transactions and Savings Account xxx-xxx xxxxx988"; - public const string CUSTOMERACCOUNTS_BANKING = "Personal Loan,Transactions and Savings Account"; - - public const string CUSTOMERID_ENERGY = "mmoss"; - public const string CUSTOMERACCOUNTS_ENERGY = "ELECTRICITY ACCOUNT,ELECTRICITY ACCOUNT 2,ELECTRICITY ACCOUNT 3,ELECTRICITY ACCOUNT 4,ELECTRICITY ACCOUNT 5,ELECTRICITY ACCOUNT 6,ELECTRICITY ACCOUNT 7,ELECTRICITY ACCOUNT 8,ELECTRICITY ACCOUNT 9,ELECTRICITY ACCOUNT 10,ELECTRICITY ACCOUNT 11,ELECTRICITY ACCOUNT 12,ELECTRICITY ACCOUNT 13,ELECTRICITY ACCOUNT 14,ELECTRICITY ACCOUNT 15,ELECTRICITY ACCOUNT 16,ELECTRICITY ACCOUNT 17,ELECTRICITY ACCOUNT 18,ELECTRICITY ACCOUNT 19,ELECTRICITY ACCOUNT 20,ELECTRICITY ACCOUNT 21"; - - // Data Holder - public const string DH_BRANDID = "804fc2fb-18a7-4235-9a49-2af393d18bc7"; - public const string DH_BRANDID_ENERGY = "cfcaf0df-401b-47f2-98af-94787289eca8"; // Mock Data Holder (Energy) - - // Data Recipient - public const string DR_BRANDID = "ffb1c8ba-279e-44d8-96f0-1bc34a6b436f"; - public const string DR_SOFTWAREPRODUCTID = "c6327f87-687a-4369-99a4-eaacd3bb8210"; - - // URLs - static public string REGISTER_MTLS_BaseURL => Configuration["MTLS_BaseURL"] - ?? throw new Exception($"{nameof(REGISTER_MTLS_BaseURL)} - configuration setting not found"); - - public static readonly string REGISTER_IDENTITYSERVER_URL = REGISTER_MTLS_BaseURL + "/idp/connect/token"; - - // Client certificates - protected const string CERTIFICATE_FILENAME = "Certificates/client.pfx"; - protected const string CERTIFICATE_PASSWORD = "#M0ckDataRecipient#"; - - public const string JWT_CERTIFICATE_FILENAME = "Certificates/jwks.pfx"; - public const string JWT_CERTIFICATE_PASSWORD = "#M0ckDataRecipient#"; - - public const string SHARING_DURATION = "100000"; - - public bool CreateMedia { get; set; } = true; - - // Test settings. - static public bool CREATE_MEDIA => Configuration.GetValue("CreateMedia", true); - static public int TEST_TIMEOUT => Configuration.GetValue("TestTimeout", 30000); - - // URL of the web UI - static public string WEB_URL => Configuration["Web_URL"] - ?? throw new Exception($"{nameof(WEB_URL)} - configuration setting not found"); - - // Hostnames - static public string HOSTNAME_REGISTER => Configuration["Hostnames:Register"] - ?? throw new Exception($"{nameof(HOSTNAME_REGISTER)} - configuration setting not found"); - static public string HOSTNAME_DATAHOLDER => Configuration["Hostnames:DataHolder"] - ?? throw new Exception($"{nameof(HOSTNAME_DATAHOLDER)} - configuration setting not found"); - static public string HOSTNAME_DATAHOLDER_ENERGY => Configuration["Hostnames:DataHolderEnergy"] - ?? throw new Exception($"{nameof(HOSTNAME_DATAHOLDER_ENERGY)} - configuration setting not found"); - static public string HOSTNAME_DATARECIPIENT => Configuration["Hostnames:DataRecipient"] - ?? throw new Exception($"{nameof(HOSTNAME_DATARECIPIENT)} - configuration setting not found"); - - // Connection strings - static public string DATAHOLDER_CONNECTIONSTRING => Configuration["ConnectionStrings:DataHolder"] - ?? throw new Exception($"{nameof(DATAHOLDER_CONNECTIONSTRING)} - configuration setting not found"); - static public string DATAHOLDER_ENERGY_CONNECTIONSTRING => Configuration["ConnectionStrings:DataHolderEnergy"] - ?? throw new Exception($"{nameof(DATAHOLDER_ENERGY_CONNECTIONSTRING)} - configuration setting not found"); - static public string DATAHOLDER_IDENTITYSERVER_CONNECTIONSTRING => Configuration["ConnectionStrings:DataHolderIdentityServer"] - ?? throw new Exception($"{nameof(DATAHOLDER_IDENTITYSERVER_CONNECTIONSTRING)} - configuration setting not found"); - static public string DATAHOLDER_ENERGY_IDENTITYSERVER_CONNECTIONSTRING => Configuration["ConnectionStrings:DataHolderEnergyIdentityServer"] - ?? throw new Exception($"{nameof(DATAHOLDER_ENERGY_IDENTITYSERVER_CONNECTIONSTRING)} - configuration setting not found"); - static public string REGISTER_CONNECTIONSTRING => Configuration["ConnectionStrings:Register"] - ?? throw new Exception($"{nameof(REGISTER_CONNECTIONSTRING)} - configuration setting not found"); - static public string DATARECIPIENT_CONNECTIONSTRING => Configuration["ConnectionStrings:DataRecipient"] - ?? throw new Exception($"{nameof(DATARECIPIENT_CONNECTIONSTRING)} - configuration setting not found"); - - // Media folder (for videos and screenshots) - static public string MEDIAFOLDER => Configuration["MediaFolder"] - ?? throw new Exception($"{nameof(MEDIAFOLDER)} - configuration setting not found"); - - // Dataholder - Access token lifetime seconds - static public string ACCESSTOKENLIFETIMESECONDS => Configuration["DataHolder:AccessTokenLifetimeSeconds"] - ?? throw new Exception($"{nameof(ACCESSTOKENLIFETIMESECONDS)} - configuration setting not found"); - - static private IConfigurationRoot? configuration; - static protected IConfigurationRoot Configuration - { - get - { - if (configuration == null) - { - configuration = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json") - .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", true) - .Build(); - } - - return configuration; - } - } - - protected BaseTest_v3() - { - // Default from config. - this.CreateMedia = CREATE_MEDIA; - } - - private bool inArrange = false; - protected delegate Task ArrangeDelegate(IPage page); - protected async Task ArrangeAsync(string testName, ArrangeDelegate arrange) - { - if (inArrange) - return; - - inArrange = true; - - static void DeleteFile(string filename) - { - if (File.Exists(filename)) - { - File.Delete(filename); - } - } - - if (CreateMedia == true) - { - // Remove video/screens if they exist - DeleteFile($"{MEDIAFOLDER}/{testName}-arrange.webm"); - } - - try - { - // Setup Playwright - using var playwright = await Playwright.CreateAsync(); - - // Setup browser - await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions - { - SlowMo = 250, -#if TEST_DEBUG_MODE - Headless = false, - Timeout = 5000 // DEBUG - 5 seconds -#endif - }); - - // Setup browser context - var context = await browser.NewContextAsync(new BrowserNewContextOptions - { - IgnoreHTTPSErrors = true, - RecordVideoDir = CreateMedia == true ? $"{MEDIAFOLDER}" : null, - ViewportSize = new ViewportSize - { - Width = 1200, - Height = 1600 - } - }); - - string? videoPath = null; - var page = await context.NewPageAsync(); - try - { - - page.Close += async (_, page) => - { - // Page is closed, so save videoPath - if (CreateMedia == true) - { - if (page.Video != null) - { - videoPath = await page.Video.PathAsync(); - } - } - }; - - using (new AssertionScope()) - { - page.SetDefaultTimeout(TEST_TIMEOUT); - await arrange(page); - } - } - finally - { - - await context.CloseAsync(); - await browser.CloseAsync(); - // Rename video file - if (CreateMedia == true) - { - if (videoPath != null) - { - File.Move(videoPath, $"{MEDIAFOLDER}/{testName}-arrange.webm"); - } - } - } - } - finally - { - inArrange = false; - } - } - - private bool inCleanup = false; - protected delegate Task CleanupDelegate(IPage page); - protected async Task CleanupAsync(CleanupDelegate cleanup) - { - if (inArrange || inCleanup) - return; - - inCleanup = true; - try - { - // Setup Playwright - using var playwright = await Playwright.CreateAsync(); - - // Setup browser - await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions - { - SlowMo = 250, -#if TEST_DEBUG_MODE - Headless = false, - Timeout = 5000 // DEBUG - 5 seconds -#endif - }); - - // Setup browser context - var context = await browser.NewContextAsync(new BrowserNewContextOptions - { - IgnoreHTTPSErrors = true, - RecordVideoDir = null, - ViewportSize = new ViewportSize - { - Width = 1200, - Height = 1600 - } - }); - - try - { - var page = await context.NewPageAsync(); - page.Close += async (_, page) => - { - }; - - using (new AssertionScope()) - { - page.SetDefaultTimeout(TEST_TIMEOUT); - await cleanup(page); - } - } - finally - { - await context.CloseAsync(); - await browser.CloseAsync(); - } - } - finally - { - inCleanup = false; - } - } - - protected delegate Task TestDelegate(IPage page); - protected async Task TestAsync(string testName, TestDelegate testDelegate) //, bool? CreateMedia = true) - { - _testName = testName; - - static void DeleteFile(string filename) - { - if (File.Exists(filename)) - { - File.Delete(filename); - } - } - - if (CreateMedia == true) - { - // Remove video/screens if they exist - DeleteFile($"{MEDIAFOLDER}/{testName}.webm"); - DeleteFile($"{MEDIAFOLDER}/{testName}.png"); - DeleteFile($"{MEDIAFOLDER}/{testName}-exception.png"); - } - - // Setup Playwright - using var playwright = await Playwright.CreateAsync(); - - // Setup browser - await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions - { - SlowMo = 250, -#if TEST_DEBUG_MODE - Headless = false, - Timeout = 5000 // DEBUG - 5 seconds -#endif - }); - - // Setup browser context - var context = await browser.NewContextAsync(new BrowserNewContextOptions - { - IgnoreHTTPSErrors = true, - RecordVideoDir = CreateMedia == true ? $"{MEDIAFOLDER}" : null, - - //#if !TEST_DEBUG_MODE - ViewportSize = new ViewportSize - { - Width = 1200, - Height = 1600 - } - //#endif - }); - - string? videoPath = null; - try - { - var page = await context.NewPageAsync(); - try - { - page.Close += async (_, page) => - { - // Page is closed, so save videoPath - if (CreateMedia == true) - { - if (page.Video != null) - { - videoPath = await page.Video.PathAsync(); - } - } - }; - - using (new AssertionScope()) - { - page.SetDefaultTimeout(TEST_TIMEOUT); - await testDelegate(page); - } - } - finally - { - // Save a screenshot - if (CreateMedia == true) - { - await ScreenshotAsync(page, ""); - } - } - } - finally - { - // Wait 1 second so that video captures final state of page - await Task.Delay(1000); - - await context.CloseAsync(); - - // Rename video file - if (CreateMedia == true) - { - if (videoPath != null) - { - File.Move(videoPath, $"{MEDIAFOLDER}/{testName}.webm"); - } - } - - await browser.CloseAsync(); - } - } - - private string? _testName; - public async Task ScreenshotAsync(IPage page, string name) - { - await page.ScreenshotAsync(new PageScreenshotOptions { Path = $"{MEDIAFOLDER}/{_testName}{name}.png" }); - } - - protected static string? StripJsonProperty(string? json, string propertyName) - { - if (String.IsNullOrEmpty(json)) - return json; - - return Regex.Replace(json, @$"""{propertyName}"".*", ""); - } - - protected static void Assert_Json(string? expectedJson, string? actualJson) - { - static object? Deserialize(string json) - { - try { return JsonConvert.DeserializeObject(json); } - catch { return null; } - } - - static bool JsonCompare(string json, string jsonToCompare) - { - var jsonToken = JToken.Parse(json); - var jsonToCompareToken = JToken.Parse(jsonToCompare); - return JToken.DeepEquals(jsonToken, jsonToCompareToken); - } - - expectedJson.Should().NotBeNullOrEmpty(); - actualJson.Should().NotBeNullOrEmpty(expectedJson == null ? "" : $"expected {expectedJson}"); - - if (string.IsNullOrEmpty(expectedJson) || string.IsNullOrEmpty(actualJson)) - return; - - object? expectedObject = Deserialize(expectedJson); - expectedObject.Should().NotBeNull($"Error deserializing expected json - '{expectedJson}'"); - - object? actualObject = Deserialize(actualJson); - actualObject.Should().NotBeNull($"Error deserializing actual json - '{actualJson}'"); - - var expectedJsonNormalised = JsonConvert.SerializeObject(expectedObject); - var actualJsonNormalised = JsonConvert.SerializeObject(actualObject); - - JsonCompare(actualJson, expectedJson).Should().BeTrue( - $"\r\nExpected json:\r\n{expectedJsonNormalised}\r\nActual Json:\r\n{actualJsonNormalised}\r\n" - ); - } - - protected const string ASSERT_JSON2_ANYVALUE = "***ANYVALUE***"; - protected static void Assert_Json2(string? actualJson, (string name, string? value)[] expected) - { - actualJson.Should().NotBeNullOrEmpty(); - if (actualJson == null) - return; - - var root = JToken.Parse(actualJson); - - foreach ((var name, var value) in expected) - { - // Assert that json property exists - root[name].Should().NotBeNull($"Missing property '{name}'"); - - // Assert that value matches - if (value != ASSERT_JSON2_ANYVALUE) - { - root.Value(name).Should().Be(value, $"Property '{name}' should be '{value}'"); - } - } - } - - public static void PatchRegister() - { - using var connection = new SqlConnection(BaseTest_v3.REGISTER_CONNECTIONSTRING); - connection.Open(); - - // mock-data-recipient - using var updateCommand = new SqlCommand($@" - update - softwareproduct - set - recipientbaseuri = 'https://{BaseTest_v3.HOSTNAME_DATARECIPIENT}:9001', - revocationuri = 'https://{BaseTest_v3.HOSTNAME_DATARECIPIENT}:9001/revocation', - redirecturis = 'https://{BaseTest_v3.HOSTNAME_DATARECIPIENT}:9001/consent/callback', - jwksuri = 'https://{BaseTest_v3.HOSTNAME_DATARECIPIENT}:9001/jwks' - where - softwareproductid = '{BaseTest_v3.DR_SOFTWAREPRODUCTID}'", - connection); - updateCommand.ExecuteNonQuery(); - - // mock-data-holder - using var updateCommand2 = new SqlCommand($@" - update - endpoint - set - publicbaseuri = 'https://{BaseTest_v3.HOSTNAME_DATAHOLDER}:8000', - resourcebaseuri = 'https://{BaseTest_v3.HOSTNAME_DATAHOLDER}:8002', - infosecbaseuri = 'https://{BaseTest_v3.HOSTNAME_DATAHOLDER}:8001' - where - brandid = '{BaseTest_v3.DH_BRANDID}'", - connection); - updateCommand2.ExecuteNonQuery(); - - // mock-data-holder-energy - using var updateCommand3 = new SqlCommand($@" - update - endpoint - set - publicbaseuri = 'https://{BaseTest_v3.HOSTNAME_DATAHOLDER_ENERGY}:8100', - resourcebaseuri = 'https://{BaseTest_v3.HOSTNAME_DATAHOLDER_ENERGY}:8102', - infosecbaseuri = 'https://{BaseTest_v3.HOSTNAME_DATAHOLDER_ENERGY}:8101' - where - brandid = '{BaseTest_v3.DH_BRANDID_ENERGY}'", - connection); - updateCommand3.ExecuteNonQuery(); - } - - static void Purge(SqlConnection connection, string table) - { - // Delete all rows from table - using var deleteCommand = new SqlCommand($"delete from {table}", connection); - deleteCommand.ExecuteNonQuery(); - - // Check all rows deleted - using var selectCommand = new SqlCommand($"select count(*) from {table}", connection); - var count = Convert.ToInt32(selectCommand.ExecuteScalar()); - if (count != 0) - { - throw new Exception($"Error purging {table}"); - } - } - - public static void PurgeMDR() - { - using var mdrConnection = new SqlConnection(BaseTest_v3.DATARECIPIENT_CONNECTIONSTRING); - mdrConnection.Open(); - - Purge(mdrConnection, "CdrArrangement"); - Purge(mdrConnection, "DataHolderBrand"); - Purge(mdrConnection, "Registration"); - } - - private static void PurgeIdentityServer(string connectionString) - { - using var identityServerConnection = new SqlConnection(connectionString); - identityServerConnection.Open(); - Purge(identityServerConnection, "ClientClaims"); - Purge(identityServerConnection, "ClientCorsOrigins"); - Purge(identityServerConnection, "ClientGrantTypes"); - Purge(identityServerConnection, "ClientIdPRestrictions"); - Purge(identityServerConnection, "ClientPostLogoutRedirectUris"); - Purge(identityServerConnection, "ClientProperties"); - Purge(identityServerConnection, "ClientRedirectUris"); - Purge(identityServerConnection, "Clients"); - Purge(identityServerConnection, "ClientScopes"); - Purge(identityServerConnection, "ClientSecrets"); - Purge(identityServerConnection, "PersistedGrants"); - } - - public static void PurgeMDHIdentityServer() - { - PurgeIdentityServer(BaseTest_v3.DATAHOLDER_IDENTITYSERVER_CONNECTIONSTRING); - } - - public static void PurgeMDHEnergyIdentityServer() - { - PurgeIdentityServer(BaseTest_v3.DATAHOLDER_ENERGY_IDENTITYSERVER_CONNECTIONSTRING); - } - - static protected async Task DataHolders_Discover(IPage page, string industry = "ALL", string version = "2", int? expectedRecords = 32, string? expectedError = null) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Discover Data Holders").ClickAsync(); - await page.Locator("h2 >> text=Discover Data Holders").TextContentAsync(); - - // Arrange - Set industry - if (String.IsNullOrEmpty(industry)) // Clear industry - { - await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new SelectOptionValue[] { }); - } - else - { - await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new[] { industry switch - { - // "" => "", // Doesn't work for clearing, use SelectOptionAsync(new SelectOptionValue[] { }) instead (see above) - "ALL" => "0", - "BANKING" => "1", - "ENERGY" => "2", - "TELCO" => "3", - _ => throw new ArgumentOutOfRangeException($"{nameof(industry)}") - }}); - } - - // Arrange - Set version - await page.Locator("input[name=\"Version\"]").FillAsync(version); - - // Act - Click Refresh button - await page.Locator(@"h5:has-text(""Refresh Data Holders"") ~ div.card-body >> input:has-text(""Refresh"")").ClickAsync(); - - // Assert - Check refresh was successful - var footer = page.Locator(@"h5:has-text(""Refresh Data Holders"") ~ div.card-footer"); - var text = await footer.InnerTextAsync(); - if (expectedError != null) - { - text.Should().Be(expectedError); - } - else - { - if (expectedRecords != -1) // -1 = don't bother checking - { - text.Should().Be($"OK: {expectedRecords} data holder brands added. 0 data holder brands updated."); - } - } - } - - static protected async Task SSA_Get(IPage page, string industry, string version, string drBrandId, string drSoftwareProductId, string expectedMessage) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Get SSA").ClickAsync(); - await page.Locator("h2 >> text=Get Software Statement Assertion").TextContentAsync(); - - // Set version - await page.Locator("input[name=\"Version\"]").FillAsync(version); - // Set brandId - await page.Locator("input[name=\"BrandId\"]").FillAsync(drBrandId); - // Set softwareProductId - await page.Locator("input[name=\"SoftwareProductId\"]").FillAsync(drSoftwareProductId); - // Set industry - await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new[] { industry switch - { - // "" => "", // Doesn't work for clearing, use SelectOptionAsync(new SelectOptionValue[] { }) instead (see above) - "ALL" => "0", - "BANKING" => "1", - "ENERGY" => "2", - "TELCO" => "3", - _ => throw new ArgumentOutOfRangeException($"{nameof(industry)}") - }}); - - // Act - Click Refresh button - await page.Locator(@"h5:has-text(""Get SSA"") ~ div.card-body >> input:has-text(""Get SSA"")").ClickAsync(); - - // Assert - Check refresh was successful, card-footer should be showing OK - SSA Generated - var footer = page.Locator(@"h5:has-text(""Get SSA"") ~ div.card-footer"); - var text = await footer.InnerTextAsync(); - text.Should().StartWith(expectedMessage); - } - - // Create Client Registration returning DH client ID of client that was registered - static protected async Task ClientRegistration_Create(IPage page, - string dhBrandId, - string drBrandId, - string drSoftwareProductId, - string? jarmSigningAlgo = null, - string responseTypes = "code id_token", - string? jarmEncrypAlg = null, - string? jarmEncryptEnc = null) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Dynamic Client Registration").ClickAsync(); - await page.Locator("h2 >> text=Dynamic Client Registration").TextContentAsync(); - - // Set data holder brand id - await page.Locator("select[name=\"DataHolderBrandId\"]").SelectOptionAsync(new[] { dhBrandId }); - - // Assert - Check software product id - (await page.Locator("input[name=\"SoftwareProductId\"]").InputValueAsync()).Should().Be(drSoftwareProductId); - - await page.Locator("input[name=\"ResponseTypes\"]").FillAsync(responseTypes); - - if (jarmSigningAlgo != null) - { - await page.Locator("input[name=\"AuthorizationSignedResponseAlg\"]").FillAsync(jarmSigningAlgo); - } - if (jarmEncrypAlg != null) - { - await page.Locator("input[name=\"AuthorizationEncryptedResponseAlg\"]").FillAsync(jarmEncrypAlg); - } - if (jarmEncryptEnc != null) - { - await page.Locator("input[name=\"AuthorizationEncryptedResponseEnc\"]").FillAsync(jarmEncryptEnc); - } - - // Act - Click create button - await page.Locator(@"h5:has-text(""Create Client Registration"") ~ div.card-body >> input:has-text(""Register"")").ClickAsync(); - - // Assert - Check client was registered - await page.Locator(@"h5:has-text(""Create Client Registration"") ~ div.card-footer:has-text(""Created - Registered"")").TextContentAsync(); - - // Assert - Get json result - var json = await page.Locator(@"h5:has-text(""Create Client Registration"") ~ div.card-footer >> pre").InnerTextAsync(); - - // Deserialise response and return DH client id - DCRResponse dcrResponse = JsonConvert.DeserializeObject(json) ?? throw new NullReferenceException(nameof(json)); - return dcrResponse.ClientId ?? throw new NullReferenceException(nameof(dcrResponse.ClientId)); - } - - static protected async Task ConsentAndAuthorisation2(IPage page, string customerId = CUSTOMERID_BANKING, string customerAccounts = CUSTOMERACCOUNTS_BANKING) - { - - ConsentAndAuthorisationPages consentAndAuthorisationPages = new ConsentAndAuthorisationPages(page); - - await consentAndAuthorisationPages.EnterCustomerId(customerId); - await consentAndAuthorisationPages.ClickContinue(); - - await consentAndAuthorisationPages.EnterOtp("000789"); - await consentAndAuthorisationPages.ClickContinue(); - - await consentAndAuthorisationPages.SelectAccounts(customerAccounts); - await consentAndAuthorisationPages.ClickContinue(); - - await consentAndAuthorisationPages.ClickAuthorise(); - - // Assert - Check callback is shown and get arrangement ID - await page.Locator("text=Consent and Authorisation - Callback").TextContentAsync(); - - return new ConsentAndAuthorisationResponse - { - IDToken = await page.Locator(@"dt:has-text(""Id Token"") + dd ").TextContentAsync(), - AccessToken = await page.Locator(@"dt:has-text(""Access Token"") + dd ").TextContentAsync(), - RefreshToken = await page.Locator(@"dt:has-text(""Refresh Token"") + dd ").TextContentAsync(), - ExpiresIn = await page.Locator(@"dt:has-text(""Expires In"") + dd ").TextContentAsync(), - Scope = await page.Locator(@"dt:has-text(""Scope"") + dd ").TextContentAsync(), - TokenType = await page.Locator(@"dt:has-text("" Token Type"") + dd ").TextContentAsync(), - CDRArrangementID = await page.Locator(@"dt:has-text(""CDR Arrangement Id"") + dd ").TextContentAsync() - }; - } - - static protected async Task NewConsentAndAuthorisationWithPAR( - IPage page, - string dhClientId, - string customerId = CUSTOMERID_BANKING, - string customerAccounts = CUSTOMERACCOUNTS_BANKING, - string dhBrandId = DH_BRANDID) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - ParPage parPage = new ParPage(page); - await parPage.GotoPar(); - await parPage.CompleteParForm(dhClientId, dhBrandId, sharingDuration: SHARING_DURATION); - await parPage.ClickInitiatePar(); - await parPage.ClickAuthorizeUrl(); - - return await ConsentAndAuthorisation2(page, customerId, customerAccounts); - } - - private class DCRResponse - { - [JsonProperty("client_id")] - public string? ClientId { get; set; } - } - static protected async Task ClientRegistration_Delete(IPage page) - { - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Dynamic Client Registration").ClickAsync(); - await page.Locator("h2 >> text=Dynamic Client Registration").TextContentAsync(); - await page.Locator("text=Delete").ClickAsync(); - await page.Locator("text=No existing registrations found.").TextContentAsync(); - } - static protected async Task Consents_DeleteLocal(IPage page) - { - await TestInfo(page, "Delete (local)", "Delete Arrangement", "204"); - } - public static async Task TestInfo(IPage page, string menuText, string modalTitle, string expectedStatusCode, (string name, string? value)[]? expectedPayload = null) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Consents").ClickAsync(); - await page.Locator("h2 >> text=Consents").TextContentAsync(); - - // Act - Click actions button and submenu item - await page.Locator("button:has-text(\"Actions\")").ClickAsync(); - await page.Locator($"a >> text={menuText}").ClickAsync(); - - // Act - Check modal opens - await page.Locator($"div#modal-info >> h5.modal-title >> text={modalTitle}").TextContentAsync(); - - // Assert - Check statuscode - var statusCode = await page.Locator(@$"div#modal-info >> div.modal-statusCode >> text={expectedStatusCode}").TextContentAsync(); - statusCode.Should().Be(expectedStatusCode); - - // Assert - Check payload is what's expected - if (expectedPayload != null) - { - var payload = await page.Locator(@"div#modal-info >> pre.modal-payload").TextContentAsync(); - Assert_Json2(payload, expectedPayload); - } - } - public class ConsentAndAuthorisationResponse - { - public string? IDToken { get; init; } - public string? AccessToken { get; init; } - public string? RefreshToken { get; init; } - public string? ExpiresIn { get; init; } - public string? Scope { get; init; } - public string? TokenType { get; init; } - public string? CDRArrangementID { get; init; } - } - } -} \ No newline at end of file diff --git a/Source/CDR.DataRecipient.E2ETests/CDR.DataRecipient.E2ETests.csproj b/Source/CDR.DataRecipient.E2ETests/CDR.DataRecipient.E2ETests.csproj index cdbb80c..87bef6c 100644 --- a/Source/CDR.DataRecipient.E2ETests/CDR.DataRecipient.E2ETests.csproj +++ b/Source/CDR.DataRecipient.E2ETests/CDR.DataRecipient.E2ETests.csproj @@ -3,9 +3,9 @@ net6.0 false - 1.2.4 - 1.2.4 - 1.2.4 + 1.2.5 + 1.2.5 + 1.2.5 diff --git a/Source/CDR.DataRecipient.E2ETests/Fixtures/TestFixture.cs b/Source/CDR.DataRecipient.E2ETests/Fixtures/TestFixture.cs index 692aeb9..d289b17 100644 --- a/Source/CDR.DataRecipient.E2ETests/Fixtures/TestFixture.cs +++ b/Source/CDR.DataRecipient.E2ETests/Fixtures/TestFixture.cs @@ -12,7 +12,7 @@ public class TestFixture : IAsyncLifetime public Task InitializeAsync() { // Only install Playwright if not running in container, since Dockerfile.e2e-tests already installed Playwright - if (!BaseTest_v3.RUNNING_IN_CONTAINER) + if (!BaseTest.RUNNING_IN_CONTAINER) { // Ensure that Playwright has been fully installed. Microsoft.Playwright.Program.Main(new string[] { "install" }); diff --git a/Source/CDR.DataRecipient.E2ETests/Infrastructure/AccessToken.cs b/Source/CDR.DataRecipient.E2ETests/Infrastructure/AccessToken.cs index cfde5bb..72efdb8 100644 --- a/Source/CDR.DataRecipient.E2ETests/Infrastructure/AccessToken.cs +++ b/Source/CDR.DataRecipient.E2ETests/Infrastructure/AccessToken.cs @@ -14,7 +14,7 @@ namespace CDR.DataRecipient.E2ETests.Infrastructure { public class AccessToken { - private static readonly string IDENTITYSERVER_URL = BaseTest_v3.REGISTER_IDENTITYSERVER_URL; + private static readonly string IDENTITYSERVER_URL = BaseTest.REGISTER_IDENTITYSERVER_URL; private static readonly string AUDIENCE = IDENTITYSERVER_URL; private const string SCOPE = "cdr-register:bank:read"; private const string GRANT_TYPE = "client_credentials"; diff --git a/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests.cs b/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests.cs index 70625da..1549359 100644 --- a/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests.cs +++ b/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests.cs @@ -1,6 +1,4 @@ -#undef DEPRECATED // instead see US23863_MDR_E2ETests_v2 -#if DEPRECATED - +using CDR.DataRecipient.E2ETests.Pages; using FluentAssertions; using Microsoft.Data.SqlClient; using Microsoft.Playwright; @@ -16,24 +14,28 @@ public class US23863_MDR_E2ETests : BaseTest, IClassFixture { private const string SWAGGER_BANKING_IFRAME = "cds-banking/index.html"; private const string SWAGGER_ENERGY_IFRAME = "cds-energy/index.html"; - - private const string SHARING_DURATION = "100000"; + private const string SWAGGER_COMMON_IFRAME = "cds-common/index.html"; // Pre-generated ID Token used in IDTokenhelper test - const string IDTOKEN = @"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00iLCJraWQiOiJCNTQ4QzkxNEEwMjc4N0EzQjVGMTU1ODNDOEVCMDMwRDk0QkMyNDI1In0.biUv7OpkYyUYecHQ8x-XxyR77ZwCfCORY-MRLtoOYuoM5XrWm" + - "mqmuVD_1mFa88dvmkEeDPnK89cdzCFevV1u5xThXECMUHAMyBrxLgcp86DFqBtiB9g1UyvN1-1JgTX3719yl0tk5jqXvKW4iike-rtI-vZyeFtcZAp2ZrEXMo033cAEzW7gOKiZtoTY2GTmxgdtH5DqhCld0kNfII" + - "idpQ0vaKNVbV28K0sotUjSOGeN63vOtPb3JrcUorQ1kMqI4mTZDDSs8O97fqEqcnKsbvw65WOQk-T5uqPPycz2Q8BW_V1V0t8F19VMGB2rmHnFxVlBaWlm3NBdUnqFxWmYyw.EpLS7enX1zoeCYn5.cQ9dhezjgVE" + - "AzReklnAdUgcsCSMDhJ3GmriGD5gBqFveI4anjsupBMqd39OVhSdsJKh_w1Xz8rtY3OdeQPGLG_ZFlGdFLn3KMRRYrPx9i8lifXMYR2dxSDBDDfFblmmpGogrSqH5_O7e3kr4J9uRIVffGRHMZzajsg1ZqeSTiStI" + - "teGxxTVwnMSIUvsUpLLFN3wUZA7mlidtD1WhylRSbLHpw6h7OPKgELxUrl28FQd44vBNUnEBo73jpm1v0XvPwZI6JDZjoG4lFXg88SzOwnHX6B2xdWTDqrSkTboWw-tAJyPDYCzmufOx8c9UKp8FA7gLUNYqWBwTo" + - "jkOuj-xiqm9VkBFJ-MIFZcZiLAS5W2e2sE_td78CxroYK1iKpGr4CoHvvDrS-RhqiOWR7_lGmMOgGFxYZvFugr_iNYW69UPhMfKOBx_aGS6g_UBnNQfW10zhGNPFG3aacJ9JkDEC8HEBVddmbxCK2f_PBpzG65GXI" + - "kcFOHQlkoKgfHSFqcSDQvBte-hHgKuL-iFOoIaCTvytQ5SwAoqEmR_6O6_5GI_TyMV3h0ZtJOdAR0CBL6E5brmTYMgbpSJiQDJTaDTJBkLFrJxkgE1rDByXyO4hYGyq6ec8FHdr49c8Pe5w7hDZLMIzE2HGkXwK6B" + - "cxuu9pTXotJKzpCOlsjTRQRzHfvW-Jc7x6RAZO_9HdslTr_fY5addJscGuy7TOqXDvTBY-fsk8F3RbKb_ZekmfNVo1-v9MbtvszynF6bx3eXOVbdWmt-mxGijzf0_iKOJicvuddOjNZizTMgkcsceoxSnnm0rX1Ob" + - "SMAmyLr0uQYC8EZAiUuqZUyTsydCH4P9C3GgxYX_NkLacV92iEZTTqt4NajFJq5u3JwBTp2gA8p-cim6ncV82cQfNBW4Cuct2uQuRODiMsgwaMVAxTtUKV3tWz66BEh2fRWuwmJrgDKTo2KlVMH3GhBVUQg4zCo26" + - "ewTMWy8zJl7ehplYPDbtOJJB-yzz0lOfkE9r3s1izbzmcw7A3_ITw7U3dHmFApZyxX3lrR4hPg9bJNG6Vvr5CGL5snit3spe1nzujp1aY91lVIUTziBiyshnWhLjjcl341nPJPnQ9aw81nIx_3PAjoMT0O4Y338fD" + - "H-u34_gkCGyXUx4IWuf3okhRF4GIE4Hz-Dls4fgJSkhHYXGJcHiDauv8RdzbmzjBG_-grLvAlnHVb5pXHQNZz0aNKqu6YHFuEtlwXqvbOGejv_2DLB0csxiBLDHUfoQGZb0_OOaq3CPE6_q87K8gJlLfkqoVsrgbL" + - "o0hnzYCaP2rI6oB1PMMPNxeW4OuuSZYcs_GX0jiLwzt88gsoLoavbFsWl7arskUWN9XoIRieTJfFi1seY3zH-hVGVQC5ixPgJv45Q96LfpZZKV5lJPNOQHhqaoHOfHSb2jw-X-_drxzFB0bfGqnFQ32VC1xi_qnBG" + - "TB9U3T-pxeWnjaefeLxXDlQx7ZRPIni7Yf7sB3u4IoxfUNuORHL9OP1d_fljD_pd65xZEY-weNGJ8NhlFeMzf_e288dg44PD2xzkk5oAsh_qdn8HKV8PeBTaiUywYvQiQM3HGGJ6kd3TeB2UYmLFlCwsjONt_qJ7w" + - "dJ9KgyjWN6ypuCrbCZ9TGq6i0o3HjH6tNup6ltnYfquW1FPmyIeB_TEQ3GLsxJSAauomwJ9PljuEJlhZsh7Cllc8ack7R47UHbYXAYTR2VVt11PsAWrdeCoAQpjqQ.S6AhwkvWKyJ7Jz3nmp_PJg"; + const string IDTOKEN = @"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00iLCJraWQiOiJkYTNiYzA3OTlhMjlkODM2NWU2OWVkZjJiZmQxMzVh" + + "MDhjNGRkYmE3ZWM3ZTFiNmVhYjkzNWY5NjcyNWExZTNhIn0.afEh0qVHeHSYqu-Q-leao8EQe-cGR8m2-fszGZQOq0dBBQNGRaFwSTKn3u4KqGTXXI-w" + + "1p20YHe_JMH4k1B7_NG93YXpYsx1pfEc_qa5x7_9gYvN_X6NLESuxVQW3TJBgsmE-LMu6TjSZzXtt_HkKk0V-q5epsrWgYX-WWR4Jk-yAUEYxrqA-bGm" + + "EKLbY9rLbZaituis0E4fYP4SF9keL2H6iJ4h99F4MrEKz8K7HgsQ1SkrlFw9ApR3Wnl3NaLXsEcJJZqZcpXkHUaIA76UChG5tvZTV436Jyz_ehxbcQeK" + + "9Yx5ZhXWY2Ud9K0LZ3hQ3A0SdEGkhExGbUpiNecAGA.YtIsaDgqhifPIsRj.MHSYKFpgyc0opB0LqAQWxMaikTTc7dviOd4tSLInpQ8KwnrCHnVKJFJq" + + "2P6rFz26xorAFHtZZeeqG2RmAehMFWBxbWuSTLgmXqF1SmhVgAT6XHgPNBZE_KM4OE4FrYd2eMxbLSYVbGs1zcu8rxV_Fal74w_2qgVqiuR-8DgKLqkb" + + "dLrW0F7XXl_PtIZj4vWdwbon7SQldvk0usg5ZxqC5PeyrV2AYhu_0_VNRnwAxcbzvYdh9HxckrdYACUtcjcKi_VSPd9gw4urq58NnCSKghBD6rJvHqW1" + + "qdL32UTf-V58Ma9bRaItlUr_DOCFRp-vT7nBJwn3EDJWL_GE2QjOu6Zy-GNwv4p220Ct5GmqRVfgMXjZYOzZieBBHIU0AyXIohlF2PPC4NAXlgpFacna" + + "RKNZb3et6B9WsqEMlDhMajMeY1DWgQb0eSXrAtX4QidFucEirIhV2XwMFi60uoycuPbk2ziKCRQCdS-TiTCkrKH72GoR_8v27ddkPKF8cspqPNTmJdJi" + + "d84jyoWTgo7fMa3xf-Sa7OO9jNPuAChtpX3t9amyq-NQfoAlSRu5fUZcWgzxKcJbnHlWG71QH6ALF-4HyMML3brHlV1HoIybMyUKpCkz_qJ6uK0JQC90" + + "PMJ4f7hkFc5wZ_V4E6BOrX635SPVxk0ts4G2AVpi1nDfjajd_Ljg8ni1mE9PDuWdYap2hxRDJnmJ5XssR0FlMcWRPO3IJCjrdSmtMKxdePq3T_UEXK8C" + + "3sWs17k0URmlxnkjp6Qe6YSzAkALwgHyPCD9IqqnpFAXG88669fFWgCH7uMu9dyJI-Agwc3ufU1NAQRnknowj3DKp5DuhYL1AL-P4c8d7mlI5bpwee2c" + + "WxLQMDog4hp-FQMuir7IacY2lJ9Ocvoirf6yM-R5-lQka74poe2PGOu2QlrywvdHvJ-ExSNkT5mNAZPCPYT-eHVqdeV_aQCBu8bRD8nUeq5o6ZJMzOlr" + + "V3LDS9jyGKRVvQf7YyXHODPnTMeL78mgD_V4WSdme54-J_tnOQh-j9a58CH_7E6AlD6ahc27K1sA8hG-vZ_jRUG1QXhJfER5pQjCoPfEtWzGbJF58LYC" + + "piwR0KE15LtpJgKPBwbBFQwpBRcZDEtouBZLFyMjfNGg1cnTfdlblEtnZcE50_ZVjTfk3n1nNjRlYHceaGnd7GYINBNl87JZCd2Dn_-JmRJfKK2vnF17" + + "HA3dUOHz_rUJa6hQd77WwWDxwU7oG1bpmoRDjgjl1AxXmJVSuhkgyK6JEDgeF6SDPDsU1yym_9ACitE1FjS8VAqU3e8cgoaDD5BzASt9OmApsHQHRQur" + + "HOh05w_b63JHd3Cg_-ASojF78GjKQ2TWV-jZn65nacY5NSIU3Qxt87UbR7Cr64UZMJAhRQ0VoXmdHpG6dSjtYEP20HTgvTI7uQD8Ibw9C7jILUi76HO_" + + "-n3R2errngQrYNunYmW9q45eDdngOiA_N5HB3rS3y3-V3kYnkW8Wio-gSzuGYBoAM4OT5QFGbs7QYw0PR4wYDk7iVIkfCf5vDlVb2ehcfNQx2m5gYYuW" + + "ppVENCqtjrsUmAxmyPZ5v_Fvh8N36J-4IaKNcv9J3ic4mm0yUdCLVCRxBjpsfw.xPc7ZQDVN11iHX41af-wvg"; static string GetClientId() { @@ -49,53 +51,6 @@ static string GetClientId() return clientId; } - public class ConsentAndAuthorisationResponse - { - public string? IDToken { get; init; } - public string? AccessToken { get; init; } - public string? RefreshToken { get; init; } - public string? ExpiresIn { get; init; } - public string? Scope { get; init; } - public string? TokenType { get; init; } - public string? CDRArrangementID { get; init; } - } - - static async Task ConsentAndAuthorisation(IPage page, string customerId = CUSTOMERID_BANKING, string customerAccounts = CUSTOMERACCOUNTS_BANKING) - { - // Act - Enter Customer ID - await page.Locator("[placeholder=\"Your Customer ID\"]").FillAsync(customerId); - await page.Locator("text=Continue").ClickAsync(); - - // Act - Wait for OTP, then enter it, and click Continue - await Task.Delay(5000); - await page.Locator("[placeholder=\"Enter 6 digit One Time Password\"]").FillAsync("000789"); - await page.Locator("text=Continue").ClickAsync(); - - // Act - Select accounts - foreach (var customerAccount in customerAccounts.Split(',')) - { - await page.Locator($"text={customerAccount}").ClickAsync(); - } - - // Act - Click Continue and I confirm - await page.Locator("text=Continue").ClickAsync(); - await page.Locator("text=I Confirm").ClickAsync(); - - // Assert - Check callback is shown and get arrangement ID - await page.Locator("text=Consent and Authorisation - Callback").TextContentAsync(); - - return new ConsentAndAuthorisationResponse - { - IDToken = await page.Locator(@"dt:has-text(""Id Token"") + dd ").TextContentAsync(), - AccessToken = await page.Locator(@"dt:has-text(""Access Token"") + dd ").TextContentAsync(), - RefreshToken = await page.Locator(@"dt:has-text(""Refresh Token"") + dd ").TextContentAsync(), - ExpiresIn = await page.Locator(@"dt:has-text(""Expires In"") + dd ").TextContentAsync(), - Scope = await page.Locator(@"dt:has-text(""Scope"") + dd ").TextContentAsync(), - TokenType = await page.Locator(@"dt:has-text("" Token Type"") + dd ").TextContentAsync(), - CDRArrangementID = await page.Locator(@"dt:has-text(""CDR Arrangement Id"") + dd ").TextContentAsync() - }; - } - public static async Task TestToken(IPage page, string menuText, string? expectedToken) { // Arrange - Goto home page, click menu button, check page loaded @@ -116,32 +71,6 @@ public static async Task TestToken(IPage page, string menuText, string? expected token.Should().Be(expectedToken); } - public static async Task TestInfo(IPage page, string menuText, string modalTitle, string expectedStatusCode, (string name, string? value)[]? expectedPayload = null) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Consents").ClickAsync(); - await page.Locator("h2 >> text=Consents").TextContentAsync(); - - // Act - Click actions button and submenu item - await page.Locator("button:has-text(\"Actions\")").ClickAsync(); - await page.Locator($"a >> text={menuText}").ClickAsync(); - - // Act - Check modal opens - await page.Locator($"div#modal-info >> h5.modal-title >> text={modalTitle}").TextContentAsync(); - - // Assert - Check statuscode - var statusCode = await page.Locator(@$"div#modal-info >> div.modal-statusCode >> text={expectedStatusCode}").TextContentAsync(); - statusCode.Should().Be(expectedStatusCode); - - // Assert - Check payload is what's expected - if (expectedPayload != null) - { - var payload = await page.Locator(@"div#modal-info >> pre.modal-payload").TextContentAsync(); - Assert_Json2(payload, expectedPayload); - } - } - static async Task TestResults(IPage page, string label, string? value = null) { // Check for label and value @@ -155,8 +84,6 @@ static async Task TestResults(IPage page, string label, string? value = null) [Fact] public async Task AC01_HomePage() { - await Arrange(async () => { }); - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC01_HomePage)}", async (page) => { // Act - Goto home page @@ -173,156 +100,81 @@ await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC01_HomePage)}", asy await page.Locator("a >> text=Discover Data Holders").TextContentAsync(); await page.Locator("a >> text=Get SSA").TextContentAsync(); await page.Locator("a >> text=Dynamic Client Registration").TextContentAsync(); - await page.Locator("a >> text=Consent and Authorisation").TextContentAsync(); await page.Locator("a >> text=Consents").TextContentAsync(); - await page.Locator("a >> text=Consumer Data Sharing - Banking").TextContentAsync(); - await page.Locator("a >> text=Consumer Data Sharing - Energy").TextContentAsync(); + await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Common\")").TextContentAsync(); + await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Banking\")").TextContentAsync(); + await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Energy\")").TextContentAsync(); await page.Locator("a >> text=PAR").TextContentAsync(); await page.Locator("span >> text=Utilities").TextContentAsync(); await page.Locator("a >> text=ID Token Helper").TextContentAsync(); await page.Locator("a >> text=Private Key JWT Generator").TextContentAsync(); + Assert.True(true); }); } - [Theory] - [InlineData("", "", null, "BadRequest - Bad Request")] - [InlineData("", "1", 32)] - [InlineData("", "2", null, "NotAcceptable - Not Acceptable")] - [InlineData("", "foo", null, "BadRequest - Bad Request")] - [InlineData("Banking", "", null, "BadRequest - Bad Request")] - [InlineData("Banking", "1", 30)] - [InlineData("Banking", "2", null, "NotAcceptable - Not Acceptable")] - [InlineData("Banking", "foo", null, "BadRequest - Bad Request")] - [InlineData("Energy", "", null, "BadRequest - Bad Request")] - [InlineData("Energy", "1", 2)] - [InlineData("Energy", "2", null, "NotAcceptable - Not Acceptable")] - [InlineData("Energy", "foo", null, "BadRequest - Bad Request")] - [InlineData("Telco", "", null, "BadRequest - Bad Request")] - [InlineData("Telco", "1", 0)] - [InlineData("Telco", "2", null, "NotAcceptable - Not Acceptable")] - [InlineData("Telco", "foo", null, "BadRequest - Bad Request")] - public async Task AC02_DiscoverDataHolders(string industry = "", string version = "1", int? expectedRecords = 32, string? expectedError = null) + [Fact] + public async Task AC02_01_DiscoverDataHolders_Banking() { - await Arrange(async () => { }); - - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC02_DiscoverDataHolders)} - Industry={industry} - Version={version}", async (page) => + await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC02_01_DiscoverDataHolders_Banking)}", async (page) => { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Discover Data Holders").ClickAsync(); - await page.Locator("h2 >> text=Discover Data Holders").TextContentAsync(); - - // Set industry - if (String.IsNullOrEmpty(industry)) // Clear industry - await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new SelectOptionValue[] { }); - else - await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new[] { industry switch - { - // "" => "", // Doesn't work for clearing, use SelectOptionAsync(new SelectOptionValue[] { }) instead (see above) - "Banking" => "0", - "Energy" => "1", - "Telco" => "2", - _ => throw new ArgumentOutOfRangeException($"{nameof(industry)}") - }}); - - // Set version - await page.Locator("input[name=\"Version\"]").FillAsync(version); - - // Act - Click Refresh button - await page.Locator(@"h5:has-text(""Refresh Data Holders"") ~ div.card-body >> input:has-text(""Refresh"")").ClickAsync(); - - // Assert - Check refresh was successful - var footer = page.Locator(@"h5:has-text(""Refresh Data Holders"") ~ div.card-footer"); - var text = await footer.InnerTextAsync(); - if (expectedError != null) - { - text.Should().Be(expectedError); - } - else - { - text.Should().Be($"OK - {expectedRecords} data holder brands loaded."); - } + await DataHolders_Discover(page, "BANKING", "2", 30); }); } [Fact] - public async Task AC02_DiscoverDataHolders_MultipleAttempts() + public async Task AC02_02_DiscoverDataHolders_Energy() { - await Arrange(async () => { }); - - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC02_DiscoverDataHolders_MultipleAttempts)}", async (page) => + await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC02_02_DiscoverDataHolders_Energy)}", async (page) => { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Discover Data Holders").ClickAsync(); - await page.Locator("h2 >> text=Discover Data Holders").TextContentAsync(); - - // Act/Assert - await Test(page, "Banking", 30); - await Test(page, "Energy", 2); - await Test(page, "Banking", 30); + await DataHolders_Discover(page, "ENERGY", "2", 2); }); + } - static async Task Test(IPage page, string industry, int expectedRecords) + [Fact] + public async Task AC02_03_DiscoverDataHolders_Telco() + { + await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC02_03_DiscoverDataHolders_Telco)}", async (page) => { - // Arrange - if (String.IsNullOrEmpty(industry)) // Clear industry - await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new SelectOptionValue[] { }); - else - await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new[] { industry switch - { - "Banking" => "0", - "Energy" => "1", - "Telco" => "2", - _ => throw new ArgumentOutOfRangeException($"{nameof(industry)}") - }}); - - // Set version - await page.Locator("input[name=\"Version\"]").FillAsync("1"); - - // Act - Click Refresh button - await page.Locator(@"h5:has-text(""Refresh Data Holders"") ~ div.card-body >> input:has-text(""Refresh"")").ClickAsync(); - - // Assert - Check refresh was successful - var footer = page.Locator(@"h5:has-text(""Refresh Data Holders"") ~ div.card-footer"); - var text = await footer.InnerTextAsync(); - text.Should().Be($"OK - {expectedRecords} data holder brands loaded."); - } + await DataHolders_Discover(page, "TELCO", "2", 0); // Currently no Telco dataholders, so 0 = no additional dataholders loaded + }); } + [Fact] + public async Task AC02_04_DiscoverDataHolders_AnyIndustry() + { + await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC02_04_DiscoverDataHolders_AnyIndustry)}", async (page) => + { + await DataHolders_Discover(page, "ALL", "2", 0); // Should have loaded all dataholders by now, so 0 = no additional dataholders loaded + }); + } [Theory] - [InlineData("", DR_BRANDID, DR_SOFTWAREPRODUCTID, "BadRequest")] - [InlineData("1", DR_BRANDID, DR_SOFTWAREPRODUCTID, "OK - SSA Generated")] - [InlineData("2", DR_BRANDID, DR_SOFTWAREPRODUCTID, "NotAcceptable")] - public async Task AC03_GetSSA(string version = "1", string drBrandId = DR_BRANDID, string drSoftwareProductId = DR_SOFTWAREPRODUCTID, string expectedMessage = "OK - SSA Generated") + [InlineData("ALL", "3", null, "NotAcceptable - Not Acceptable")] + [InlineData("ALL", "foo", null, "BadRequest - Bad Request")] + [InlineData("BANKING", "3", null, "NotAcceptable - Not Acceptable")] + [InlineData("BANKING", "foo", null, "BadRequest - Bad Request")] + [InlineData("ENERGY", "3", null, "NotAcceptable - Not Acceptable")] + [InlineData("ENERGY", "foo", null, "BadRequest - Bad Request")] + [InlineData("TELCO", "3", null, "NotAcceptable - Not Acceptable")] + [InlineData("TELCO", "foo", null, "BadRequest - Bad Request")] + public async Task AC02_99_DiscoverDataHolders(string industry = "ALL", string version = "2", int? expectedRecords = 32, string? expectedError = null) { - await Arrange(async () => + await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC02_99_DiscoverDataHolders)} - Industry={industry} - Version={version}", async (page) => { - await AC02_DiscoverDataHolders(); + await DataHolders_Discover(page, industry, version, expectedRecords, expectedError); }); + } + [Theory] + [InlineData("BANKING", "1", DR_BRANDID, DR_SOFTWAREPRODUCTID, "NotAcceptable")] + [InlineData("BANKING", "2", DR_BRANDID, DR_SOFTWAREPRODUCTID, "NotAcceptable")] + [InlineData("BANKING", "3", DR_BRANDID, DR_SOFTWAREPRODUCTID, "OK - SSA Generated")] + [InlineData("BANKING", "4", DR_BRANDID, DR_SOFTWAREPRODUCTID, "NotAcceptable")] + public async Task AC03_GetSSA(string industry, string version, string drBrandId, string drSoftwareProductId, string expectedMessage) + { await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC03_GetSSA)} - Version={version} - DR_BrandId={drBrandId} - DR_SoftwareProductId={drSoftwareProductId}", async (page) => { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Get SSA").ClickAsync(); - await page.Locator("h2 >> text=Get Software Statement Assertion").TextContentAsync(); - - // Set version - await page.Locator("input[name=\"Version\"]").FillAsync(version); - // Set brandId - await page.Locator("input[name=\"BrandId\"]").FillAsync(drBrandId); - // Set softwareProductId - await page.Locator("input[name=\"SoftwareProductId\"]").FillAsync(drSoftwareProductId); - - // Act - Click Refresh button - await page.Locator(@"h5:has-text(""Get SSA"") ~ div.card-body >> input:has-text(""Get SSA"")").ClickAsync(); - - // Assert - Check refresh was successful, card-footer should be showing OK - SSA Generated - var footer = page.Locator(@"h5:has-text(""Get SSA"") ~ div.card-footer"); - var text = await footer.InnerTextAsync(); - text.Should().StartWith(expectedMessage); + await SSA_Get(page, industry, version, drBrandId, drSoftwareProductId, expectedMessage); }); } @@ -331,217 +183,108 @@ await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC03_GetSSA)} - Versi [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID)] // Also test for Energy DH public async Task AC04_DynamicClientRegistration(string dhBrandId = DH_BRANDID, string drBrandId = DR_BRANDID, string drSoftwareProductId = DR_SOFTWAREPRODUCTID) { - await Arrange(async () => - { - await AC02_DiscoverDataHolders(); - await AC03_GetSSA("1", drBrandId, drSoftwareProductId); - }); - + string testName = $"{nameof(US23863_MDR_E2ETests)} - {nameof(AC04_DynamicClientRegistration)} - DH_BrandId={dhBrandId} - DR_BrandId={drBrandId} - DR_SoftwareProductId={drSoftwareProductId}"; try { - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC04_DynamicClientRegistration)} - DH_BrandId={dhBrandId} - DR_BrandId={drBrandId} - DR_SoftwareProductId={drSoftwareProductId}", async (page) => + await ArrangeAsync(testName, async (page) => { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Dynamic Client Registration").ClickAsync(); - await page.Locator("h2 >> text=Dynamic Client Registration").TextContentAsync(); - - // Set data holder brand id - await page.Locator("select[name=\"DataHolderBrandId\"]").SelectOptionAsync(new[] { dhBrandId }); - - // Assert - Check software product id - (await page.Locator("input[name=\"SoftwareProductId\"]").InputValueAsync()).Should().Be(drSoftwareProductId); - - // Act - Click Refresh button - await page.Locator(@"h5:has-text(""Create Client Registration"") ~ div.card-body >> input:has-text(""Register"")").ClickAsync(); ; + await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands + await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); + }); - // Assert - Check refresh was successful, card-footer should be showing OK etc - var footer = page.Locator(@"h5:has-text(""Create Client Registration"") ~ div.card-footer"); - var text = await footer.InnerTextAsync(); - text.Should().StartWith("Created - Registered"); + await TestAsync(testName, async (page) => + { + await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId); }); } finally { await CleanupAsync(async (page) => { - await DeleteDCR(page); + try { await ClientRegistration_Delete(page); } catch { }; }); } } - // Delete the DCR via UI since just clearing the table in arrangement doesn't seem to work (web client must be caching the DCR??) - private static async Task DeleteDCR(IPage page) + public delegate Task ConsentsDelegate(IPage page, ConsentAndAuthorisationResponse response); + public async Task Test_Consents(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts, string testName, ConsentsDelegate test) { - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Dynamic Client Registration").ClickAsync(); - await page.Locator("h2 >> text=Dynamic Client Registration").TextContentAsync(); - await page.Locator("text=Delete").ClickAsync(); - await page.Locator("text=No existing registrations found.").TextContentAsync(); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC05_ConsentAndAuthorisation( - string dhBrandId = DH_BRANDID, - string drBrandId = DR_BRANDID, - string drSoftwareProductId = DR_SOFTWAREPRODUCTID, - string customerId = CUSTOMERID_BANKING, - string customerAccounts = CUSTOMERACCOUNTS_BANKING) - { - await Arrange(async () => - { - await AC02_DiscoverDataHolders(); - await AC03_GetSSA("1", drBrandId, drSoftwareProductId); - await AC04_DynamicClientRegistration(dhBrandId, drBrandId, drSoftwareProductId); - }); - try { - ConsentAndAuthorisationResponse? res = null; - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC05_ConsentAndAuthorisation)} - DH_BrandId={dhBrandId}", async (page) => + string? dhClientId = null; + ConsentAndAuthorisationResponse? cdrArrangement = null; + await ArrangeAsync($"{testName} - DH_BrandId={dhBrandId}", async (page) => { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("text=Consent and Authorisation").ClickAsync(); - await page.Locator("h2 >> text=Consent and Authorisation").TextContentAsync(); - - // Arrange - Set Client ID - await page.Locator("select[name=\"ClientId\"]").SelectOptionAsync(new[] { GetClientId() }); - await page.Locator("select[name=\"ClientId\"]").ClickAsync(); // there is JS that runs on the click event, so simulate click here - await Task.Delay(2000); + await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands + await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); + dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) + ?? throw new NullReferenceException(nameof(dhClientId)); + cdrArrangement = await NewConsentAndAuthorisationWithPAR(page, dhClientId, customerId, customerAccounts, dhBrandId) + ?? throw new NullReferenceException(nameof(cdrArrangement)); - // Arrange - Set Sharing Duration - await page.Locator("input[name=\"SharingDuration\"]").FillAsync(SHARING_DURATION); - // Arrange - Click Construct Authoriation URI button - await page.Locator("text=Construct Authorisation Uri").ClickAsync(); - - // Act - Click Authorisation URI link - await page.Locator("p.results > a").ClickAsync(); - - // Act/Assert - Perform consent and authorisation - res = await ConsentAndAuthorisation(page, customerId, customerAccounts); }); - return res ?? throw new ArgumentNullException($"Expected {nameof(ConsentAndAuthorisationResponse)}"); - } - finally - { - await CleanupAsync(async (page) => + await TestAsync($"{testName} - DH_BrandId={dhBrandId}", async (page) => { - await DeleteDCR(page); - }); - } - } - - [Fact] - public async Task AC06_Consents_ViewIDToken() - { - ConsentAndAuthorisationResponse? response = null; - - await Arrange(async () => - { - await AC02_DiscoverDataHolders(); - await AC03_GetSSA(); - await AC04_DynamicClientRegistration(); - response = await AC05_ConsentAndAuthorisation(); - }); - - try - { - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_ViewIDToken)}", async (page) => - { - await TestToken(page, "View ID Token", response?.IDToken ?? throw new ArgumentNullException()); + await test(page, cdrArrangement ?? throw new NullReferenceException(nameof(cdrArrangement))); }); } finally { await CleanupAsync(async (page) => { - await DeleteDCR(page); + try { await ClientRegistration_Delete(page); } catch { }; }); } } - [Fact] - public async Task AC06_Consents_ViewAccessToken() + [Theory] + [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] + [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH + public async Task AC06_Consents_ViewIDToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) { - ConsentAndAuthorisationResponse? response = null; - - await Arrange(async () => + await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_ViewIDToken)}", async (page, response) => { - await AC02_DiscoverDataHolders(); - await AC03_GetSSA(); - await AC04_DynamicClientRegistration(); - response = await AC05_ConsentAndAuthorisation(); + await TestToken(page, "View ID Token", response?.IDToken ?? throw new ArgumentNullException(nameof(response.IDToken))); }); - - try - { - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_ViewAccessToken)}", async (page) => - { - await TestToken(page, "View Access Token", response?.AccessToken ?? throw new ArgumentNullException()); - }); - } - finally - { - await CleanupAsync(async (page) => - { - await DeleteDCR(page); - }); - } } - [Fact] - public async Task AC06_Consents_ViewRefreshToken() + [Theory] + [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] + [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH + public async Task AC06_Consents_ViewAccessToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) { - ConsentAndAuthorisationResponse? response = null; - - await Arrange(async () => + await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_ViewAccessToken)}", async (page, response) => { - await AC02_DiscoverDataHolders(); - await AC03_GetSSA(); - await AC04_DynamicClientRegistration(); - response = await AC05_ConsentAndAuthorisation(); + await TestToken(page, "View Access Token", response?.AccessToken ?? throw new ArgumentNullException(nameof(response.AccessToken))); }); - - try - { - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_ViewRefreshToken)}", async (page) => - { - await TestToken(page, "View Refresh Token", response?.RefreshToken ?? throw new ArgumentNullException()); - }); - } - finally - { - await CleanupAsync(async (page) => - { - await DeleteDCR(page); - }); - } } - [Fact] - public async Task AC06_Consents_ViewUserInfo() + [Theory] + [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] + [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH + public async Task AC06_Consents_ViewRefreshToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) { - await Arrange(async () => + await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_ViewRefreshToken)}", async (page, response) => { - await AC02_DiscoverDataHolders(); - await AC03_GetSSA(); - await AC04_DynamicClientRegistration(); - await AC05_ConsentAndAuthorisation(); + await TestToken(page, "View Refresh Token", response?.RefreshToken ?? throw new ArgumentNullException(nameof(response.RefreshToken))); }); + } - try + [Theory] + [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING, "Jane", "Wilson")] + [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY, "Mary", "Moss")] // Also test for Energy DH + public async Task AC06_Consents_ViewUserInfo(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts, string expectedGivenName, string expectedFamilyName) + { + await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_ViewUserInfo)}", async (page, response) => { await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_ViewUserInfo)}", async (page) => { var expected = new (string, string?)[] { - ("given_name", "Jane"), - ("family_name", "Wilson"), - ("name", "Jane Wilson"), + ("given_name", expectedGivenName), + ("family_name", expectedFamilyName), + ("name", $"{expectedGivenName} {expectedFamilyName}"), ("aud", ASSERT_JSON2_ANYVALUE), ("iss", ASSERT_JSON2_ANYVALUE), ("sub", ASSERT_JSON2_ANYVALUE), @@ -549,249 +292,222 @@ await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_ViewUse await TestInfo(page, "UserInfo", "User Info", "200", expected); }); - } - finally - { - await CleanupAsync(async (page) => - { - await DeleteDCR(page); - }); - } + }); } - [Fact] - public async Task AC06_Consents_Introspect() + [Theory] + [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] + [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH + public async Task AC06_Consents_Introspect(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) { - ConsentAndAuthorisationResponse? response = null; - - await Arrange(async () => - { - await AC02_DiscoverDataHolders(); - await AC03_GetSSA(); - await AC04_DynamicClientRegistration(); - response = await AC05_ConsentAndAuthorisation(); - }); - - try + await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_Introspect)}", async (page, response) => { - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_Introspect)}", async (page) => + var expected = new (string, string?)[] { - var expected = new (string, string?)[] - { - ("cdr_arrangement_id", response?.CDRArrangementID ?? throw new ArgumentNullException()), + ("cdr_arrangement_id", response?.CDRArrangementID ?? throw new ArgumentNullException(nameof(response.CDRArrangementID))), ("scope", ASSERT_JSON2_ANYVALUE), ("exp", ASSERT_JSON2_ANYVALUE), ("active", "True"), - }; + }; - await TestInfo(page, "Introspect", "Introspection", "200", expected); - }); - } - finally - { - await CleanupAsync(async (page) => - { - await DeleteDCR(page); - }); - } + await TestInfo(page, "Introspect", "Introspection", "200", expected); + }); } - [Fact] - public async Task AC06_Consents_Refresh_Access_Token() + [Theory] + [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING, + "openid profile common:customer.basic:read common:customer.detail:read bank:accounts.basic:read bank:accounts.detail:read bank:transactions:read bank:regular_payments:read bank:payees:read")] + [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY, + "openid profile common:customer.basic:read common:customer.detail:read energy:accounts.basic:read energy:accounts.detail:read energy:accounts.concessions:read energy:accounts.paymentschedule:read energy:billing:read energy:electricity.servicepoints.basic:read energy:electricity.servicepoints.detail:read energy:electricity.der:read energy:electricity.usage:read")] // Also test for Energy DH + public async Task AC06_Consents_Refresh_Access_Token(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts, string expectedScope) { - await Arrange(async () => - { - await AC02_DiscoverDataHolders(); - await AC03_GetSSA(); - await AC04_DynamicClientRegistration(); - await AC05_ConsentAndAuthorisation(); - }); - - try + await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_Refresh_Access_Token)}", async (page, response) => { - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_Refresh_Access_Token)}", async (page) => + var expected = new (string, string?)[] { - var expected = new (string, string?)[] - { ("id_token", ASSERT_JSON2_ANYVALUE), ("access_token", ASSERT_JSON2_ANYVALUE), ("refresh_token", ASSERT_JSON2_ANYVALUE), ("expires_in", ACCESSTOKENLIFETIMESECONDS), ("token_type", "Bearer"), - ("scope", "openid profile cdr:registration bank:accounts.basic:read bank:transactions:read common:customer.basic:read"), + ("scope", expectedScope), ("cdr_arrangement_id", ASSERT_JSON2_ANYVALUE), - }; + }; - await TestInfo(page, "Refresh Access Token", "Refresh Access Token", "200", expected); - }); - } - finally - { - await CleanupAsync(async (page) => - { - await DeleteDCR(page); - }); - } + await TestInfo(page, "Refresh Access Token", "Refresh Access Token", "200", expected); + }); } - [Fact] - public async Task AC06_Consents_Revoke_Arrangement() + [Theory] + [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] + [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH + public async Task AC06_Consents_Revoke_Arrangement(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) { - await Arrange(async () => - { - await AC02_DiscoverDataHolders(); - await AC03_GetSSA(); - await AC04_DynamicClientRegistration(); - await AC05_ConsentAndAuthorisation(); - }); - - try + await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_Revoke_Arrangement)}", async (page, response) => { - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_Revoke_Arrangement)}", async (page) => - { - await TestInfo(page, "Revoke Arrangement", "Revoke Arrangement", "204"); - await ScreenshotAsync(page, "-Modal"); + await TestInfo(page, "Revoke Arrangement", "Revoke Arrangement", "204"); + await ScreenshotAsync(page, "-Modal"); - await page.Locator("div#modal-info >> div.modal-footer >> a >> text=Refresh Page").ClickAsync(); - }); - } - finally - { - await CleanupAsync(async (page) => - { - await DeleteDCR(page); - }); - } + await page.Locator("div#modal-info >> div.modal-footer >> a >> text=Refresh Page").ClickAsync(); + }); } - [Fact] - public async Task AC06_Consents_Revoke_AccessToken() + [Theory] + [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] + [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH + public async Task AC06_Consents_Revoke_AccessToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) { - await Arrange(async () => + await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_Revoke_AccessToken)}", async (page, response) => { - await AC02_DiscoverDataHolders(); - await AC03_GetSSA(); - await AC04_DynamicClientRegistration(); - await AC05_ConsentAndAuthorisation(); + await TestInfo(page, "Revoke Access Token", "Revoke Access Token", "200"); }); + } - try - { - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_Revoke_AccessToken)}", async (page) => - { - await TestInfo(page, "Revoke Access Token", "Revoke Access Token", "200"); - }); - } - finally + [Theory] + [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] + [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH + public async Task AC06_Consents_Revoke_RefreshToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) + { + await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_Revoke_RefreshToken)}", async (page, response) => { - await CleanupAsync(async (page) => - { - await DeleteDCR(page); - }); - } + await TestInfo(page, "Revoke Refresh Token", "Revoke Refresh Token", "200"); + }); } - [Fact] - public async Task AC06_Consents_Revoke_RefreshToken() + [Theory] + [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] + [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH + public async Task AC06_Consents_Delete_Local(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) { - await Arrange(async () => + await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_Delete_Local)}", async (page, response) => { - await AC02_DiscoverDataHolders(); - await AC03_GetSSA(); - await AC04_DynamicClientRegistration(); - await AC05_ConsentAndAuthorisation(); + await Consents_DeleteLocal(page); }); + } + [Theory] + [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] + [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH + public async Task AC07_PAR(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) + { try { - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_Revoke_RefreshToken)}", async (page) => + string testName = $"{nameof(US23863_MDR_E2ETests)} - {nameof(AC07_PAR)}"; + string? dhClientId = null; + ConsentAndAuthorisationResponse? cdrArrangement = null; + await ArrangeAsync(testName, async (page) => + { + await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands + await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); + dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) + ?? throw new NullReferenceException(nameof(dhClientId)); + cdrArrangement = await NewConsentAndAuthorisationWithPAR(page, dhClientId, customerId, customerAccounts, dhBrandId) + ?? throw new NullReferenceException(nameof(cdrArrangement)); + }); + + await TestAsync(testName, async (page) => { - await TestInfo(page, "Revoke Refresh Token", "Revoke Refresh Token", "200"); + // Arrange - Goto home page, click menu button, check page loaded + await page.GotoAsync(WEB_URL); + ParPage parPage = new ParPage(page); + await parPage.GotoPar(); + await parPage.CompleteParForm(dhClientId, dhBrandId, cdrArrangement: cdrArrangement!.CDRArrangementID, sharingDuration: SHARING_DURATION); + await parPage.ClickInitiatePar(); + await parPage.ClickAuthorizeUrl(); + + // Act/Assert - Perform consent and authorisation + await ConsentAndAuthorisation2(page, customerId, customerAccounts); }); } finally { await CleanupAsync(async (page) => { - await DeleteDCR(page); + try { await ClientRegistration_Delete(page); } catch { }; }); } } - [Fact] - public async Task AC06_Consents_Delete_Local() + [Theory] + [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] + public async Task AC08_ConsumerDataSharing_Banking(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) { - await Arrange(async () => - { - await AC02_DiscoverDataHolders(); - await AC03_GetSSA(); - await AC04_DynamicClientRegistration(); - await AC05_ConsentAndAuthorisation(); - }); - try { - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC06_Consents_Delete_Local)}", async (page) => + string testName = $"{nameof(US23863_MDR_E2ETests)} - {nameof(AC08_ConsumerDataSharing_Banking)}"; + string? dhClientId = null; + ConsentAndAuthorisationResponse? cdrArrangement = null; + await ArrangeAsync(testName, async (page) => { - await TestInfo(page, "Delete (local)", "Delete Arrangement", "204"); + await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands + await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); + dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) + ?? throw new NullReferenceException(nameof(dhClientId)); + cdrArrangement = await NewConsentAndAuthorisationWithPAR(page, dhClientId, customerId, customerAccounts, dhBrandId) + ?? throw new NullReferenceException(nameof(cdrArrangement)); + }); + + await TestAsync(testName, async (page) => + { + // Arrange - Goto home page, click menu button, check page loaded + await page.GotoAsync(WEB_URL); + await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Banking\")").ClickAsync(); + await page.Locator("h2 >> text=Data Sharing - Banking").TextContentAsync(); + await Task.Delay(2000); // give screen time to refresh }); } finally { await CleanupAsync(async (page) => { - await DeleteDCR(page); + try { await ClientRegistration_Delete(page); } catch { }; }); } } - [Fact] - public async Task AC07_ConsumerDataSharing_Banking() - { - await Arrange(async () => { }); - - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC07_ConsumerDataSharing_Banking)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Consumer Data Sharing - Banking").ClickAsync(); - await page.Locator("h2 >> text=Data Sharing - Banking").TextContentAsync(); - await Task.Delay(2000); - }); - } - - [Fact] - public async Task AC07_ConsumerDataSharing_Banking_AccountsGet() + [Theory] + [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] + public async Task AC08_ConsumerDataSharing_Banking_AccountsGet(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) { - string? cdrArrangementId = null; - - await Arrange(async () => - { - await AC02_DiscoverDataHolders(); - await AC03_GetSSA(); - await AC04_DynamicClientRegistration(); - cdrArrangementId = (await AC05_ConsentAndAuthorisation()).CDRArrangementID; - }); - try { - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC07_ConsumerDataSharing_Banking_AccountsGet)}", async (page) => + string testName = $"{nameof(US23863_MDR_E2ETests)} - {nameof(AC08_ConsumerDataSharing_Banking_AccountsGet)}"; + string? dhClientId = null; + ConsentAndAuthorisationResponse? cdrArrangement = null; + await ArrangeAsync(testName, async (page) => + { + await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands + await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); + dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) + ?? throw new NullReferenceException(nameof(dhClientId)); + cdrArrangement = await NewConsentAndAuthorisationWithPAR(page, dhClientId, customerId, customerAccounts, dhBrandId) + ?? throw new NullReferenceException(nameof(cdrArrangement)); + }); + + await TestAsync(testName, async (page) => { // Arrange - Goto home page, click menu button, check page loaded await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Consumer Data Sharing - Banking").ClickAsync(); + await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Banking\")").ClickAsync(); await page.Locator("h2 >> text=Data Sharing - Banking").TextContentAsync(); // Arrange - Get Swagger iframe var iFrame = page.FrameByUrl($"{WEB_URL}/{SWAGGER_BANKING_IFRAME}") ?? throw new Exception($"IFrame not found - {SWAGGER_BANKING_IFRAME}"); + // Wait for the CDR arrangement to be added and populated. + System.Threading.Thread.Sleep(10000); - // Act - Click request uri - await page.Locator("p.results > a").ClickAsync(); + // Arrange - Select CDR arrangemment + await iFrame.SelectOptionAsync( + "select", + new string[] { + cdrArrangement!.CDRArrangementID ?? throw new NullReferenceException(nameof(cdrArrangement.CDRArrangementID)) + }, + new FrameSelectOptionOptions() { Timeout = 90000 } + ); - // Act/Assert - Perform consent and authorisation - await ConsentAndAuthorisation(page, customerId, customerAccounts); + // Arrange - Click GET​/energy​/accountsGet Energy Accounts + await iFrame.ClickAsync("text=Energy GET/energy/plansGet Generic PlansGET/energy/plans/{planId}Get Generic Pla >> [aria-label=\"get ​\\/energy​\\/accounts\"]"); + + // Arrange - Click Try it out + await iFrame.ClickAsync("text=Try it out"); + + // Arrange - Set x-v + await iFrame.FillAsync("[placeholder=\"x-v\"]", "1"); + + // Act - Click Execute + await iFrame.ClickAsync("text=Execute"); + + // Assert - Status code should be 200 + var statusCode = await iFrame.Locator("div.responses-inner > div > div > table > tbody > tr > td.response-col_status").TextContentAsync(); + statusCode.Should().Be("200"); }); } finally { await CleanupAsync(async (page) => { - await DeleteDCR(page); + try { await ClientRegistration_Delete(page); } catch { }; }); } } @@ -904,8 +640,6 @@ await CleanupAsync(async (page) => [InlineData(IDTOKEN)] public async Task AC09_IDTokenHelper(string encryptedToken) { - await Arrange(async () => { }); - await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC09_IDTokenHelper)}", async (page) => { // Arrange - Goto home page, click menu button, check page loaded @@ -920,34 +654,29 @@ await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC09_IDTokenHelper)}" await page.Locator("text=Decrypt ID Token").ClickAsync(); // Assert - Check results - await TestResults(page, "nbf", "1635114387"); - await TestResults(page, "exp", "1635114687"); - // await TestResults(page, "iss", $"https://{BaseTest.HOSTNAME_DATAHOLDER}:8001"); - await TestResults(page, "iss", $"https://localhost:8001"); // token is const, it was created on localhost, we are just checking the decryption of token works and not where it was issued - await TestResults(page, "aud", "ffd1f415-a576-4e3e-9eab-1f732bbf55c6"); - await TestResults(page, "nonce", "38ff9cc4-57c4-404a-98ec-5e519336d419"); - await TestResults(page, "iat", "1635114387"); - await TestResults(page, "at_hash", "HPpIrSN5_JyYHYUfwp9LAA"); - await TestResults(page, "s_hash", "D0zlxPkG8fQvsfSB9hw36w"); - await TestResults(page, "auth_time", "1635114375"); - await TestResults(page, "idp", "local"); - await TestResults(page, "sharing_expires_at", "1635214377"); - await TestResults(page, "cdr_arrangement_id", "457e3e07-0fae-4441-ad44-0523f4bd13eb"); - await TestResults(page, "sub", "pJkPifkovXGjesboAo9+40W1e7nf2QHtXV0KZLjQTJsA8Oy03Q3CVJvGuvW/uY8p"); - await TestResults(page, "name", "Jane Wilson"); + await TestResults(page, "nbf", "1687210290"); + await TestResults(page, "exp", "1687210590"); + await TestResults(page, "iss", $"https://mock-data-holder:8001"); + await TestResults(page, "aud", "549076d1-785e-46c8-b1f4-8074e859c004"); + await TestResults(page, "nonce", "998c7257-8e42-4ef9-81cc-09d08eff413f"); + await TestResults(page, "iat", "1687210290"); + await TestResults(page, "at_hash", "wvmLTnV0mNAEeqVrmgvnuw"); + await TestResults(page, "c_hash", "fRr6y32yxRN257qQ9Rzlvw"); + await TestResults(page, "auth_time", "1687210289"); + await TestResults(page, "sub", "GYFWjFhkegCHsQe0KVvFhg=="); + await TestResults(page, "name", "jwilson"); await TestResults(page, "family_name", "Wilson"); await TestResults(page, "given_name", "Jane"); - await TestResults(page, "updated_at", "1624884401"); + await TestResults(page, "updated_at", "1687210290"); await TestResults(page, "acr", "urn:cds.au:cdr:2"); - await TestResults(page, "refresh_token_expires_at", "1635214377"); - await TestResults(page, "amr", "pwd"); + + Assert.True(true); }); } [Fact] public async Task AC10_PrivateKeyJWTGenerator() { - await Arrange(async () => { }); await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC10_PrivateKeyJWTGenerator)}", async (page) => { @@ -984,6 +713,7 @@ await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC11_Settings)}", asy await page.GotoAsync(WEB_URL); await page.Locator("a >> text=Settings").ClickAsync(); await page.Locator("h2 >> text=Settings").TextContentAsync(); + Assert.True(true); }); } @@ -996,9 +726,9 @@ await TestAsync($"{nameof(US23863_MDR_E2ETests)} - {nameof(AC12_About)}", async await page.GotoAsync(WEB_URL); await page.Locator("a >> text=About").ClickAsync(); await page.Locator("h2 >> text=About").TextContentAsync(); + Assert.True(true); }); } - } -} -#endif \ No newline at end of file + } +} \ No newline at end of file diff --git a/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests_v2.cs b/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests_v2.cs deleted file mode 100644 index 5590f35..0000000 --- a/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests_v2.cs +++ /dev/null @@ -1,1064 +0,0 @@ -#undef DEPRECATED // instead see US23863_MDR_E2ETests_v2 -#if DEPRECATED -using FluentAssertions; -using Microsoft.Data.SqlClient; -using Microsoft.Playwright; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Xunit; - -#nullable enable - -namespace CDR.DataRecipient.E2ETests -{ - public class US23863_MDR_E2ETests_v2 : BaseTest_v2, IClassFixture - { - private const string SWAGGER_BANKING_IFRAME = "cds-banking/index.html"; - private const string SWAGGER_ENERGY_IFRAME = "cds-energy/index.html"; - private const string SWAGGER_COMMON_IFRAME = "cds-common/index.html"; - - private const string SHARING_DURATION = "100000"; - - // Pre-generated ID Token used in IDTokenhelper test - const string IDTOKEN = @"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00iLCJraWQiOiJlMmM2ZWFmZjdmYWQwODFjNzhiMjJkNjNiYmI1N" + - "jdlODYwNzBlNTFlYjE0NzZhYmNhNmEyMzNiY2U4Y2ExNGJhIn0.fp9-2--a7mM70FsVL1c5MacViVkPcI-CZCGXyjV4F1T-RZuUsMaw9sCkjNrnE3" + - "LR9nnBOYploFXljRo6_ZkH5PJHtSfnoF8GRnJJHJ74dvJC3MqRsvGUl8uS5P2sEW2TexXQlhdKwFA3REM1khpVNAA1FZyFK3iv7IucipnL0UcO1H-" + - "23iBb7puOdEm6_3Sndu2ycACt5in-gO2UIWHFeaUDwLdr7iCBH4fzn5jupSJdyZ-9iU2ahOhf6iJFAwYM4R7CEPRTr8h8JqXBW3cqOcAktK0jScmv" + - "U3k2zOqtiwTxZ3yTwNEinSSvDxyxofKmiXsQDkgOzbJt6YPAq2c9gw.o-hgXFF8FzFUd1gY.NX-J0RWfE53KksdvhNK9pcXjXvLicaFO3N1N-ivAV" + - "G3HL_7k7f4L2d7B3Elh4UXiiV84xuS2wBltNT2XcOAEMZuJd6-e1Octuhzzc9o8pFQEtP-72vzpo6K6wbdSgFwqPNQ4xGJTArS2BCG1v_rfiUNqM7" + - "Y-igdsGImk3DoCBtsq-PWaWZgwj0d4ci5De4EkMpb3UZrk9UlZGGpgOH0rqGEPQEhO41M-7XeBw-cVqyGwaS6c3iwSUZHHCLgluZ-AfJ3ebfq9ya3" + - "u02de95C1YMhN04BA9Oj_tkTUA4XvyfXnxd_cXtjPUUjAo2Tvmc1YxU-tfNgwLgW3s2jFdkeJnHj7vwXzAbiAthIleD9D2LrYUN_vNWI0Lc570R1g" + - "GVXVFl_IfUMhZBSRYTl4z15NGdTwTopusNDVnOKQrKu5FsRWa0g1h80Fnmiw4sNRByFzxY_qziz67aUbJK1qz57FdBhHy85GkdK90Zd7kTuITYkPc" + - "c7_Srtu6ZHMWNRbUxvEHF_YHnTVWiH3DCiGYwrPCYEcXLutoY2A0nJGBAPsgCYnZ8_FvsQCsUno-PJyyWhjZ98mXcmtNIBOw5qArH7E520p586FtO" + - "JjS0zbRL7UjNxK2IcSB01-9WkWVxTxYrQnD8fzobnNPCf6esGGyPjU-PD-bstCQ1PUhA5OSg7MmBiTyRZYfvj59_rkhqdLovYCqyZLu9NbySLoFiq" + - "hnCXmmCROv6U_-KDW0-y30Uf9s_ke00l5kBSs9F4h8shDF5rXySL8HeAwNt_0JY4Q1pg6zu2PISuXVmcnizCZoCFaDTQ1ReQKHBfsDss7g680F6OY" + - "_UFxzYwxowIctfZzKQtT0q0J2xghgjPP-U47ng8VTQX2b_8TmMMWXiEvumxEb9gHp_i6246uHOeuiBu2LVGniAJkbTB2DHgICXgRYSd_pQTi7GBsu" + - "m4ZzQeVIVC7UKxc1OOHkLLypzPRK2bwOIg0SMZjnugCLbmQUyJxyB7ht5iA2psX-EavKeR-KjTqOWFSr5byOIbMUSLY44K0Al503u7NTvH5JVUH4y" + - "y6zI8sgiaQTcfAXo1YKhmHqJPf4VbQZRMTs3_2tdu5rNl-BSytbLnKrmFvL85RoKAq6wqE3Clk4BLJQ0CNoBvm-nObhzhQ_mhbXyRXn7A1vKEkf_p" + - "KHv3-dKBlX4-jdyFJAwd_HPqb6gtBFsKROlpQwlCxGbEV5GF2iN0az03r6RPveqxvkP4RpgfG8VaXvKyW9xi4lENVelt_Ep11BXHsrJGKupIaIdW" + - "IhUZu90VJYIezKKztLycPlxs7oOkEDTIfVrO1HeuEOHk1CCgxBiWtqZiKO2ELtE5mj2fee35fWFQ31muNiXBVD2DgHabnb_S0ZXHzY6MR368Rj0h" + - "xqxiDVc6ppQcVt02XYL4HLz4mBExyvy0F13OfuEkP5tWlaHkK8k90eISkn7aKcoMVV5JSFjqPasA_dY91Gbpq0itHDtaEIzgcOYWP-u8LUGJGLF4N" + - "qWkBfZUEGxgPIQ1ynRGwwUwnrh8xQSuvG_Phid0DGHm0Kxz_j0Vyvr60TpFoYNwGPH6vQ3bsiSs2JlxLuOdC-Kw6YVahxsGkE6b9ZKn9HiW6tmxj-" + - "CCf1u4tYiYxW48ceOcivydgT-mIKAdQeClTIbAJdJq4wY_936f5GWIJxM-wJ78qwFTN4R7zG4vINi2gd5000h4JjCaYTyX9v989Fzuq5SIkNHRb8E" + - "hSLcMA_3De7epFZCnImEhkKUQPHxwaW9kDBExy-sVJ2ku9EN6k4AZAM60lCMAdOGWwvOFN-pW9k9DBDmZTfg1kjfnbn4guIfw7lJKp2iy-0TGVhDD" + - "3MN3BTrucmURy6_kpXWRLGuLd3fEj-bQAwD4sMgLVe_GWh6f1TFo7hUfrNmwuXLjqtFMjMgWXbo8zM4VJDL6fCO_U0HZzXx3CGzxuSETWQxF9EeDG" + - "kSpwIdweEmFl1finL1g.gTClNE4BztTzJIpe8BcNRw"; - - static string GetClientId() - { - using var mdrConnection = new SqlConnection(BaseTest_v2.DATARECIPIENT_CONNECTIONSTRING); - mdrConnection.Open(); - - using var selectCommand = new SqlCommand($"select clientid from registration", mdrConnection); - string? clientId = Convert.ToString(selectCommand.ExecuteScalar()); - - if (String.IsNullOrEmpty(clientId)) - throw new Exception("No registrations found"); - - return clientId; - } - - public class ConsentAndAuthorisationResponse - { - public string? IDToken { get; init; } - public string? AccessToken { get; init; } - public string? RefreshToken { get; init; } - public string? ExpiresIn { get; init; } - public string? Scope { get; init; } - public string? TokenType { get; init; } - public string? CDRArrangementID { get; init; } - } - - static async Task ConsentAndAuthorisation2(IPage page, string customerId = CUSTOMERID_BANKING, string customerAccounts = CUSTOMERACCOUNTS_BANKING) - { - // Act - Enter Customer ID - await page.Locator("[placeholder=\"Your Customer ID\"]").FillAsync(customerId); - await page.Locator("text=Continue").ClickAsync(); - - // Act - Wait for OTP, then enter it, and click Continue - await Task.Delay(5000); - await page.Locator("[placeholder=\"Enter 6 digit One Time Password\"]").FillAsync("000789"); - await page.Locator("text=Continue").ClickAsync(); - - // Act - Select accounts - foreach (var customerAccount in customerAccounts.Split(',')) - { - await page.Locator($"text={customerAccount}").ClickAsync(); - } - - // Act - Click Continue and I confirm - await page.Locator("text=Continue").ClickAsync(); - await page.Locator("text=I Confirm").ClickAsync(); - - // Assert - Check callback is shown and get arrangement ID - await page.Locator("text=Consent and Authorisation - Callback").TextContentAsync(); - - return new ConsentAndAuthorisationResponse - { - IDToken = await page.Locator(@"dt:has-text(""Id Token"") + dd ").TextContentAsync(), - AccessToken = await page.Locator(@"dt:has-text(""Access Token"") + dd ").TextContentAsync(), - RefreshToken = await page.Locator(@"dt:has-text(""Refresh Token"") + dd ").TextContentAsync(), - ExpiresIn = await page.Locator(@"dt:has-text(""Expires In"") + dd ").TextContentAsync(), - Scope = await page.Locator(@"dt:has-text(""Scope"") + dd ").TextContentAsync(), - TokenType = await page.Locator(@"dt:has-text("" Token Type"") + dd ").TextContentAsync(), - CDRArrangementID = await page.Locator(@"dt:has-text(""CDR Arrangement Id"") + dd ").TextContentAsync() - }; - } - - static async Task NewConsentAndAuthorisationWithPAR( - IPage page, - string dhClientId, - string customerId = CUSTOMERID_BANKING, - string customerAccounts = CUSTOMERACCOUNTS_BANKING, - string dhBrandId = DH_BRANDID) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=PAR").ClickAsync(); - await page.Locator("h2 >> text=Pushed Authorisation Request (PAR)").TextContentAsync(); - - // Arrange - Set Client ID - await page.Locator("select[name=\"RegistrationId\"]").SelectOptionAsync(new[] { $"{dhClientId!}|||{dhBrandId}" }); - await page.Locator("select[name=\"RegistrationId\"]").ClickAsync(); // there is JS that runs on the click event, so simulate click here - await Task.Delay(2000); - // Arrange - Set CdrArrangementId - //await page.Locator("select[name=\"CdrArrangementId\"]").SelectOptionAsync(new[] { cdrArrangement!.CDRArrangementID ?? throw new NullReferenceException(nameof(cdrArrangement.CDRArrangementID)) }); - // Arrange - Set Sharing Duration - await page.Locator("input[name=\"SharingDuration\"]").FillAsync(SHARING_DURATION); - - // Act - Click Initiate PAR button - await page.Locator("div.form >> text=Initiate PAR").ClickAsync(); - - // Act - Click request uri - await page.Locator("p.results > a").ClickAsync(); - - return await ConsentAndAuthorisation2(page, customerId, customerAccounts); - } - - public static async Task TestToken(IPage page, string menuText, string? expectedToken) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Consents").ClickAsync(); - await page.Locator("h2 >> text=Consents").TextContentAsync(); - - // Act - Click actions button and submenu item - await page.Locator("button:has-text(\"Actions\")").ClickAsync(); - await page.Locator($"a >> text={menuText}").ClickAsync(); - - // Act - Check modal opens - await page.Locator("div#modal-token >> h5.modal-title >> text=Token Contents").TextContentAsync(); - - // Assert - Check actual token matches expected token - var token = await page.Locator(@"div#modal-token >> div.modal-body").TextContentAsync(); - token.Should().NotBeNullOrEmpty(); - token.Should().Be(expectedToken); - } - - public static async Task TestInfo(IPage page, string menuText, string modalTitle, string expectedStatusCode, (string name, string? value)[]? expectedPayload = null) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Consents").ClickAsync(); - await page.Locator("h2 >> text=Consents").TextContentAsync(); - - // Act - Click actions button and submenu item - await page.Locator("button:has-text(\"Actions\")").ClickAsync(); - await page.Locator($"a >> text={menuText}").ClickAsync(); - - // Act - Check modal opens - await page.Locator($"div#modal-info >> h5.modal-title >> text={modalTitle}").TextContentAsync(); - - // Assert - Check statuscode - var statusCode = await page.Locator(@$"div#modal-info >> div.modal-statusCode >> text={expectedStatusCode}").TextContentAsync(); - statusCode.Should().Be(expectedStatusCode); - - // Assert - Check payload is what's expected - if (expectedPayload != null) - { - var payload = await page.Locator(@"div#modal-info >> pre.modal-payload").TextContentAsync(); - Assert_Json2(payload, expectedPayload); - } - } - - static async Task TestResults(IPage page, string label, string? value = null) - { - // Check for label and value - if (value != null) - await page.Locator($"div.results >> dl >> dt:has-text(\"{label}\") + dd:has-text(\"{value}\")").TextContentAsync(); - // Just check for label - else - await page.Locator($"div.results >> dl >> dt:has-text(\"{label}\")").TextContentAsync(); - } - - [Fact] - public async Task AC01_HomePage() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC01_HomePage)}", async (page) => - { - // Act - Goto home page - await page.GotoAsync(WEB_URL); - - // Assert - Check banner - await page.Locator("h1 >> text=Mock Data Recipient").TextContentAsync(); - await page.Locator("text=Welcome to the Mock Data Recipient").TextContentAsync(); - await page.Locator("a >> text=Settings").TextContentAsync(); - await page.Locator("a >> text=About").TextContentAsync(); - - // Assert - Check menu items exists - await page.Locator("a >> text=Home").TextContentAsync(); - await page.Locator("a >> text=Discover Data Holders").TextContentAsync(); - await page.Locator("a >> text=Get SSA").TextContentAsync(); - await page.Locator("a >> text=Dynamic Client Registration").TextContentAsync(); - await page.Locator("a >> text=Consent and Authorisation").TextContentAsync(); - await page.Locator("a >> text=Consents").TextContentAsync(); - await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Common\")").TextContentAsync(); - await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Banking\")").TextContentAsync(); - await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Energy\")").TextContentAsync(); - await page.Locator("a >> text=PAR").TextContentAsync(); - await page.Locator("span >> text=Utilities").TextContentAsync(); - await page.Locator("a >> text=ID Token Helper").TextContentAsync(); - await page.Locator("a >> text=Private Key JWT Generator").TextContentAsync(); - }); - } - - static private async Task DataHolders_Discover(IPage page, string industry = "ALL", string version = "2", int? expectedRecords = 32, string? expectedError = null) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Discover Data Holders").ClickAsync(); - await page.Locator("h2 >> text=Discover Data Holders").TextContentAsync(); - - // Arrange - Set industry - if (String.IsNullOrEmpty(industry)) // Clear industry - { - await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new SelectOptionValue[] { }); - } - else - { - await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new[] { industry switch - { - // "" => "", // Doesn't work for clearing, use SelectOptionAsync(new SelectOptionValue[] { }) instead (see above) - "ALL" => "0", - "BANKING" => "1", - "ENERGY" => "2", - "TELCO" => "3", - _ => throw new ArgumentOutOfRangeException($"{nameof(industry)}") - }}); - } - - // Arrange - Set version - await page.Locator("input[name=\"Version\"]").FillAsync(version); - - // Act - Click Refresh button - await page.Locator(@"h5:has-text(""Refresh Data Holders"") ~ div.card-body >> input:has-text(""Refresh"")").ClickAsync(); - - // Assert - Check refresh was successful - var footer = page.Locator(@"h5:has-text(""Refresh Data Holders"") ~ div.card-footer"); - var text = await footer.InnerTextAsync(); - if (expectedError != null) - { - text.Should().Be(expectedError); - } - else - { - if (expectedRecords != -1) // -1 = don't bother checking - { - text.Should().Be($"OK: {expectedRecords} data holder brands added. 0 data holder brands updated."); - } - } - } - - [Fact] - public async Task AC02_01_DiscoverDataHolders_Banking() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC02_01_DiscoverDataHolders_Banking)}", async (page) => - { - await DataHolders_Discover(page, "BANKING", "1", 30); - }); - } - - [Fact] - public async Task AC02_02_DiscoverDataHolders_Energy() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC02_02_DiscoverDataHolders_Energy)}", async (page) => - { - await DataHolders_Discover(page, "ENERGY", "2", 2); - }); - } - - [Fact] - public async Task AC02_03_DiscoverDataHolders_Telco() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC02_03_DiscoverDataHolders_Telco)}", async (page) => - { - await DataHolders_Discover(page, "TELCO", "2", 0); // Currently no Telco dataholders, so 0 = no additional dataholders loaded - }); - } - - [Fact] - public async Task AC02_04_DiscoverDataHolders_AnyIndustry() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC02_04_DiscoverDataHolders_AnyIndustry)}", async (page) => - { - await DataHolders_Discover(page, "ALL", "2", 0); // Should have loaded all dataholders by now, so 0 = no additional dataholders loaded - }); - } - - [Theory] - //[InlineData("ALL", "", null, "BadRequest - Bad Request")] // DF: won't fail anymore - [InlineData("ALL", "3", null, "NotAcceptable - Not Acceptable")] - [InlineData("ALL", "foo", null, "BadRequest - Bad Request")] - //[InlineData("BANKING", "", null, "BadRequest - Bad Request")] // DF: won't fail anymore - [InlineData("BANKING", "3", null, "NotAcceptable - Not Acceptable")] - [InlineData("BANKING", "foo", null, "BadRequest - Bad Request")] - //[InlineData("ENERGY", "", null, "BadRequest - Bad Request")] // DF: won't fail anymore - [InlineData("ENERGY", "3", null, "NotAcceptable - Not Acceptable")] - [InlineData("ENERGY", "foo", null, "BadRequest - Bad Request")] - //[InlineData("TELCO", "", null, "BadRequest - Bad Request")] // DF: won't fail anymore - [InlineData("TELCO", "3", null, "NotAcceptable - Not Acceptable")] - [InlineData("TELCO", "foo", null, "BadRequest - Bad Request")] - public async Task AC02_99_DiscoverDataHolders(string industry = "ALL", string version = "2", int? expectedRecords = 32, string? expectedError = null) - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC02_99_DiscoverDataHolders)} - Industry={industry} - Version={version}", async (page) => - { - await DataHolders_Discover(page, industry, version, expectedRecords, expectedError); - }); - } - - static private async Task SSA_Get(IPage page, string industry, string version, string drBrandId, string drSoftwareProductId, string expectedMessage) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Get SSA").ClickAsync(); - await page.Locator("h2 >> text=Get Software Statement Assertion").TextContentAsync(); - - // Set version - await page.Locator("input[name=\"Version\"]").FillAsync(version); - // Set brandId - await page.Locator("input[name=\"BrandId\"]").FillAsync(drBrandId); - // Set softwareProductId - await page.Locator("input[name=\"SoftwareProductId\"]").FillAsync(drSoftwareProductId); - // Set industry - await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new[] { industry switch - { - // "" => "", // Doesn't work for clearing, use SelectOptionAsync(new SelectOptionValue[] { }) instead (see above) - "ALL" => "0", - "BANKING" => "1", - "ENERGY" => "2", - "TELCO" => "3", - _ => throw new ArgumentOutOfRangeException($"{nameof(industry)}") - }}); - - // Act - Click Refresh button - await page.Locator(@"h5:has-text(""Get SSA"") ~ div.card-body >> input:has-text(""Get SSA"")").ClickAsync(); - - // Assert - Check refresh was successful, card-footer should be showing OK - SSA Generated - var footer = page.Locator(@"h5:has-text(""Get SSA"") ~ div.card-footer"); - var text = await footer.InnerTextAsync(); - text.Should().StartWith(expectedMessage); - } - - [Theory] - //[InlineData("", DR_BRANDID, DR_SOFTWAREPRODUCTID, "BadRequest")] // DF: no longer an error - [InlineData("BANKING", "1", DR_BRANDID, DR_SOFTWAREPRODUCTID, "OK - SSA Generated")] - [InlineData("BANKING", "2", DR_BRANDID, DR_SOFTWAREPRODUCTID, "OK - SSA Generated")] - [InlineData("BANKING", "3", DR_BRANDID, DR_SOFTWAREPRODUCTID, "OK - SSA Generated")] - [InlineData("BANKING", "4", DR_BRANDID, DR_SOFTWAREPRODUCTID, "NotAcceptable")] - public async Task AC03_GetSSA(string industry, string version, string drBrandId, string drSoftwareProductId, string expectedMessage) - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC03_GetSSA)} - Version={version} - DR_BrandId={drBrandId} - DR_SoftwareProductId={drSoftwareProductId}", async (page) => - { - await SSA_Get(page, industry, version, drBrandId, drSoftwareProductId, expectedMessage); - }); - } - - private class DCRResponse - { - [JsonProperty("client_id")] - public string? ClientId { get; set; } - } - - // Create Client Registration returning DH client ID of client that was registered - static private async Task ClientRegistration_Create(IPage page, string dhBrandId, string drBrandId, string drSoftwareProductId) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Dynamic Client Registration").ClickAsync(); - await page.Locator("h2 >> text=Dynamic Client Registration").TextContentAsync(); - - // Set data holder brand id - await page.Locator("select[name=\"DataHolderBrandId\"]").SelectOptionAsync(new[] { dhBrandId }); - - // Assert - Check software product id - (await page.Locator("input[name=\"SoftwareProductId\"]").InputValueAsync()).Should().Be(drSoftwareProductId); - - // Act - Click create button - await page.Locator(@"h5:has-text(""Create Client Registration"") ~ div.card-body >> input:has-text(""Register"")").ClickAsync(); - - // Assert - Check client was registered - await page.Locator(@"h5:has-text(""Create Client Registration"") ~ div.card-footer:has-text(""Created - Registered"")").TextContentAsync(); - - // Assert - Get json result - var json = await page.Locator(@"h5:has-text(""Create Client Registration"") ~ div.card-footer >> pre").InnerTextAsync(); - - // Deserialise response and return DH client id - DCRResponse dcrResponse = JsonConvert.DeserializeObject(json) ?? throw new NullReferenceException(nameof(json)); - return dcrResponse.ClientId ?? throw new NullReferenceException(nameof(dcrResponse.ClientId)); - } - - // Delete Client Registration - static private async Task ClientRegistration_Delete(IPage page) - { - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Dynamic Client Registration").ClickAsync(); - await page.Locator("h2 >> text=Dynamic Client Registration").TextContentAsync(); - await page.Locator("text=Delete").ClickAsync(); - await page.Locator("text=No existing registrations found.").TextContentAsync(); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID)] - [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID)] // Also test for Energy DH - public async Task AC04_DynamicClientRegistration(string dhBrandId = DH_BRANDID, string drBrandId = DR_BRANDID, string drSoftwareProductId = DR_SOFTWAREPRODUCTID) - { - try - { - await ArrangeAsync(async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - }); - - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC04_DynamicClientRegistration)} - DH_BrandId={dhBrandId} - DR_BrandId={drBrandId} - DR_SoftwareProductId={drSoftwareProductId}", async (page) => - { - await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId); - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - }); - } - } - - static private async Task ConsentAndAuthorisation( - IPage page, - string dhClientId, - string dhBrandId, - string drBrandId, - string drSoftwareProductId, - string customerId, - string customerAccounts) - { - ConsentAndAuthorisationResponse? res = null; - - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a:text(\"Consent and Authorisation\")").ClickAsync(); - await page.Locator("h2 >> text=Consent and Authorisation").TextContentAsync(); - - // Arrange - Set Client ID - await page.Locator("select[name=\"RegistrationId\"]").SelectOptionAsync($"{dhClientId}|||{dhBrandId}"); - await page.Locator("select[name=\"RegistrationId\"]").ClickAsync(); // there is JS that runs on the click event, so simulate click here - await Task.Delay(2000); - - // Arrange - Set Sharing Duration - await page.Locator("input[name=\"SharingDuration\"]").FillAsync(SHARING_DURATION); - // Arrange - Click Construct Authoriation URI button - await page.Locator("text=Construct Authorisation Uri").ClickAsync(); - - // Act - Click Authorisation URI link - await page.Locator("p.results > a").ClickAsync(); - - // Act/Assert - Perform consent and authorisation - res = await ConsentAndAuthorisation2(page, customerId, customerAccounts); - - return res ?? throw new ArgumentNullException($"Expected {nameof(ConsentAndAuthorisationResponse)}"); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Don't test for Energy as error will be raised due to FAPI 1.0 conformance - public async Task AC05_ConsentAndAuthorisation( - string dhBrandId = DH_BRANDID, - string drBrandId = DR_BRANDID, - string drSoftwareProductId = DR_SOFTWAREPRODUCTID, - string customerId = CUSTOMERID_BANKING, - string customerAccounts = CUSTOMERACCOUNTS_BANKING) - { - try - { - string? dhClientId = null; - await ArrangeAsync(async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) ?? throw new NullReferenceException(nameof(dhClientId)); - }); - - ConsentAndAuthorisationResponse? res = null; - - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC05_ConsentAndAuthorisation)} - DH_BrandId={dhBrandId}", async (page) => - { - res = await ConsentAndAuthorisation(page, dhClientId!, dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts); - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - try { await Consents_DeleteLocal(page); } catch { }; - }); - } - } - - public delegate Task ConsentsDelegate(IPage page, ConsentAndAuthorisationResponse response); - public async Task Test_Consents(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts, string testName, ConsentsDelegate test) - { - try - { - string? dhClientId = null; - ConsentAndAuthorisationResponse? cdrArrangement = null; - await ArrangeAsync(async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) - ?? throw new NullReferenceException(nameof(dhClientId)); - cdrArrangement = await ConsentAndAuthorisation(page, dhClientId, dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts); - }); - - await TestAsync($"{testName} - DH_BrandId={dhBrandId}", async (page) => - { - await test(page, cdrArrangement ?? throw new NullReferenceException(nameof(cdrArrangement))); - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - try { await Consents_DeleteLocal(page); } catch { }; - }); - } - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_ViewIDToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC06_Consents_ViewIDToken)}", async (page, response) => - { - await TestToken(page, "View ID Token", response?.IDToken ?? throw new ArgumentNullException(nameof(response.IDToken))); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_ViewAccessToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC06_Consents_ViewAccessToken)}", async (page, response) => - { - await TestToken(page, "View Access Token", response?.AccessToken ?? throw new ArgumentNullException(nameof(response.AccessToken))); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_ViewRefreshToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC06_Consents_ViewRefreshToken)}", async (page, response) => - { - await TestToken(page, "View Refresh Token", response?.RefreshToken ?? throw new ArgumentNullException(nameof(response.RefreshToken))); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - // [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_ViewUserInfo(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC06_Consents_ViewUserInfo)}", async (page, response) => - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC06_Consents_ViewUserInfo)}", async (page) => - { - var expected = new (string, string?)[] - { - ("given_name", "Jane"), - ("family_name", "Wilson"), - ("name", "Jane Wilson"), - ("aud", ASSERT_JSON2_ANYVALUE), - ("iss", ASSERT_JSON2_ANYVALUE), - ("sub", ASSERT_JSON2_ANYVALUE), - }; - - await TestInfo(page, "UserInfo", "User Info", "200", expected); - }); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_Introspect(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC06_Consents_Introspect)}", async (page, response) => - { - var expected = new (string, string?)[] - { - ("cdr_arrangement_id", response?.CDRArrangementID ?? throw new ArgumentNullException(nameof(response.CDRArrangementID))), - ("scope", ASSERT_JSON2_ANYVALUE), - ("exp", ASSERT_JSON2_ANYVALUE), - ("active", "True"), - }; - - await TestInfo(page, "Introspect", "Introspection", "200", expected); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING, - "openid profile cdr:registration bank:accounts.basic:read bank:transactions:read common:customer.basic:read")] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY, - // "openid profile cdr:registration energy:accounts.basic:read energy:accounts.concessions:read common:customer.basic:read")] // Also test for Energy DH - public async Task AC06_Consents_Refresh_Access_Token(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts, string expectedScope) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC06_Consents_Refresh_Access_Token)}", async (page, response) => - { - var expected = new (string, string?)[] - { - ("id_token", ASSERT_JSON2_ANYVALUE), - ("access_token", ASSERT_JSON2_ANYVALUE), - ("refresh_token", ASSERT_JSON2_ANYVALUE), - ("expires_in", ACCESSTOKENLIFETIMESECONDS), - ("token_type", "Bearer"), - ("scope", expectedScope), - ("cdr_arrangement_id", ASSERT_JSON2_ANYVALUE), - }; - - await TestInfo(page, "Refresh Access Token", "Refresh Access Token", "200", expected); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_Revoke_Arrangement(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC06_Consents_Revoke_Arrangement)}", async (page, response) => - { - await TestInfo(page, "Revoke Arrangement", "Revoke Arrangement", "204"); - await ScreenshotAsync(page, "-Modal"); - - await page.Locator("div#modal-info >> div.modal-footer >> a >> text=Refresh Page").ClickAsync(); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_Revoke_AccessToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC06_Consents_Revoke_AccessToken)}", async (page, response) => - { - await TestInfo(page, "Revoke Access Token", "Revoke Access Token", "200"); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_Revoke_RefreshToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC06_Consents_Revoke_RefreshToken)}", async (page, response) => - { - await TestInfo(page, "Revoke Refresh Token", "Revoke Refresh Token", "200"); - }); - } - - private static async Task Consents_DeleteLocal(IPage page) - { - await TestInfo(page, "Delete (local)", "Delete Arrangement", "204"); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_Delete_Local(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC06_Consents_Delete_Local)}", async (page, response) => - { - await Consents_DeleteLocal(page); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC07_PAR(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - try - { - string? dhClientId = null; - ConsentAndAuthorisationResponse? cdrArrangement = null; - await ArrangeAsync(async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) - ?? throw new NullReferenceException(nameof(dhClientId)); - cdrArrangement = await ConsentAndAuthorisation(page, dhClientId, dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts) - ?? throw new NullReferenceException(nameof(cdrArrangement)); - }); - - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC07_PAR)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=PAR").ClickAsync(); - await page.Locator("h2 >> text=Pushed Authorisation Request (PAR)").TextContentAsync(); - - // Arrange - Set Client ID - await page.Locator("select[name=\"RegistrationId\"]").SelectOptionAsync(new[] { $"{dhClientId}|||{dhBrandId}" }); - await page.Locator("select[name=\"RegistrationId\"]").ClickAsync(); // there is JS that runs on the click event, so simulate click here - await Task.Delay(2000); - // Arrange - Set CdrArrangementId - await page.Locator("select[name=\"CdrArrangementId\"]").SelectOptionAsync(new[] { cdrArrangement!.CDRArrangementID ?? throw new NullReferenceException(nameof(cdrArrangement.CDRArrangementID)) }); - // Arrange - Set Sharing Duration - await page.Locator("input[name=\"SharingDuration\"]").FillAsync(SHARING_DURATION); - - // Act - Click Initiate PAR button - await page.Locator("div.form >> text=Initiate PAR").ClickAsync(); - - // Act - Click request uri - await page.Locator("p.results > a").ClickAsync(); - - // Act/Assert - Perform consent and authorisation - await ConsentAndAuthorisation2(page, customerId, customerAccounts); - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - try { await Consents_DeleteLocal(page); } catch { }; - }); - } - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - public async Task AC08_ConsumerDataSharing_Banking(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - try - { - string? dhClientId = null; - ConsentAndAuthorisationResponse? cdrArrangement = null; - await ArrangeAsync(async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) - ?? throw new NullReferenceException(nameof(dhClientId)); - cdrArrangement = await ConsentAndAuthorisation(page, dhClientId, dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts); - }); - - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC08_ConsumerDataSharing_Banking)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Banking\")").ClickAsync(); - await page.Locator("h2 >> text=Data Sharing - Banking").TextContentAsync(); - await Task.Delay(2000); // give screen time to refresh - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - try { await Consents_DeleteLocal(page); } catch { }; - }); - } - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - public async Task AC08_ConsumerDataSharing_Banking_AccountsGet(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - try - { - string? dhClientId = null; - ConsentAndAuthorisationResponse? cdrArrangement = null; - await ArrangeAsync(async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) - ?? throw new NullReferenceException(nameof(dhClientId)); - cdrArrangement = await ConsentAndAuthorisation(page, dhClientId, dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts) - ?? throw new NullReferenceException(nameof(cdrArrangement)); - }); - - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC08_ConsumerDataSharing_Banking_AccountsGet)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Banking\")").ClickAsync(); - await page.Locator("h2 >> text=Data Sharing - Banking").TextContentAsync(); - - // Arrange - Get Swagger iframe - var iFrame = page.FrameByUrl($"{WEB_URL}/{SWAGGER_BANKING_IFRAME}") ?? throw new Exception($"IFrame not found - {SWAGGER_BANKING_IFRAME}"); - - // Wait for the CDR arrangement to be added and populated. - System.Threading.Thread.Sleep(10000); - - // Arrange - Select CDR arrangemment - await iFrame.SelectOptionAsync( - "select", - new string[] { - cdrArrangement!.CDRArrangementID ?? throw new NullReferenceException(nameof(cdrArrangement.CDRArrangementID)) - }, - new FrameSelectOptionOptions() { Timeout = 90000 } - ); - - // Arrange - Click GET​/energy​/accountsGet Energy Accounts - // await iFrame.ClickAsync("text=GET​/energy​/accountsGet Energy Accounts"); - await iFrame.ClickAsync("text=Energy GET/energy/plansGet Generic PlansGET/energy/plans/{planId}Get Generic Pla >> [aria-label=\"get ​\\/energy​\\/accounts\"]"); - - // Arrange - Click Try it out - await iFrame.ClickAsync("text=Try it out"); - - // Arrange - Set x-v - await iFrame.FillAsync("[placeholder=\"x-v\"]", "1"); - - // Act - Click Execute - await iFrame.ClickAsync("text=Execute"); - - // Assert - Status code should be 200 - var statusCode = await iFrame.Locator("div.responses-inner > div > div > table > tbody > tr > td.response-col_status").TextContentAsync(); - statusCode.Should().Be("200"); - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - try { await Consents_DeleteLocal(page); } catch { }; - }); - } - } - - [Theory] - [InlineData(IDTOKEN)] - public async Task AC09_IDTokenHelper(string encryptedToken) - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC09_IDTokenHelper)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=ID Token Helper").ClickAsync(); - await page.Locator("h2 >> text=ID Token Helper").TextContentAsync(); - - // Arrange - Enter id token to decrypt - await page.Locator("textarea[name=\"IdTokenEncrypted\"]").FillAsync(encryptedToken); - - // Act - await page.Locator("text=Decrypt ID Token").ClickAsync(); - - // Assert - Check results - await TestResults(page, "nbf", "1653444726"); - await TestResults(page, "exp", "1653445026"); - // await TestResults(page, "iss", $"https://{BaseTest.HOSTNAME_DATAHOLDER}:8001"); - await TestResults(page, "iss", $"https://localhost:8001"); // token is const, it was created on localhost, we are just checking the decryption of token works and not where it was issued - await TestResults(page, "aud", "17d9e269-96d7-4b2a-bd0d-6767ecff965a"); - await TestResults(page, "nonce", "78b2faa4-954c-45de-af0e-33d1424732c7"); - await TestResults(page, "iat", "1653444725"); - await TestResults(page, "at_hash", "jybXQh-TiklHgnSjITgtoA"); - await TestResults(page, "s_hash", "DlHToSN2VJtaskuOQYV2sw"); - await TestResults(page, "auth_time", "1653444711"); - await TestResults(page, "idp", "local"); - await TestResults(page, "cdr_arrangement_id", "d6505b4b-001c-4b98-ae36-1b4d29ea0ef4"); - await TestResults(page, "sub", "mYnxnN7keNe/eiR2j9OZ+axM5WUUa5IdTUEBxyqQWUToZbS9MlaxYYPEhWOhJUQl"); - await TestResults(page, "name", "Kamilla Smith"); - await TestResults(page, "family_name", "Smith"); - await TestResults(page, "given_name", "Kamilla"); - await TestResults(page, "updated_at", "1614623400"); - await TestResults(page, "acr", "urn:cds.au:cdr:2"); - await TestResults(page, "amr", "pwd"); - }); - } - - [Fact] - public async Task AC10_PrivateKeyJWTGenerator() - { - // await ArrangeAsync(async () => { }); - - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC10_PrivateKeyJWTGenerator)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Private Key JWT Generator").ClickAsync(); - await page.Locator("h2 >> text=Private Key JWT Generator").TextContentAsync(); - await page.Locator("input[name=\"Jti\"]").FillAsync("foo"); - - // Act - Click generate button - await page.Locator("form >> text=Generate").ClickAsync(); - - // Assert - Client assertion was generated, and check for View Decoded button - var clientAssertion = await page.Locator("div.results >> div.code").TextContentAsync(); - clientAssertion.Should().NotBeNullOrWhiteSpace(); - await page.Locator("a >> text=View Decoded").TextContentAsync(); - - // Assert - Check client assertions claims - await TestResults(page, "sub", "c6327f87-687a-4369-99a4-eaacd3bb8210"); - await TestResults(page, "jti", "foo"); - await TestResults(page, "iat"); // just check claim exists - await TestResults(page, "exp"); // just check claim exists - await TestResults(page, "iss", "c6327f87-687a-4369-99a4-eaacd3bb8210"); - await TestResults(page, "aud", $"https://{BaseTest_v2.HOSTNAME_REGISTER}:7001/idp/connect/token"); - }); - } - - [Fact] - public async Task AC11_Settings() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC11_Settings)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Settings").ClickAsync(); - await page.Locator("h2 >> text=Settings").TextContentAsync(); - }); - } - - [Fact] - public async Task AC12_About() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v2)} - {nameof(AC12_About)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=About").ClickAsync(); - await page.Locator("h2 >> text=About").TextContentAsync(); - }); - } - } -} -#endif \ No newline at end of file diff --git a/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests_v3.cs b/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests_v3.cs deleted file mode 100644 index a22f726..0000000 --- a/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests_v3.cs +++ /dev/null @@ -1,994 +0,0 @@ -#undef DEPRECATED // instead see US23863_MDR_E2ETests_v2 -#if DEPRECATED -using FluentAssertions; -using Microsoft.Data.SqlClient; -using Microsoft.Playwright; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Xunit; - -#nullable enable - -namespace CDR.DataRecipient.E2ETests -{ - public class US23863_MDR_E2ETests_v3 : BaseTest_v2, IClassFixture - { - private const string SWAGGER_BANKING_IFRAME = "cds-banking/index.html"; - private const string SWAGGER_ENERGY_IFRAME = "cds-energy/index.html"; - private const string SWAGGER_COMMON_IFRAME = "cds-common/index.html"; - - private const string SHARING_DURATION = "100000"; - - // Pre-generated ID Token used in IDTokenhelper test - const string IDTOKEN = @"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00iLCJraWQiOiJlMmM2ZWFmZjdmYWQwODFjNzhiMjJkNjNiYmI1N" + - "jdlODYwNzBlNTFlYjE0NzZhYmNhNmEyMzNiY2U4Y2ExNGJhIn0.fp9-2--a7mM70FsVL1c5MacViVkPcI-CZCGXyjV4F1T-RZuUsMaw9sCkjNrnE3" + - "LR9nnBOYploFXljRo6_ZkH5PJHtSfnoF8GRnJJHJ74dvJC3MqRsvGUl8uS5P2sEW2TexXQlhdKwFA3REM1khpVNAA1FZyFK3iv7IucipnL0UcO1H-" + - "23iBb7puOdEm6_3Sndu2ycACt5in-gO2UIWHFeaUDwLdr7iCBH4fzn5jupSJdyZ-9iU2ahOhf6iJFAwYM4R7CEPRTr8h8JqXBW3cqOcAktK0jScmv" + - "U3k2zOqtiwTxZ3yTwNEinSSvDxyxofKmiXsQDkgOzbJt6YPAq2c9gw.o-hgXFF8FzFUd1gY.NX-J0RWfE53KksdvhNK9pcXjXvLicaFO3N1N-ivAV" + - "G3HL_7k7f4L2d7B3Elh4UXiiV84xuS2wBltNT2XcOAEMZuJd6-e1Octuhzzc9o8pFQEtP-72vzpo6K6wbdSgFwqPNQ4xGJTArS2BCG1v_rfiUNqM7" + - "Y-igdsGImk3DoCBtsq-PWaWZgwj0d4ci5De4EkMpb3UZrk9UlZGGpgOH0rqGEPQEhO41M-7XeBw-cVqyGwaS6c3iwSUZHHCLgluZ-AfJ3ebfq9ya3" + - "u02de95C1YMhN04BA9Oj_tkTUA4XvyfXnxd_cXtjPUUjAo2Tvmc1YxU-tfNgwLgW3s2jFdkeJnHj7vwXzAbiAthIleD9D2LrYUN_vNWI0Lc570R1g" + - "GVXVFl_IfUMhZBSRYTl4z15NGdTwTopusNDVnOKQrKu5FsRWa0g1h80Fnmiw4sNRByFzxY_qziz67aUbJK1qz57FdBhHy85GkdK90Zd7kTuITYkPc" + - "c7_Srtu6ZHMWNRbUxvEHF_YHnTVWiH3DCiGYwrPCYEcXLutoY2A0nJGBAPsgCYnZ8_FvsQCsUno-PJyyWhjZ98mXcmtNIBOw5qArH7E520p586FtO" + - "JjS0zbRL7UjNxK2IcSB01-9WkWVxTxYrQnD8fzobnNPCf6esGGyPjU-PD-bstCQ1PUhA5OSg7MmBiTyRZYfvj59_rkhqdLovYCqyZLu9NbySLoFiq" + - "hnCXmmCROv6U_-KDW0-y30Uf9s_ke00l5kBSs9F4h8shDF5rXySL8HeAwNt_0JY4Q1pg6zu2PISuXVmcnizCZoCFaDTQ1ReQKHBfsDss7g680F6OY" + - "_UFxzYwxowIctfZzKQtT0q0J2xghgjPP-U47ng8VTQX2b_8TmMMWXiEvumxEb9gHp_i6246uHOeuiBu2LVGniAJkbTB2DHgICXgRYSd_pQTi7GBsu" + - "m4ZzQeVIVC7UKxc1OOHkLLypzPRK2bwOIg0SMZjnugCLbmQUyJxyB7ht5iA2psX-EavKeR-KjTqOWFSr5byOIbMUSLY44K0Al503u7NTvH5JVUH4y" + - "y6zI8sgiaQTcfAXo1YKhmHqJPf4VbQZRMTs3_2tdu5rNl-BSytbLnKrmFvL85RoKAq6wqE3Clk4BLJQ0CNoBvm-nObhzhQ_mhbXyRXn7A1vKEkf_p" + - "KHv3-dKBlX4-jdyFJAwd_HPqb6gtBFsKROlpQwlCxGbEV5GF2iN0az03r6RPveqxvkP4RpgfG8VaXvKyW9xi4lENVelt_Ep11BXHsrJGKupIaIdW" + - "IhUZu90VJYIezKKztLycPlxs7oOkEDTIfVrO1HeuEOHk1CCgxBiWtqZiKO2ELtE5mj2fee35fWFQ31muNiXBVD2DgHabnb_S0ZXHzY6MR368Rj0h" + - "xqxiDVc6ppQcVt02XYL4HLz4mBExyvy0F13OfuEkP5tWlaHkK8k90eISkn7aKcoMVV5JSFjqPasA_dY91Gbpq0itHDtaEIzgcOYWP-u8LUGJGLF4N" + - "qWkBfZUEGxgPIQ1ynRGwwUwnrh8xQSuvG_Phid0DGHm0Kxz_j0Vyvr60TpFoYNwGPH6vQ3bsiSs2JlxLuOdC-Kw6YVahxsGkE6b9ZKn9HiW6tmxj-" + - "CCf1u4tYiYxW48ceOcivydgT-mIKAdQeClTIbAJdJq4wY_936f5GWIJxM-wJ78qwFTN4R7zG4vINi2gd5000h4JjCaYTyX9v989Fzuq5SIkNHRb8E" + - "hSLcMA_3De7epFZCnImEhkKUQPHxwaW9kDBExy-sVJ2ku9EN6k4AZAM60lCMAdOGWwvOFN-pW9k9DBDmZTfg1kjfnbn4guIfw7lJKp2iy-0TGVhDD" + - "3MN3BTrucmURy6_kpXWRLGuLd3fEj-bQAwD4sMgLVe_GWh6f1TFo7hUfrNmwuXLjqtFMjMgWXbo8zM4VJDL6fCO_U0HZzXx3CGzxuSETWQxF9EeDG" + - "kSpwIdweEmFl1finL1g.gTClNE4BztTzJIpe8BcNRw"; - - static string GetClientId() - { - using var mdrConnection = new SqlConnection(BaseTest_v2.DATARECIPIENT_CONNECTIONSTRING); - mdrConnection.Open(); - - using var selectCommand = new SqlCommand($"select clientid from registration", mdrConnection); - string? clientId = Convert.ToString(selectCommand.ExecuteScalar()); - - if (String.IsNullOrEmpty(clientId)) - throw new Exception("No registrations found"); - - return clientId; - } - - public class ConsentAndAuthorisationResponse - { - public string? IDToken { get; init; } - public string? AccessToken { get; init; } - public string? RefreshToken { get; init; } - public string? ExpiresIn { get; init; } - public string? Scope { get; init; } - public string? TokenType { get; init; } - public string? CDRArrangementID { get; init; } - } - - static async Task ConsentAndAuthorisation2(IPage page, string customerId = CUSTOMERID_BANKING, string customerAccounts = CUSTOMERACCOUNTS_BANKING) - { - // Act - Enter Customer ID - await page.Locator("[placeholder=\"Your Customer ID\"]").FillAsync(customerId); - await page.Locator("text=Continue").ClickAsync(); - - // Act - Wait for OTP, then enter it, and click Continue - await Task.Delay(5000); - await page.Locator("[placeholder=\"Enter 6 digit One Time Password\"]").FillAsync("000789"); - await page.Locator("text=Continue").ClickAsync(); - - // Act - Select accounts - foreach (var customerAccount in customerAccounts.Split(',')) - { - await page.Locator($"text={customerAccount}").ClickAsync(); - } - - // Act - Click Continue and I confirm - await page.Locator("text=Continue").ClickAsync(); - await page.Locator("text=I Confirm").ClickAsync(); - - // Assert - Check callback is shown and get arrangement ID - await page.Locator("text=Consent and Authorisation - Callback").TextContentAsync(); - - return new ConsentAndAuthorisationResponse - { - IDToken = await page.Locator(@"dt:has-text(""Id Token"") + dd ").TextContentAsync(), - AccessToken = await page.Locator(@"dt:has-text(""Access Token"") + dd ").TextContentAsync(), - RefreshToken = await page.Locator(@"dt:has-text(""Refresh Token"") + dd ").TextContentAsync(), - ExpiresIn = await page.Locator(@"dt:has-text(""Expires In"") + dd ").TextContentAsync(), - Scope = await page.Locator(@"dt:has-text(""Scope"") + dd ").TextContentAsync(), - TokenType = await page.Locator(@"dt:has-text("" Token Type"") + dd ").TextContentAsync(), - CDRArrangementID = await page.Locator(@"dt:has-text(""CDR Arrangement Id"") + dd ").TextContentAsync() - }; - } - - static async Task NewConsentAndAuthorisationWithPAR( - IPage page, - string dhClientId, - string customerId = CUSTOMERID_BANKING, - string customerAccounts = CUSTOMERACCOUNTS_BANKING, - string dhBrandId = DH_BRANDID) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=PAR").ClickAsync(); - await page.Locator("h2 >> text=Pushed Authorisation Request (PAR)").TextContentAsync(); - - // Arrange - Set Client ID - await page.Locator("select[name=\"RegistrationId\"]").SelectOptionAsync(new[] { $"{dhClientId!}|||{dhBrandId}" }); - await page.Locator("select[name=\"RegistrationId\"]").ClickAsync(); // there is JS that runs on the click event, so simulate click here - await Task.Delay(2000); - // Arrange - Set CdrArrangementId - //await page.Locator("select[name=\"CdrArrangementId\"]").SelectOptionAsync(new[] { cdrArrangement!.CDRArrangementID ?? throw new NullReferenceException(nameof(cdrArrangement.CDRArrangementID)) }); - // Arrange - Set Sharing Duration - await page.Locator("input[name=\"SharingDuration\"]").FillAsync(SHARING_DURATION); - - // Act - Click Initiate PAR button - await page.Locator("div.form >> text=Initiate PAR").ClickAsync(); - - // Act - Click request uri - await page.Locator("p.results > a").ClickAsync(); - - return await ConsentAndAuthorisation2(page, customerId, customerAccounts); - } - - public static async Task TestToken(IPage page, string menuText, string? expectedToken) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Consents").ClickAsync(); - await page.Locator("h2 >> text=Consents").TextContentAsync(); - - // Act - Click actions button and submenu item - await page.Locator("button:has-text(\"Actions\")").ClickAsync(); - await page.Locator($"a >> text={menuText}").ClickAsync(); - - // Act - Check modal opens - await page.Locator("div#modal-token >> h5.modal-title >> text=Token Contents").TextContentAsync(); - - // Assert - Check actual token matches expected token - var token = await page.Locator(@"div#modal-token >> div.modal-body").TextContentAsync(); - token.Should().NotBeNullOrEmpty(); - token.Should().Be(expectedToken); - } - - public static async Task TestInfo(IPage page, string menuText, string modalTitle, string expectedStatusCode, (string name, string? value)[]? expectedPayload = null) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Consents").ClickAsync(); - await page.Locator("h2 >> text=Consents").TextContentAsync(); - - // Act - Click actions button and submenu item - await page.Locator("button:has-text(\"Actions\")").ClickAsync(); - await page.Locator($"a >> text={menuText}").ClickAsync(); - - // Act - Check modal opens - await page.Locator($"div#modal-info >> h5.modal-title >> text={modalTitle}").TextContentAsync(); - - // Assert - Check statuscode - var statusCode = await page.Locator(@$"div#modal-info >> div.modal-statusCode >> text={expectedStatusCode}").TextContentAsync(); - statusCode.Should().Be(expectedStatusCode); - - // Assert - Check payload is what's expected - if (expectedPayload != null) - { - var payload = await page.Locator(@"div#modal-info >> pre.modal-payload").TextContentAsync(); - Assert_Json2(payload, expectedPayload); - } - } - - static async Task TestResults(IPage page, string label, string? value = null) - { - // Check for label and value - if (value != null) - await page.Locator($"div.results >> dl >> dt:has-text(\"{label}\") + dd:has-text(\"{value}\")").TextContentAsync(); - // Just check for label - else - await page.Locator($"div.results >> dl >> dt:has-text(\"{label}\")").TextContentAsync(); - } - - [Fact] - public async Task AC01_HomePage() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC01_HomePage)}", async (page) => - { - // Act - Goto home page - await page.GotoAsync(WEB_URL); - - // Assert - Check banner - await page.Locator("h1 >> text=Mock Data Recipient").TextContentAsync(); - await page.Locator("text=Welcome to the Mock Data Recipient").TextContentAsync(); - await page.Locator("a >> text=Settings").TextContentAsync(); - await page.Locator("a >> text=About").TextContentAsync(); - - // Assert - Check menu items exists - await page.Locator("a >> text=Home").TextContentAsync(); - await page.Locator("a >> text=Discover Data Holders").TextContentAsync(); - await page.Locator("a >> text=Get SSA").TextContentAsync(); - await page.Locator("a >> text=Dynamic Client Registration").TextContentAsync(); - await page.Locator("a >> text=Consents").TextContentAsync(); - await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Common\")").TextContentAsync(); - await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Banking\")").TextContentAsync(); - await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Energy\")").TextContentAsync(); - await page.Locator("a >> text=PAR").TextContentAsync(); - await page.Locator("span >> text=Utilities").TextContentAsync(); - await page.Locator("a >> text=ID Token Helper").TextContentAsync(); - await page.Locator("a >> text=Private Key JWT Generator").TextContentAsync(); - }); - } - - static private async Task DataHolders_Discover(IPage page, string industry = "ALL", string version = "2", int? expectedRecords = 32, string? expectedError = null) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Discover Data Holders").ClickAsync(); - await page.Locator("h2 >> text=Discover Data Holders").TextContentAsync(); - - // Arrange - Set industry - if (String.IsNullOrEmpty(industry)) // Clear industry - { - await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new SelectOptionValue[] { }); - } - else - { - await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new[] { industry switch - { - // "" => "", // Doesn't work for clearing, use SelectOptionAsync(new SelectOptionValue[] { }) instead (see above) - "ALL" => "0", - "BANKING" => "1", - "ENERGY" => "2", - "TELCO" => "3", - _ => throw new ArgumentOutOfRangeException($"{nameof(industry)}") - }}); - } - - // Arrange - Set version - await page.Locator("input[name=\"Version\"]").FillAsync(version); - - // Act - Click Refresh button - await page.Locator(@"h5:has-text(""Refresh Data Holders"") ~ div.card-body >> input:has-text(""Refresh"")").ClickAsync(); - - // Assert - Check refresh was successful - var footer = page.Locator(@"h5:has-text(""Refresh Data Holders"") ~ div.card-footer"); - var text = await footer.InnerTextAsync(); - if (expectedError != null) - { - text.Should().Be(expectedError); - } - else - { - if (expectedRecords != -1) // -1 = don't bother checking - { - text.Should().Be($"OK: {expectedRecords} data holder brands added. 0 data holder brands updated."); - } - } - } - - [Fact] - public async Task AC02_01_DiscoverDataHolders_Banking() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC02_01_DiscoverDataHolders_Banking)}", async (page) => - { - await DataHolders_Discover(page, "BANKING", "1", 30); - }); - } - - [Fact] - public async Task AC02_02_DiscoverDataHolders_Energy() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC02_02_DiscoverDataHolders_Energy)}", async (page) => - { - await DataHolders_Discover(page, "ENERGY", "2", 2); - }); - } - - [Fact] - public async Task AC02_03_DiscoverDataHolders_Telco() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC02_03_DiscoverDataHolders_Telco)}", async (page) => - { - await DataHolders_Discover(page, "TELCO", "2", 0); // Currently no Telco dataholders, so 0 = no additional dataholders loaded - }); - } - - [Fact] - public async Task AC02_04_DiscoverDataHolders_AnyIndustry() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC02_04_DiscoverDataHolders_AnyIndustry)}", async (page) => - { - await DataHolders_Discover(page, "ALL", "2", 0); // Should have loaded all dataholders by now, so 0 = no additional dataholders loaded - }); - } - - [Theory] - //[InlineData("ALL", "", null, "BadRequest - Bad Request")] // DF: won't fail anymore - [InlineData("ALL", "3", null, "NotAcceptable - Not Acceptable")] - [InlineData("ALL", "foo", null, "BadRequest - Bad Request")] - //[InlineData("BANKING", "", null, "BadRequest - Bad Request")] // DF: won't fail anymore - [InlineData("BANKING", "3", null, "NotAcceptable - Not Acceptable")] - [InlineData("BANKING", "foo", null, "BadRequest - Bad Request")] - //[InlineData("ENERGY", "", null, "BadRequest - Bad Request")] // DF: won't fail anymore - [InlineData("ENERGY", "3", null, "NotAcceptable - Not Acceptable")] - [InlineData("ENERGY", "foo", null, "BadRequest - Bad Request")] - //[InlineData("TELCO", "", null, "BadRequest - Bad Request")] // DF: won't fail anymore - [InlineData("TELCO", "3", null, "NotAcceptable - Not Acceptable")] - [InlineData("TELCO", "foo", null, "BadRequest - Bad Request")] - public async Task AC02_99_DiscoverDataHolders(string industry = "ALL", string version = "2", int? expectedRecords = 32, string? expectedError = null) - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC02_99_DiscoverDataHolders)} - Industry={industry} - Version={version}", async (page) => - { - await DataHolders_Discover(page, industry, version, expectedRecords, expectedError); - }); - } - - static private async Task SSA_Get(IPage page, string industry, string version, string drBrandId, string drSoftwareProductId, string expectedMessage) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Get SSA").ClickAsync(); - await page.Locator("h2 >> text=Get Software Statement Assertion").TextContentAsync(); - - // Set version - await page.Locator("input[name=\"Version\"]").FillAsync(version); - // Set brandId - await page.Locator("input[name=\"BrandId\"]").FillAsync(drBrandId); - // Set softwareProductId - await page.Locator("input[name=\"SoftwareProductId\"]").FillAsync(drSoftwareProductId); - // Set industry - await page.Locator("select[name=\"Industry\"]").SelectOptionAsync(new[] { industry switch - { - // "" => "", // Doesn't work for clearing, use SelectOptionAsync(new SelectOptionValue[] { }) instead (see above) - "ALL" => "0", - "BANKING" => "1", - "ENERGY" => "2", - "TELCO" => "3", - _ => throw new ArgumentOutOfRangeException($"{nameof(industry)}") - }}); - - // Act - Click Refresh button - await page.Locator(@"h5:has-text(""Get SSA"") ~ div.card-body >> input:has-text(""Get SSA"")").ClickAsync(); - - // Assert - Check refresh was successful, card-footer should be showing OK - SSA Generated - var footer = page.Locator(@"h5:has-text(""Get SSA"") ~ div.card-footer"); - var text = await footer.InnerTextAsync(); - text.Should().StartWith(expectedMessage); - } - - [Theory] - //[InlineData("", DR_BRANDID, DR_SOFTWAREPRODUCTID, "BadRequest")] // DF: no longer an error - [InlineData("BANKING", "1", DR_BRANDID, DR_SOFTWAREPRODUCTID, "OK - SSA Generated")] - [InlineData("BANKING", "2", DR_BRANDID, DR_SOFTWAREPRODUCTID, "OK - SSA Generated")] - [InlineData("BANKING", "3", DR_BRANDID, DR_SOFTWAREPRODUCTID, "OK - SSA Generated")] - [InlineData("BANKING", "4", DR_BRANDID, DR_SOFTWAREPRODUCTID, "NotAcceptable")] - public async Task AC03_GetSSA(string industry, string version, string drBrandId, string drSoftwareProductId, string expectedMessage) - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC03_GetSSA)} - Version={version} - DR_BrandId={drBrandId} - DR_SoftwareProductId={drSoftwareProductId}", async (page) => - { - await SSA_Get(page, industry, version, drBrandId, drSoftwareProductId, expectedMessage); - }); - } - - private class DCRResponse - { - [JsonProperty("client_id")] - public string? ClientId { get; set; } - } - - // Create Client Registration returning DH client ID of client that was registered - static private async Task ClientRegistration_Create(IPage page, string dhBrandId, string drBrandId, string drSoftwareProductId) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Dynamic Client Registration").ClickAsync(); - await page.Locator("h2 >> text=Dynamic Client Registration").TextContentAsync(); - - // Set data holder brand id - await page.Locator("select[name=\"DataHolderBrandId\"]").SelectOptionAsync(new[] { dhBrandId }); - - // Assert - Check software product id - (await page.Locator("input[name=\"SoftwareProductId\"]").InputValueAsync()).Should().Be(drSoftwareProductId); - - // Act - Click create button - await page.Locator(@"h5:has-text(""Create Client Registration"") ~ div.card-body >> input:has-text(""Register"")").ClickAsync(); - - // Assert - Check client was registered - await page.Locator(@"h5:has-text(""Create Client Registration"") ~ div.card-footer:has-text(""Created - Registered"")").TextContentAsync(); - - // Assert - Get json result - var json = await page.Locator(@"h5:has-text(""Create Client Registration"") ~ div.card-footer >> pre").InnerTextAsync(); - - // Deserialise response and return DH client id - DCRResponse dcrResponse = JsonConvert.DeserializeObject(json) ?? throw new NullReferenceException(nameof(json)); - return dcrResponse.ClientId ?? throw new NullReferenceException(nameof(dcrResponse.ClientId)); - } - - // Delete Client Registration - static private async Task ClientRegistration_Delete(IPage page) - { - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Dynamic Client Registration").ClickAsync(); - await page.Locator("h2 >> text=Dynamic Client Registration").TextContentAsync(); - await page.Locator("text=Delete").ClickAsync(); - await page.Locator("text=No existing registrations found.").TextContentAsync(); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID)] - [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID)] // Also test for Energy DH - public async Task AC04_DynamicClientRegistration(string dhBrandId = DH_BRANDID, string drBrandId = DR_BRANDID, string drSoftwareProductId = DR_SOFTWAREPRODUCTID) - { - try - { - await ArrangeAsync(async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - }); - - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC04_DynamicClientRegistration)} - DH_BrandId={dhBrandId} - DR_BrandId={drBrandId} - DR_SoftwareProductId={drSoftwareProductId}", async (page) => - { - await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId); - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - }); - } - } - - public delegate Task ConsentsDelegate(IPage page, ConsentAndAuthorisationResponse response); - public async Task Test_Consents(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts, string testName, ConsentsDelegate test) - { - try - { - string? dhClientId = null; - ConsentAndAuthorisationResponse? cdrArrangement = null; - await ArrangeAsync(async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) - ?? throw new NullReferenceException(nameof(dhClientId)); - cdrArrangement = await NewConsentAndAuthorisationWithPAR(page, dhClientId, customerId, customerAccounts, dhBrandId) - ?? throw new NullReferenceException(nameof(cdrArrangement)); - - }); - - await TestAsync($"{testName} - DH_BrandId={dhBrandId}", async (page) => - { - await test(page, cdrArrangement ?? throw new NullReferenceException(nameof(cdrArrangement))); - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - try { await Consents_DeleteLocal(page); } catch { }; - }); - } - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_ViewIDToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC06_Consents_ViewIDToken)}", async (page, response) => - { - await TestToken(page, "View ID Token", response?.IDToken ?? throw new ArgumentNullException(nameof(response.IDToken))); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_ViewAccessToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC06_Consents_ViewAccessToken)}", async (page, response) => - { - await TestToken(page, "View Access Token", response?.AccessToken ?? throw new ArgumentNullException(nameof(response.AccessToken))); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_ViewRefreshToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC06_Consents_ViewRefreshToken)}", async (page, response) => - { - await TestToken(page, "View Refresh Token", response?.RefreshToken ?? throw new ArgumentNullException(nameof(response.RefreshToken))); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - // [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_ViewUserInfo(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC06_Consents_ViewUserInfo)}", async (page, response) => - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC06_Consents_ViewUserInfo)}", async (page) => - { - var expected = new (string, string?)[] - { - ("given_name", "Jane"), - ("family_name", "Wilson"), - ("name", "Jane Wilson"), - ("aud", ASSERT_JSON2_ANYVALUE), - ("iss", ASSERT_JSON2_ANYVALUE), - ("sub", ASSERT_JSON2_ANYVALUE), - }; - - await TestInfo(page, "UserInfo", "User Info", "200", expected); - }); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_Introspect(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC06_Consents_Introspect)}", async (page, response) => - { - var expected = new (string, string?)[] - { - ("cdr_arrangement_id", response?.CDRArrangementID ?? throw new ArgumentNullException(nameof(response.CDRArrangementID))), - ("scope", ASSERT_JSON2_ANYVALUE), - ("exp", ASSERT_JSON2_ANYVALUE), - ("active", "True"), - }; - - await TestInfo(page, "Introspect", "Introspection", "200", expected); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING, - "openid profile cdr:registration bank:accounts.basic:read bank:transactions:read common:customer.basic:read")] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY, - // "openid profile cdr:registration energy:accounts.basic:read energy:accounts.concessions:read common:customer.basic:read")] // Also test for Energy DH - public async Task AC06_Consents_Refresh_Access_Token(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts, string expectedScope) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC06_Consents_Refresh_Access_Token)}", async (page, response) => - { - var expected = new (string, string?)[] - { - ("id_token", ASSERT_JSON2_ANYVALUE), - ("access_token", ASSERT_JSON2_ANYVALUE), - ("refresh_token", ASSERT_JSON2_ANYVALUE), - ("expires_in", ACCESSTOKENLIFETIMESECONDS), - ("token_type", "Bearer"), - ("scope", expectedScope), - ("cdr_arrangement_id", ASSERT_JSON2_ANYVALUE), - }; - - await TestInfo(page, "Refresh Access Token", "Refresh Access Token", "200", expected); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_Revoke_Arrangement(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC06_Consents_Revoke_Arrangement)}", async (page, response) => - { - await TestInfo(page, "Revoke Arrangement", "Revoke Arrangement", "204"); - await ScreenshotAsync(page, "-Modal"); - - await page.Locator("div#modal-info >> div.modal-footer >> a >> text=Refresh Page").ClickAsync(); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_Revoke_AccessToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC06_Consents_Revoke_AccessToken)}", async (page, response) => - { - await TestInfo(page, "Revoke Access Token", "Revoke Access Token", "200"); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_Revoke_RefreshToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC06_Consents_Revoke_RefreshToken)}", async (page, response) => - { - await TestInfo(page, "Revoke Refresh Token", "Revoke Refresh Token", "200"); - }); - } - - private static async Task Consents_DeleteLocal(IPage page) - { - await TestInfo(page, "Delete (local)", "Delete Arrangement", "204"); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_Delete_Local(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC06_Consents_Delete_Local)}", async (page, response) => - { - await Consents_DeleteLocal(page); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - //[InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC07_PAR(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - try - { - string? dhClientId = null; - ConsentAndAuthorisationResponse? cdrArrangement = null; - await ArrangeAsync(async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) - ?? throw new NullReferenceException(nameof(dhClientId)); - cdrArrangement = await NewConsentAndAuthorisationWithPAR(page, dhClientId, customerId, customerAccounts, dhBrandId) - ?? throw new NullReferenceException(nameof(cdrArrangement)); - }); - - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC07_PAR)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=PAR").ClickAsync(); - await page.Locator("h2 >> text=Pushed Authorisation Request (PAR)").TextContentAsync(); - - // Arrange - Set Client ID - await page.Locator("select[name=\"RegistrationId\"]").SelectOptionAsync(new[] { $"{dhClientId}|||{dhBrandId}" }); - await page.Locator("select[name=\"RegistrationId\"]").ClickAsync(); // there is JS that runs on the click event, so simulate click here - await Task.Delay(2000); - // Arrange - Set CdrArrangementId - await page.Locator("select[name=\"CdrArrangementId\"]").SelectOptionAsync(new[] { cdrArrangement!.CDRArrangementID ?? throw new NullReferenceException(nameof(cdrArrangement.CDRArrangementID)) }); - // Arrange - Set Sharing Duration - await page.Locator("input[name=\"SharingDuration\"]").FillAsync(SHARING_DURATION); - - // Act - Click Initiate PAR button - await page.Locator("div.form >> text=Initiate PAR").ClickAsync(); - - // Act - Click request uri - await page.Locator("p.results > a").ClickAsync(); - - // Act/Assert - Perform consent and authorisation - await ConsentAndAuthorisation2(page, customerId, customerAccounts); - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - try { await Consents_DeleteLocal(page); } catch { }; - }); - } - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - public async Task AC08_ConsumerDataSharing_Banking(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - try - { - string? dhClientId = null; - ConsentAndAuthorisationResponse? cdrArrangement = null; - await ArrangeAsync(async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) - ?? throw new NullReferenceException(nameof(dhClientId)); - cdrArrangement = await NewConsentAndAuthorisationWithPAR(page, dhClientId, customerId, customerAccounts, dhBrandId) - ?? throw new NullReferenceException(nameof(cdrArrangement)); - }); - - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC08_ConsumerDataSharing_Banking)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Banking\")").ClickAsync(); - await page.Locator("h2 >> text=Data Sharing - Banking").TextContentAsync(); - await Task.Delay(2000); // give screen time to refresh - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - try { await Consents_DeleteLocal(page); } catch { }; - }); - } - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - public async Task AC08_ConsumerDataSharing_Banking_AccountsGet(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - try - { - string? dhClientId = null; - ConsentAndAuthorisationResponse? cdrArrangement = null; - await ArrangeAsync(async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) - ?? throw new NullReferenceException(nameof(dhClientId)); - cdrArrangement = await NewConsentAndAuthorisationWithPAR(page, dhClientId, customerId, customerAccounts, dhBrandId) - ?? throw new NullReferenceException(nameof(cdrArrangement)); - }); - - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC08_ConsumerDataSharing_Banking_AccountsGet)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Banking\")").ClickAsync(); - await page.Locator("h2 >> text=Data Sharing - Banking").TextContentAsync(); - - // Arrange - Get Swagger iframe - var iFrame = page.FrameByUrl($"{WEB_URL}/{SWAGGER_BANKING_IFRAME}") ?? throw new Exception($"IFrame not found - {SWAGGER_BANKING_IFRAME}"); - - // Wait for the CDR arrangement to be added and populated. - System.Threading.Thread.Sleep(10000); - - // Arrange - Select CDR arrangemment - await iFrame.SelectOptionAsync( - "select", - new string[] { - cdrArrangement!.CDRArrangementID ?? throw new NullReferenceException(nameof(cdrArrangement.CDRArrangementID)) - }, - new FrameSelectOptionOptions() { Timeout = 90000 } - ); - - // Arrange - Click GET​/energy​/accountsGet Energy Accounts - // await iFrame.ClickAsync("text=GET​/energy​/accountsGet Energy Accounts"); - await iFrame.ClickAsync("text=Energy GET/energy/plansGet Generic PlansGET/energy/plans/{planId}Get Generic Pla >> [aria-label=\"get ​\\/energy​\\/accounts\"]"); - - // Arrange - Click Try it out - await iFrame.ClickAsync("text=Try it out"); - - // Arrange - Set x-v - await iFrame.FillAsync("[placeholder=\"x-v\"]", "1"); - - // Act - Click Execute - await iFrame.ClickAsync("text=Execute"); - - // Assert - Status code should be 200 - var statusCode = await iFrame.Locator("div.responses-inner > div > div > table > tbody > tr > td.response-col_status").TextContentAsync(); - statusCode.Should().Be("200"); - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - try { await Consents_DeleteLocal(page); } catch { }; - }); - } - } - - [Theory] - [InlineData(IDTOKEN)] - public async Task AC09_IDTokenHelper(string encryptedToken) - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC09_IDTokenHelper)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=ID Token Helper").ClickAsync(); - await page.Locator("h2 >> text=ID Token Helper").TextContentAsync(); - - // Arrange - Enter id token to decrypt - await page.Locator("textarea[name=\"IdTokenEncrypted\"]").FillAsync(encryptedToken); - - // Act - await page.Locator("text=Decrypt ID Token").ClickAsync(); - - // Assert - Check results - await TestResults(page, "nbf", "1653444726"); - await TestResults(page, "exp", "1653445026"); - // await TestResults(page, "iss", $"https://{BaseTest.HOSTNAME_DATAHOLDER}:8001"); - await TestResults(page, "iss", $"https://localhost:8001"); // token is const, it was created on localhost, we are just checking the decryption of token works and not where it was issued - await TestResults(page, "aud", "17d9e269-96d7-4b2a-bd0d-6767ecff965a"); - await TestResults(page, "nonce", "78b2faa4-954c-45de-af0e-33d1424732c7"); - await TestResults(page, "iat", "1653444725"); - await TestResults(page, "at_hash", "jybXQh-TiklHgnSjITgtoA"); - await TestResults(page, "s_hash", "DlHToSN2VJtaskuOQYV2sw"); - await TestResults(page, "auth_time", "1653444711"); - await TestResults(page, "idp", "local"); - await TestResults(page, "cdr_arrangement_id", "d6505b4b-001c-4b98-ae36-1b4d29ea0ef4"); - await TestResults(page, "sub", "mYnxnN7keNe/eiR2j9OZ+axM5WUUa5IdTUEBxyqQWUToZbS9MlaxYYPEhWOhJUQl"); - await TestResults(page, "name", "Kamilla Smith"); - await TestResults(page, "family_name", "Smith"); - await TestResults(page, "given_name", "Kamilla"); - await TestResults(page, "updated_at", "1614623400"); - await TestResults(page, "acr", "urn:cds.au:cdr:2"); - await TestResults(page, "amr", "pwd"); - }); - } - - [Fact] - public async Task AC10_PrivateKeyJWTGenerator() - { - // await ArrangeAsync(async () => { }); - - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC10_PrivateKeyJWTGenerator)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Private Key JWT Generator").ClickAsync(); - await page.Locator("h2 >> text=Private Key JWT Generator").TextContentAsync(); - await page.Locator("input[name=\"Jti\"]").FillAsync("foo"); - - // Act - Click generate button - await page.Locator("form >> text=Generate").ClickAsync(); - - // Assert - Client assertion was generated, and check for View Decoded button - var clientAssertion = await page.Locator("div.results >> div.code").TextContentAsync(); - clientAssertion.Should().NotBeNullOrWhiteSpace(); - await page.Locator("a >> text=View Decoded").TextContentAsync(); - - // Assert - Check client assertions claims - await TestResults(page, "sub", "c6327f87-687a-4369-99a4-eaacd3bb8210"); - await TestResults(page, "jti", "foo"); - await TestResults(page, "iat"); // just check claim exists - await TestResults(page, "exp"); // just check claim exists - await TestResults(page, "iss", "c6327f87-687a-4369-99a4-eaacd3bb8210"); - await TestResults(page, "aud", $"https://{BaseTest_v2.HOSTNAME_REGISTER}:7001/idp/connect/token"); - }); - } - - [Fact] - public async Task AC11_Settings() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC11_Settings)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Settings").ClickAsync(); - await page.Locator("h2 >> text=Settings").TextContentAsync(); - }); - } - - [Fact] - public async Task AC12_About() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v3)} - {nameof(AC12_About)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=About").ClickAsync(); - await page.Locator("h2 >> text=About").TextContentAsync(); - }); - } - } -} -#endif \ No newline at end of file diff --git a/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests_v4.cs b/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests_v4.cs deleted file mode 100644 index 0e97813..0000000 --- a/Source/CDR.DataRecipient.E2ETests/US23863_MDR_E2ETests_v4.cs +++ /dev/null @@ -1,734 +0,0 @@ -using CDR.DataRecipient.E2ETests.Pages; -using FluentAssertions; -using Microsoft.Data.SqlClient; -using Microsoft.Playwright; -using System; -using System.Threading.Tasks; -using Xunit; - -#nullable enable - -namespace CDR.DataRecipient.E2ETests -{ - public class US23863_MDR_E2ETests_v4 : BaseTest_v3, IClassFixture - { - private const string SWAGGER_BANKING_IFRAME = "cds-banking/index.html"; - private const string SWAGGER_ENERGY_IFRAME = "cds-energy/index.html"; - private const string SWAGGER_COMMON_IFRAME = "cds-common/index.html"; - - // Pre-generated ID Token used in IDTokenhelper test - const string IDTOKEN = @"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00iLCJraWQiOiJkYTNiYzA3OTlhMjlkODM2NWU2OWVkZjJiZmQxMzVh" + - "MDhjNGRkYmE3ZWM3ZTFiNmVhYjkzNWY5NjcyNWExZTNhIn0.afEh0qVHeHSYqu-Q-leao8EQe-cGR8m2-fszGZQOq0dBBQNGRaFwSTKn3u4KqGTXXI-w" + - "1p20YHe_JMH4k1B7_NG93YXpYsx1pfEc_qa5x7_9gYvN_X6NLESuxVQW3TJBgsmE-LMu6TjSZzXtt_HkKk0V-q5epsrWgYX-WWR4Jk-yAUEYxrqA-bGm" + - "EKLbY9rLbZaituis0E4fYP4SF9keL2H6iJ4h99F4MrEKz8K7HgsQ1SkrlFw9ApR3Wnl3NaLXsEcJJZqZcpXkHUaIA76UChG5tvZTV436Jyz_ehxbcQeK" + - "9Yx5ZhXWY2Ud9K0LZ3hQ3A0SdEGkhExGbUpiNecAGA.YtIsaDgqhifPIsRj.MHSYKFpgyc0opB0LqAQWxMaikTTc7dviOd4tSLInpQ8KwnrCHnVKJFJq" + - "2P6rFz26xorAFHtZZeeqG2RmAehMFWBxbWuSTLgmXqF1SmhVgAT6XHgPNBZE_KM4OE4FrYd2eMxbLSYVbGs1zcu8rxV_Fal74w_2qgVqiuR-8DgKLqkb" + - "dLrW0F7XXl_PtIZj4vWdwbon7SQldvk0usg5ZxqC5PeyrV2AYhu_0_VNRnwAxcbzvYdh9HxckrdYACUtcjcKi_VSPd9gw4urq58NnCSKghBD6rJvHqW1" + - "qdL32UTf-V58Ma9bRaItlUr_DOCFRp-vT7nBJwn3EDJWL_GE2QjOu6Zy-GNwv4p220Ct5GmqRVfgMXjZYOzZieBBHIU0AyXIohlF2PPC4NAXlgpFacna" + - "RKNZb3et6B9WsqEMlDhMajMeY1DWgQb0eSXrAtX4QidFucEirIhV2XwMFi60uoycuPbk2ziKCRQCdS-TiTCkrKH72GoR_8v27ddkPKF8cspqPNTmJdJi" + - "d84jyoWTgo7fMa3xf-Sa7OO9jNPuAChtpX3t9amyq-NQfoAlSRu5fUZcWgzxKcJbnHlWG71QH6ALF-4HyMML3brHlV1HoIybMyUKpCkz_qJ6uK0JQC90" + - "PMJ4f7hkFc5wZ_V4E6BOrX635SPVxk0ts4G2AVpi1nDfjajd_Ljg8ni1mE9PDuWdYap2hxRDJnmJ5XssR0FlMcWRPO3IJCjrdSmtMKxdePq3T_UEXK8C" + - "3sWs17k0URmlxnkjp6Qe6YSzAkALwgHyPCD9IqqnpFAXG88669fFWgCH7uMu9dyJI-Agwc3ufU1NAQRnknowj3DKp5DuhYL1AL-P4c8d7mlI5bpwee2c" + - "WxLQMDog4hp-FQMuir7IacY2lJ9Ocvoirf6yM-R5-lQka74poe2PGOu2QlrywvdHvJ-ExSNkT5mNAZPCPYT-eHVqdeV_aQCBu8bRD8nUeq5o6ZJMzOlr" + - "V3LDS9jyGKRVvQf7YyXHODPnTMeL78mgD_V4WSdme54-J_tnOQh-j9a58CH_7E6AlD6ahc27K1sA8hG-vZ_jRUG1QXhJfER5pQjCoPfEtWzGbJF58LYC" + - "piwR0KE15LtpJgKPBwbBFQwpBRcZDEtouBZLFyMjfNGg1cnTfdlblEtnZcE50_ZVjTfk3n1nNjRlYHceaGnd7GYINBNl87JZCd2Dn_-JmRJfKK2vnF17" + - "HA3dUOHz_rUJa6hQd77WwWDxwU7oG1bpmoRDjgjl1AxXmJVSuhkgyK6JEDgeF6SDPDsU1yym_9ACitE1FjS8VAqU3e8cgoaDD5BzASt9OmApsHQHRQur" + - "HOh05w_b63JHd3Cg_-ASojF78GjKQ2TWV-jZn65nacY5NSIU3Qxt87UbR7Cr64UZMJAhRQ0VoXmdHpG6dSjtYEP20HTgvTI7uQD8Ibw9C7jILUi76HO_" + - "-n3R2errngQrYNunYmW9q45eDdngOiA_N5HB3rS3y3-V3kYnkW8Wio-gSzuGYBoAM4OT5QFGbs7QYw0PR4wYDk7iVIkfCf5vDlVb2ehcfNQx2m5gYYuW" + - "ppVENCqtjrsUmAxmyPZ5v_Fvh8N36J-4IaKNcv9J3ic4mm0yUdCLVCRxBjpsfw.xPc7ZQDVN11iHX41af-wvg"; - - static string GetClientId() - { - using var mdrConnection = new SqlConnection(BaseTest_v3.DATARECIPIENT_CONNECTIONSTRING); - mdrConnection.Open(); - - using var selectCommand = new SqlCommand($"select clientid from registration", mdrConnection); - string? clientId = Convert.ToString(selectCommand.ExecuteScalar()); - - if (String.IsNullOrEmpty(clientId)) - throw new Exception("No registrations found"); - - return clientId; - } - - public static async Task TestToken(IPage page, string menuText, string? expectedToken) - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Consents").ClickAsync(); - await page.Locator("h2 >> text=Consents").TextContentAsync(); - - // Act - Click actions button and submenu item - await page.Locator("button:has-text(\"Actions\")").ClickAsync(); - await page.Locator($"a >> text={menuText}").ClickAsync(); - - // Act - Check modal opens - await page.Locator("div#modal-token >> h5.modal-title >> text=Token Contents").TextContentAsync(); - - // Assert - Check actual token matches expected token - var token = await page.Locator(@"div#modal-token >> div.modal-body").TextContentAsync(); - token.Should().NotBeNullOrEmpty(); - token.Should().Be(expectedToken); - } - - static async Task TestResults(IPage page, string label, string? value = null) - { - // Check for label and value - if (value != null) - await page.Locator($"div.results >> dl >> dt:has-text(\"{label}\") + dd:has-text(\"{value}\")").TextContentAsync(); - // Just check for label - else - await page.Locator($"div.results >> dl >> dt:has-text(\"{label}\")").TextContentAsync(); - } - - [Fact] - public async Task AC01_HomePage() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC01_HomePage)}", async (page) => - { - // Act - Goto home page - await page.GotoAsync(WEB_URL); - - // Assert - Check banner - await page.Locator("h1 >> text=Mock Data Recipient").TextContentAsync(); - await page.Locator("text=Welcome to the Mock Data Recipient").TextContentAsync(); - await page.Locator("a >> text=Settings").TextContentAsync(); - await page.Locator("a >> text=About").TextContentAsync(); - - // Assert - Check menu items exists - await page.Locator("a >> text=Home").TextContentAsync(); - await page.Locator("a >> text=Discover Data Holders").TextContentAsync(); - await page.Locator("a >> text=Get SSA").TextContentAsync(); - await page.Locator("a >> text=Dynamic Client Registration").TextContentAsync(); - await page.Locator("a >> text=Consents").TextContentAsync(); - await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Common\")").TextContentAsync(); - await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Banking\")").TextContentAsync(); - await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Energy\")").TextContentAsync(); - await page.Locator("a >> text=PAR").TextContentAsync(); - await page.Locator("span >> text=Utilities").TextContentAsync(); - await page.Locator("a >> text=ID Token Helper").TextContentAsync(); - await page.Locator("a >> text=Private Key JWT Generator").TextContentAsync(); - Assert.True(true); - }); - } - - [Fact] - public async Task AC02_01_DiscoverDataHolders_Banking() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC02_01_DiscoverDataHolders_Banking)}", async (page) => - { - await DataHolders_Discover(page, "BANKING", "2", 30); - }); - } - - [Fact] - public async Task AC02_02_DiscoverDataHolders_Energy() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC02_02_DiscoverDataHolders_Energy)}", async (page) => - { - await DataHolders_Discover(page, "ENERGY", "2", 2); - }); - } - - [Fact] - public async Task AC02_03_DiscoverDataHolders_Telco() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC02_03_DiscoverDataHolders_Telco)}", async (page) => - { - await DataHolders_Discover(page, "TELCO", "2", 0); // Currently no Telco dataholders, so 0 = no additional dataholders loaded - }); - } - - [Fact] - public async Task AC02_04_DiscoverDataHolders_AnyIndustry() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC02_04_DiscoverDataHolders_AnyIndustry)}", async (page) => - { - await DataHolders_Discover(page, "ALL", "2", 0); // Should have loaded all dataholders by now, so 0 = no additional dataholders loaded - }); - } - - [Theory] - [InlineData("ALL", "3", null, "NotAcceptable - Not Acceptable")] - [InlineData("ALL", "foo", null, "BadRequest - Bad Request")] - [InlineData("BANKING", "3", null, "NotAcceptable - Not Acceptable")] - [InlineData("BANKING", "foo", null, "BadRequest - Bad Request")] - [InlineData("ENERGY", "3", null, "NotAcceptable - Not Acceptable")] - [InlineData("ENERGY", "foo", null, "BadRequest - Bad Request")] - [InlineData("TELCO", "3", null, "NotAcceptable - Not Acceptable")] - [InlineData("TELCO", "foo", null, "BadRequest - Bad Request")] - public async Task AC02_99_DiscoverDataHolders(string industry = "ALL", string version = "2", int? expectedRecords = 32, string? expectedError = null) - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC02_99_DiscoverDataHolders)} - Industry={industry} - Version={version}", async (page) => - { - await DataHolders_Discover(page, industry, version, expectedRecords, expectedError); - }); - } - - [Theory] - [InlineData("BANKING", "1", DR_BRANDID, DR_SOFTWAREPRODUCTID, "NotAcceptable")] - [InlineData("BANKING", "2", DR_BRANDID, DR_SOFTWAREPRODUCTID, "NotAcceptable")] - [InlineData("BANKING", "3", DR_BRANDID, DR_SOFTWAREPRODUCTID, "OK - SSA Generated")] - [InlineData("BANKING", "4", DR_BRANDID, DR_SOFTWAREPRODUCTID, "NotAcceptable")] - public async Task AC03_GetSSA(string industry, string version, string drBrandId, string drSoftwareProductId, string expectedMessage) - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC03_GetSSA)} - Version={version} - DR_BrandId={drBrandId} - DR_SoftwareProductId={drSoftwareProductId}", async (page) => - { - await SSA_Get(page, industry, version, drBrandId, drSoftwareProductId, expectedMessage); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID)] - [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID)] // Also test for Energy DH - public async Task AC04_DynamicClientRegistration(string dhBrandId = DH_BRANDID, string drBrandId = DR_BRANDID, string drSoftwareProductId = DR_SOFTWAREPRODUCTID) - { - string testName = $"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC04_DynamicClientRegistration)} - DH_BrandId={dhBrandId} - DR_BrandId={drBrandId} - DR_SoftwareProductId={drSoftwareProductId}"; - try - { - await ArrangeAsync(testName, async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - }); - - await TestAsync(testName, async (page) => - { - await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId); - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - }); - } - } - - public delegate Task ConsentsDelegate(IPage page, ConsentAndAuthorisationResponse response); - public async Task Test_Consents(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts, string testName, ConsentsDelegate test) - { - try - { - string? dhClientId = null; - ConsentAndAuthorisationResponse? cdrArrangement = null; - await ArrangeAsync($"{testName} - DH_BrandId={dhBrandId}", async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) - ?? throw new NullReferenceException(nameof(dhClientId)); - cdrArrangement = await NewConsentAndAuthorisationWithPAR(page, dhClientId, customerId, customerAccounts, dhBrandId) - ?? throw new NullReferenceException(nameof(cdrArrangement)); - - }); - - await TestAsync($"{testName} - DH_BrandId={dhBrandId}", async (page) => - { - await test(page, cdrArrangement ?? throw new NullReferenceException(nameof(cdrArrangement))); - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - }); - } - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_ViewIDToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC06_Consents_ViewIDToken)}", async (page, response) => - { - await TestToken(page, "View ID Token", response?.IDToken ?? throw new ArgumentNullException(nameof(response.IDToken))); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_ViewAccessToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC06_Consents_ViewAccessToken)}", async (page, response) => - { - await TestToken(page, "View Access Token", response?.AccessToken ?? throw new ArgumentNullException(nameof(response.AccessToken))); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_ViewRefreshToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC06_Consents_ViewRefreshToken)}", async (page, response) => - { - await TestToken(page, "View Refresh Token", response?.RefreshToken ?? throw new ArgumentNullException(nameof(response.RefreshToken))); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING, "Jane", "Wilson")] - [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY, "Mary", "Moss")] // Also test for Energy DH - public async Task AC06_Consents_ViewUserInfo(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts, string expectedGivenName, string expectedFamilyName) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC06_Consents_ViewUserInfo)}", async (page, response) => - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC06_Consents_ViewUserInfo)}", async (page) => - { - var expected = new (string, string?)[] - { - ("given_name", expectedGivenName), - ("family_name", expectedFamilyName), - ("name", $"{expectedGivenName} {expectedFamilyName}"), - ("aud", ASSERT_JSON2_ANYVALUE), - ("iss", ASSERT_JSON2_ANYVALUE), - ("sub", ASSERT_JSON2_ANYVALUE), - }; - - await TestInfo(page, "UserInfo", "User Info", "200", expected); - }); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_Introspect(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC06_Consents_Introspect)}", async (page, response) => - { - var expected = new (string, string?)[] - { - ("cdr_arrangement_id", response?.CDRArrangementID ?? throw new ArgumentNullException(nameof(response.CDRArrangementID))), - ("scope", ASSERT_JSON2_ANYVALUE), - ("exp", ASSERT_JSON2_ANYVALUE), - ("active", "True"), - }; - - await TestInfo(page, "Introspect", "Introspection", "200", expected); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING, - "openid profile common:customer.basic:read common:customer.detail:read bank:accounts.basic:read bank:accounts.detail:read bank:transactions:read bank:regular_payments:read bank:payees:read")] - [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY, - "openid profile common:customer.basic:read common:customer.detail:read energy:accounts.basic:read energy:accounts.detail:read energy:accounts.concessions:read energy:accounts.paymentschedule:read energy:billing:read energy:electricity.servicepoints.basic:read energy:electricity.servicepoints.detail:read energy:electricity.der:read energy:electricity.usage:read")] // Also test for Energy DH - public async Task AC06_Consents_Refresh_Access_Token(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts, string expectedScope) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC06_Consents_Refresh_Access_Token)}", async (page, response) => - { - var expected = new (string, string?)[] - { - ("id_token", ASSERT_JSON2_ANYVALUE), - ("access_token", ASSERT_JSON2_ANYVALUE), - ("refresh_token", ASSERT_JSON2_ANYVALUE), - ("expires_in", ACCESSTOKENLIFETIMESECONDS), - ("token_type", "Bearer"), - ("scope", expectedScope), - ("cdr_arrangement_id", ASSERT_JSON2_ANYVALUE), - }; - - await TestInfo(page, "Refresh Access Token", "Refresh Access Token", "200", expected); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_Revoke_Arrangement(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC06_Consents_Revoke_Arrangement)}", async (page, response) => - { - await TestInfo(page, "Revoke Arrangement", "Revoke Arrangement", "204"); - await ScreenshotAsync(page, "-Modal"); - - await page.Locator("div#modal-info >> div.modal-footer >> a >> text=Refresh Page").ClickAsync(); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_Revoke_AccessToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC06_Consents_Revoke_AccessToken)}", async (page, response) => - { - await TestInfo(page, "Revoke Access Token", "Revoke Access Token", "200"); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_Revoke_RefreshToken(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC06_Consents_Revoke_RefreshToken)}", async (page, response) => - { - await TestInfo(page, "Revoke Refresh Token", "Revoke Refresh Token", "200"); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC06_Consents_Delete_Local(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - await Test_Consents(dhBrandId, drBrandId, drSoftwareProductId, customerId, customerAccounts, $"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC06_Consents_Delete_Local)}", async (page, response) => - { - await Consents_DeleteLocal(page); - }); - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - [InlineData(DH_BRANDID_ENERGY, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_ENERGY, CUSTOMERACCOUNTS_ENERGY)] // Also test for Energy DH - public async Task AC07_PAR(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - try - { - string testName = $"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC07_PAR)}"; - string? dhClientId = null; - ConsentAndAuthorisationResponse? cdrArrangement = null; - await ArrangeAsync(testName, async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) - ?? throw new NullReferenceException(nameof(dhClientId)); - cdrArrangement = await NewConsentAndAuthorisationWithPAR(page, dhClientId, customerId, customerAccounts, dhBrandId) - ?? throw new NullReferenceException(nameof(cdrArrangement)); - }); - - await TestAsync(testName, async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - ParPage parPage = new ParPage(page); - await parPage.GotoPar(); - await parPage.CompleteParForm(dhClientId, dhBrandId, cdrArrangement: cdrArrangement!.CDRArrangementID, sharingDuration: SHARING_DURATION); - await parPage.ClickInitiatePar(); - await parPage.ClickAuthorizeUrl(); - - // Act/Assert - Perform consent and authorisation - await ConsentAndAuthorisation2(page, customerId, customerAccounts); - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - }); - } - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - public async Task AC08_ConsumerDataSharing_Banking(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - try - { - string testName = $"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC08_ConsumerDataSharing_Banking)}"; - string? dhClientId = null; - ConsentAndAuthorisationResponse? cdrArrangement = null; - await ArrangeAsync(testName, async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) - ?? throw new NullReferenceException(nameof(dhClientId)); - cdrArrangement = await NewConsentAndAuthorisationWithPAR(page, dhClientId, customerId, customerAccounts, dhBrandId) - ?? throw new NullReferenceException(nameof(cdrArrangement)); - }); - - await TestAsync(testName, async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Banking\")").ClickAsync(); - await page.Locator("h2 >> text=Data Sharing - Banking").TextContentAsync(); - await Task.Delay(2000); // give screen time to refresh - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - }); - } - } - - [Theory] - [InlineData(DH_BRANDID, DR_BRANDID, DR_SOFTWAREPRODUCTID, CUSTOMERID_BANKING, CUSTOMERACCOUNTS_BANKING)] - public async Task AC08_ConsumerDataSharing_Banking_AccountsGet(string dhBrandId, string drBrandId, string drSoftwareProductId, string customerId, string customerAccounts) - { - try - { - string testName = $"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC08_ConsumerDataSharing_Banking_AccountsGet)}"; - string? dhClientId = null; - ConsentAndAuthorisationResponse? cdrArrangement = null; - await ArrangeAsync(testName, async (page) => - { - await DataHolders_Discover(page, "ALL", "2", -1); // get all dh brands - await SSA_Get(page, "ALL", "3", drBrandId, drSoftwareProductId, "OK - SSA Generated"); - dhClientId = await ClientRegistration_Create(page, dhBrandId, drBrandId, drSoftwareProductId) - ?? throw new NullReferenceException(nameof(dhClientId)); - cdrArrangement = await NewConsentAndAuthorisationWithPAR(page, dhClientId, customerId, customerAccounts, dhBrandId) - ?? throw new NullReferenceException(nameof(cdrArrangement)); - }); - - await TestAsync(testName, async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("span:text(\"Consumer Data Sharing\") + ul >> a:text(\"Banking\")").ClickAsync(); - await page.Locator("h2 >> text=Data Sharing - Banking").TextContentAsync(); - - // Arrange - Get Swagger iframe - var iFrame = page.FrameByUrl($"{WEB_URL}/{SWAGGER_BANKING_IFRAME}") ?? throw new Exception($"IFrame not found - {SWAGGER_BANKING_IFRAME}"); - - // Wait for the CDR arrangement to be added and populated. - System.Threading.Thread.Sleep(10000); - - // Arrange - Select CDR arrangemment - await iFrame.SelectOptionAsync( - "select", - new string[] { - cdrArrangement!.CDRArrangementID ?? throw new NullReferenceException(nameof(cdrArrangement.CDRArrangementID)) - }, - new FrameSelectOptionOptions() { Timeout = 90000 } - ); - - // Arrange - Click GET​/energy​/accountsGet Energy Accounts - await iFrame.ClickAsync("text=Energy GET/energy/plansGet Generic PlansGET/energy/plans/{planId}Get Generic Pla >> [aria-label=\"get ​\\/energy​\\/accounts\"]"); - - // Arrange - Click Try it out - await iFrame.ClickAsync("text=Try it out"); - - // Arrange - Set x-v - await iFrame.FillAsync("[placeholder=\"x-v\"]", "1"); - - // Act - Click Execute - await iFrame.ClickAsync("text=Execute"); - - // Assert - Status code should be 200 - var statusCode = await iFrame.Locator("div.responses-inner > div > div > table > tbody > tr > td.response-col_status").TextContentAsync(); - statusCode.Should().Be("200"); - }); - } - finally - { - await CleanupAsync(async (page) => - { - try { await ClientRegistration_Delete(page); } catch { }; - }); - } - } - - [Theory] - [InlineData(IDTOKEN)] - public async Task AC09_IDTokenHelper(string encryptedToken) - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC09_IDTokenHelper)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=ID Token Helper").ClickAsync(); - await page.Locator("h2 >> text=ID Token Helper").TextContentAsync(); - - // Arrange - Enter id token to decrypt - await page.Locator("textarea[name=\"IdTokenEncrypted\"]").FillAsync(encryptedToken); - - // Act - await page.Locator("text=Decrypt ID Token").ClickAsync(); - - // Assert - Check results - await TestResults(page, "nbf", "1687210290"); - await TestResults(page, "exp", "1687210590"); - await TestResults(page, "iss", $"https://mock-data-holder:8001"); - await TestResults(page, "aud", "549076d1-785e-46c8-b1f4-8074e859c004"); - await TestResults(page, "nonce", "998c7257-8e42-4ef9-81cc-09d08eff413f"); - await TestResults(page, "iat", "1687210290"); - await TestResults(page, "at_hash", "wvmLTnV0mNAEeqVrmgvnuw"); - await TestResults(page, "c_hash", "fRr6y32yxRN257qQ9Rzlvw"); - await TestResults(page, "auth_time", "1687210289"); - await TestResults(page, "sub", "GYFWjFhkegCHsQe0KVvFhg=="); - await TestResults(page, "name", "jwilson"); - await TestResults(page, "family_name", "Wilson"); - await TestResults(page, "given_name", "Jane"); - await TestResults(page, "updated_at", "1687210290"); - await TestResults(page, "acr", "urn:cds.au:cdr:2"); - - Assert.True(true); - }); - } - - [Fact] - public async Task AC10_PrivateKeyJWTGenerator() - { - - await TestAsync($"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC10_PrivateKeyJWTGenerator)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Private Key JWT Generator").ClickAsync(); - await page.Locator("h2 >> text=Private Key JWT Generator").TextContentAsync(); - await page.Locator("input[name=\"Jti\"]").FillAsync("foo"); - - // Act - Click generate button - await page.Locator("form >> text=Generate").ClickAsync(); - - // Assert - Client assertion was generated, and check for View Decoded button - var clientAssertion = await page.Locator("div.results >> div.code").TextContentAsync(); - clientAssertion.Should().NotBeNullOrWhiteSpace(); - await page.Locator("a >> text=View Decoded").TextContentAsync(); - - // Assert - Check client assertions claims - await TestResults(page, "sub", "c6327f87-687a-4369-99a4-eaacd3bb8210"); - await TestResults(page, "jti", "foo"); - await TestResults(page, "iat"); // just check claim exists - await TestResults(page, "exp"); // just check claim exists - await TestResults(page, "iss", "c6327f87-687a-4369-99a4-eaacd3bb8210"); - await TestResults(page, "aud", $"https://{BaseTest_v3.HOSTNAME_REGISTER}:7001/idp/connect/token"); - }); - } - - [Fact] - public async Task AC11_Settings() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC11_Settings)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=Settings").ClickAsync(); - await page.Locator("h2 >> text=Settings").TextContentAsync(); - Assert.True(true); - }); - } - - [Fact] - public async Task AC12_About() - { - await TestAsync($"{nameof(US23863_MDR_E2ETests_v4)} - {nameof(AC12_About)}", async (page) => - { - // Arrange - Goto home page, click menu button, check page loaded - await page.GotoAsync(WEB_URL); - await page.Locator("a >> text=About").ClickAsync(); - await page.Locator("h2 >> text=About").TextContentAsync(); - Assert.True(true); - }); - } - - } -} \ No newline at end of file diff --git a/Source/CDR.DataRecipient.E2ETests/US46331_MDR_E2ETests_ParFapi.cs b/Source/CDR.DataRecipient.E2ETests/US46331_MDR_E2ETests_ParFapi.cs index 3190d55..eda2134 100644 --- a/Source/CDR.DataRecipient.E2ETests/US46331_MDR_E2ETests_ParFapi.cs +++ b/Source/CDR.DataRecipient.E2ETests/US46331_MDR_E2ETests_ParFapi.cs @@ -18,7 +18,7 @@ namespace CDR.DataRecipient.E2ETests { - public class US46331_MDR_E2ETests_ParFapi : BaseTest_v3, IClassFixture + public class US46331_MDR_E2ETests_ParFapi : BaseTest, IClassFixture { public const string DH_DEFAULT_PAR_SCOPE = "openid profile common:customer.basic:read bank:accounts.basic:read bank:transactions:read cdr:registration"; diff --git a/Source/CDR.DataRecipient.E2ETests/US46352_MDR_E2ETests_AuthCodeFlowJarm.cs b/Source/CDR.DataRecipient.E2ETests/US46352_MDR_E2ETests_AuthCodeFlowJarm.cs index a2f1513..9acc1d6 100644 --- a/Source/CDR.DataRecipient.E2ETests/US46352_MDR_E2ETests_AuthCodeFlowJarm.cs +++ b/Source/CDR.DataRecipient.E2ETests/US46352_MDR_E2ETests_AuthCodeFlowJarm.cs @@ -12,7 +12,7 @@ namespace CDR.DataRecipient.E2ETests { - public class US46352_MDR_E2ETests_AuthCodeFlowJarm : BaseTest_v3, IClassFixture + public class US46352_MDR_E2ETests_AuthCodeFlowJarm : BaseTest, IClassFixture { private const string WRONG_CERTIFICATE_FILENAME = "Certificates/client.pfx"; diff --git a/Source/CDR.DataRecipient.IntegrationTests/CDR.DataRecipient.IntegrationTests.csproj b/Source/CDR.DataRecipient.IntegrationTests/CDR.DataRecipient.IntegrationTests.csproj index 3c88364..ab55e78 100644 --- a/Source/CDR.DataRecipient.IntegrationTests/CDR.DataRecipient.IntegrationTests.csproj +++ b/Source/CDR.DataRecipient.IntegrationTests/CDR.DataRecipient.IntegrationTests.csproj @@ -3,9 +3,9 @@ net6.0 false - 1.2.4 - 1.2.4 - 1.2.4 + 1.2.5 + 1.2.5 + 1.2.5 @@ -19,6 +19,7 @@ + diff --git a/Source/CDR.DataRecipient.IntegrationTests/US61217_MDR_UserInfo.cs b/Source/CDR.DataRecipient.IntegrationTests/US61217_MDR_UserInfo.cs new file mode 100644 index 0000000..5b0d7c2 --- /dev/null +++ b/Source/CDR.DataRecipient.IntegrationTests/US61217_MDR_UserInfo.cs @@ -0,0 +1,57 @@ +using FluentAssertions; +using Xunit; +using System.Linq; +using CDR.DataRecipient.SDK.Models; +using Moq; +using CDR.DataRecipient.SDK.Services.DataHolder; +using Moq.Protected; +using System.Net.Http; +using System.Threading.Tasks; +using System.Net; +using System.Threading; +using System.Security.Cryptography.X509Certificates; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using CDR.DataRecipient.SDK.Services.Tokens; +using System; +using Xunit.Abstractions; +using Newtonsoft.Json; + +namespace CDR.DataRecipient.IntegrationTests +{ + public class US61217_MDR_UserInfo : BaseTest + { + [Fact] + public async Task AC01_DhUserInfoWithComplexAddress_ShouldNotThrowException() + { + // Arrange + + // Mock a DH Client with a complex json result for the User Info endpoint. + var mockDhResponseHandler = new Mock(); + var mockDhApiRequest = mockDhResponseHandler.Protected().Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()); + mockDhApiRequest.ReturnsAsync(new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent("{\"given_name\":\"Kamilla\",\"family_name\":\"Smith\",\"name\":\"Kamilla Smith\",\"aud\":\"10e6a335-78ab-410c-8722-7a13f492a9c4\",\"iss\":\"https://mock-data-holder:8001\",\"sub\":\"gAuwOMal3lXIdTDBZrykDg==\",\"address\": { \"formatted\": \"2 Lonsdale Street, Melbourne, VIC 3000, Australia\", \"street_address\": \"2 Lonsdale Street\", \"locality\": \"Melbourne\", \"region\": \"VIC\", \"postal_code\": \"3000\", \"country\": \"Australia\"}}") + }); + var mockDhClient = new HttpClient(mockDhResponseHandler.Object) { BaseAddress = new Uri("https://localhost/") }; + + // Mock Infosec Service to use the mock DH Endpoint + var mockInfosecService = new Mock( + new Mock().Object, new Mock>().Object, new Mock().Object, new Mock().Object); + mockInfosecService.Protected() + .Setup("GetHttpClient", ItExpr.IsAny(), ItExpr.IsAny(), ItExpr.IsAny()) + .Returns(mockDhClient) + .Verifiable(); + + // Act + var resultException = await Record.ExceptionAsync(() => mockInfosecService.Object.UserInfo("https://localhost/", null, string.Empty)); + + // Assert + resultException.Should().BeNull(); + } + } +} diff --git a/Source/CDR.DataRecipient.Repository.SQL/CDR.DataRecipient.Repository.SQL.csproj b/Source/CDR.DataRecipient.Repository.SQL/CDR.DataRecipient.Repository.SQL.csproj index 144bbd2..4d9b104 100644 --- a/Source/CDR.DataRecipient.Repository.SQL/CDR.DataRecipient.Repository.SQL.csproj +++ b/Source/CDR.DataRecipient.Repository.SQL/CDR.DataRecipient.Repository.SQL.csproj @@ -2,9 +2,9 @@ net6.0 - 1.2.4 - 1.2.4 - 1.2.4 + 1.2.5 + 1.2.5 + 1.2.5 diff --git a/Source/CDR.DataRecipient.SDK/CDR.DataRecipient.SDK.csproj b/Source/CDR.DataRecipient.SDK/CDR.DataRecipient.SDK.csproj index 6059a98..8a5adf3 100644 --- a/Source/CDR.DataRecipient.SDK/CDR.DataRecipient.SDK.csproj +++ b/Source/CDR.DataRecipient.SDK/CDR.DataRecipient.SDK.csproj @@ -2,9 +2,9 @@ net6.0 - 1.2.4 - 1.2.4 - 1.2.4 + 1.2.5 + 1.2.5 + 1.2.5 diff --git a/Source/CDR.DataRecipient.SDK/Models/UserInfo.cs b/Source/CDR.DataRecipient.SDK/Models/UserInfo.cs index de3f509..30b0cce 100644 --- a/Source/CDR.DataRecipient.SDK/Models/UserInfo.cs +++ b/Source/CDR.DataRecipient.SDK/Models/UserInfo.cs @@ -5,7 +5,7 @@ namespace CDR.DataRecipient.SDK.Models { [Serializable] - public class UserInfo : Dictionary + public class UserInfo : Dictionary { public UserInfo() : base() { } diff --git a/Source/CDR.DataRecipient.SDK/Services/BaseService.cs b/Source/CDR.DataRecipient.SDK/Services/BaseService.cs index 7e95414..b18fd51 100644 --- a/Source/CDR.DataRecipient.SDK/Services/BaseService.cs +++ b/Source/CDR.DataRecipient.SDK/Services/BaseService.cs @@ -30,7 +30,7 @@ protected BaseService( _serviceConfiguration = serviceConfiguration; } - protected HttpClient GetHttpClient( + protected virtual HttpClient GetHttpClient( X509Certificate2 clientCertificate = null, string accessToken = null, string version = null) diff --git a/Source/CDR.DataRecipient.Web/CDR.DataRecipient.Web.csproj b/Source/CDR.DataRecipient.Web/CDR.DataRecipient.Web.csproj index 5d3a635..1dde373 100644 --- a/Source/CDR.DataRecipient.Web/CDR.DataRecipient.Web.csproj +++ b/Source/CDR.DataRecipient.Web/CDR.DataRecipient.Web.csproj @@ -5,9 +5,9 @@ win-x64;linux-x64 e18cd40c-c7d1-4df4-8448-82de536a628c Linux - 1.2.4 - 1.2.4 - 1.2.4 + 1.2.5 + 1.2.5 + 1.2.5 diff --git a/Source/CDR.DataRecipient/CDR.DataRecipient.csproj b/Source/CDR.DataRecipient/CDR.DataRecipient.csproj index a328e47..d38e579 100644 --- a/Source/CDR.DataRecipient/CDR.DataRecipient.csproj +++ b/Source/CDR.DataRecipient/CDR.DataRecipient.csproj @@ -2,9 +2,9 @@ net6.0 - 1.2.4 - 1.2.4 - 1.2.4 + 1.2.5 + 1.2.5 + 1.2.5 diff --git a/Source/CDR.DiscoverDataHolders/CDR.DiscoverDataHolders.csproj b/Source/CDR.DiscoverDataHolders/CDR.DiscoverDataHolders.csproj index e91e41e..8d5442f 100644 --- a/Source/CDR.DiscoverDataHolders/CDR.DiscoverDataHolders.csproj +++ b/Source/CDR.DiscoverDataHolders/CDR.DiscoverDataHolders.csproj @@ -3,9 +3,9 @@ net6.0 v4 <_FunctionsSkipCleanOutput>true - 1.2.4 - 1.2.4 - 1.2.4 + 1.2.5 + 1.2.5 + 1.2.5 diff --git a/Source/DockerCompose/docker-compose.E2ETests.yml b/Source/DockerCompose/docker-compose.E2ETests.yml new file mode 100644 index 0000000..389a7c4 --- /dev/null +++ b/Source/DockerCompose/docker-compose.E2ETests.yml @@ -0,0 +1,55 @@ +# Docker compose file used to execute E2E tests for the Mock Data Recipient. +# It extends docker-compose.TestsBase.yml. + + +version: '3.8' + +name: mock-data-recipient-e2e-tests + +services: + mock-register: + container_name: mock-register-mdr-e2e + extends: + file: docker-compose.TestsBase.yml + service: mock-register + + mock-data-holder: + container_name: mock-data-holder-mdr-e2e + extends: + file: docker-compose.TestsBase.yml + service: mock-data-holder + + mock-data-holder-energy: + container_name: mock-data-holder-energy-mdr-e2e + environment: + - CdrAuthServer__SupportJarmEncryption=true + extends: + file: docker-compose.TestsBase.yml + service: mock-data-holder-energy + + mock-data-recipient: + container_name: mock-data-recipient-mdr-e2e + extends: + file: docker-compose.TestsBase.yml + service: mock-data-recipient + + mssql: + container_name: sql-mdr-e2e + extends: + file: docker-compose.TestsBase.yml + service: mssql + + mock-data-recipient-e2e-tests: + container_name: mock-data-recipient-e2e-tests + image: mock-data-recipient-e2e-tests + hostname: mock-data-recipient-e2e-tests + build: + context: .. + dockerfile: Dockerfile.e2e-tests + environment: + - ASPNETCORE_ENVIRONMENT=Release + volumes: + - "./_temp/mock-data-recipient-e2e-tests/testresults:/testresults" + depends_on: + mock-data-recipient: + condition: service_healthy \ No newline at end of file diff --git a/Source/DockerCompose/docker-compose.IntegrationTests.yml b/Source/DockerCompose/docker-compose.IntegrationTests.yml new file mode 100644 index 0000000..cc63502 --- /dev/null +++ b/Source/DockerCompose/docker-compose.IntegrationTests.yml @@ -0,0 +1,53 @@ +# Docker compose file used to execute E2E tests for the Mock Data Recipient. +# It extends docker-compose.TestsBase.yml. + +version: '3.8' + +name: mock-data-recipient-integration-tests + +services: + mock-register: + container_name: mock-register-mdr-int + extends: + file: docker-compose.TestsBase.yml + service: mock-register + + mock-data-holder: + container_name: mock-data-holder-mdr-int + extends: + file: docker-compose.TestsBase.yml + service: mock-data-holder + + mock-data-holder-energy: + container_name: mock-data-holder-energy-mdr-int + extends: + file: docker-compose.TestsBase.yml + service: mock-data-holder-energy + + mock-data-recipient: + container_name: mock-data-recipient-mdr-int + extends: + file: docker-compose.TestsBase.yml + service: mock-data-recipient + + mssql: + container_name: sql-mdr-int + extends: + file: docker-compose.TestsBase.yml + service: mssql + + mock-data-recipient-integration-tests: + container_name: mock-data-recipient-integration-tests + image: mock-data-recipient-integration-tests + build: + context: .. + dockerfile: Dockerfile.integration-tests + environment: + - ASPNETCORE_ENVIRONMENT=Release + volumes: + - "./_temp/mock-data-recipient-integration-tests/tmp:/tmp" + - "./_temp/mock-data-recipient-integration-tests/testresults:/testresults" + depends_on: + mock-data-recipient: + condition: service_healthy + diff --git a/Source/docker-compose.E2ETests.yml b/Source/DockerCompose/docker-compose.TestsBase.yml similarity index 57% rename from Source/docker-compose.E2ETests.yml rename to Source/DockerCompose/docker-compose.TestsBase.yml index 68f67d1..6446791 100644 --- a/Source/docker-compose.E2ETests.yml +++ b/Source/DockerCompose/docker-compose.TestsBase.yml @@ -1,4 +1,5 @@ -# Docker compose for E2E tests +# Docker compose base file for E2E and integration tests. +# This compose file is extended by docker-compose.E2ETests.yml and docker-compose.IntegrationTests.yml files to compose up and execute E2E or integration tests the Mock Data Recipient. version: '3.8' @@ -10,14 +11,12 @@ services: ports: - "7000:7000" - "7001:7001" + - "7002:7002" - "7006:7006" environment: - - ASPNETCORE_ENVIRONMENT=Release - # FIXME - MJS - commented out volumes below as volume is mounted as 1001:121 (vsts:docker) in build pipeline and causes issue with chown in dockerfile (appuser:appgroup), ie stops container from starting because of different user - # volumes: - # - "./_temp/mock-register/tmp:/tmp" + - ASPNETCORE_ENVIRONMENT=Release healthcheck: - test: wget --no-check-certificate --no-verbose --spider https://localhost:7006/health || exit 1 + test: ((wget --no-check-certificate --no-verbose --spider https://localhost:7006/health) && (wget --no-check-certificate --no-verbose --spider https://localhost:7002/idp/.well-known/openid-configuration)) || exit 1 timeout: 15s interval: 15s retries: 20 @@ -34,16 +33,11 @@ services: - "8001:8001" - "8002:8002" - "8005:8005" - # auth ui - "3000:3000" environment: - ASPNETCORE_ENVIRONMENT=Release - # tests need expiry of 3600 - CdrAuthServer__AccessTokenExpirySeconds=3600 - CdrAuthServer__SupportJarmEncryption=true - # FIXME - MJS - commented out volumes below as volume is mounted as 1001:121 (vsts:docker) in build pipeline and causes issue with chown in dockerfile (appuser:appgroup), ie stops container from starting because of different user - # volumes: - # - "./_temp/mock-data-holder/tmp:/tmp" healthcheck: test: ((wget --no-check-certificate --no-verbose --spider https://localhost:8005/health) && (wget --no-check-certificate --no-verbose --spider https://localhost:8001/health) && (wget --no-check-certificate --no-verbose --spider https://localhost:3000)) || exit 1 timeout: 15s @@ -62,16 +56,10 @@ services: - "8101:8101" - "8102:8102" - "8105:8105" - # auth ui - "3100:3100" environment: - ASPNETCORE_ENVIRONMENT=Release - # tests need expiry of 3600 - CdrAuthServer__AccessTokenExpirySeconds=3600 - - CdrAuthServer__SupportJarmEncryption=true - # FIXME - MJS - commented out volumes below as volume is mounted as 1001:121 (vsts:docker) in build pipeline and causes issue with chown in dockerfile (appuser:appgroup), ie stops container from starting because of different user - # volumes: - # - "./_temp/mock-data-holder-energy/tmp:/tmp" healthcheck: test: ((wget --no-check-certificate --no-verbose --spider https://localhost:8105/health) && (wget --no-check-certificate --no-verbose --spider https://localhost:8101/health) && (wget --no-check-certificate --no-verbose --spider https://localhost:3100)) || exit 1 timeout: 15s @@ -88,13 +76,10 @@ services: ports: - "9001:9001" build: - context: . + context: .. dockerfile: Dockerfile environment: - ASPNETCORE_ENVIRONMENT=Release - # FIXME - MJS - commented out volumes below as volume is mounted as 1001:121 (vsts:docker) in build pipeline and causes issue with chown in dockerfile (appuser:appgroup), ie stops container from starting because of different user - # volumes: - # - "./_temp/mock-data-recipient/tmp:/tmp" healthcheck: test: wget --no-check-certificate --no-verbose --spider https://localhost:9001/health || exit 1 timeout: 15s @@ -103,21 +88,6 @@ services: depends_on: mock-data-holder-energy: condition: service_healthy - - mock-data-recipient-e2e-tests: - container_name: mock-data-recipient-e2e-tests - image: mock-data-recipient-e2e-tests - hostname: mock-data-recipient-e2e-tests - build: - context: . - dockerfile: Dockerfile.e2e-tests - environment: - - ASPNETCORE_ENVIRONMENT=Release - volumes: - - "./_temp/mock-data-recipient-e2e-tests/testresults:/testresults" - depends_on: - mock-data-recipient: - condition: service_healthy mssql: container_name: sql1 diff --git a/Source/docker-compose.UnitTests.yml b/Source/DockerCompose/docker-compose.UnitTests.yml similarity index 97% rename from Source/docker-compose.UnitTests.yml rename to Source/DockerCompose/docker-compose.UnitTests.yml index 9416a52..690b54c 100644 --- a/Source/docker-compose.UnitTests.yml +++ b/Source/DockerCompose/docker-compose.UnitTests.yml @@ -10,7 +10,7 @@ services: ports: - "9001:9001" build: - context: . + context: .. dockerfile: Dockerfile environment: - ASPNETCORE_ENVIRONMENT=Release @@ -30,7 +30,7 @@ services: container_name: mock-data-recipient-unit-tests image: mock-data-recipient-unit-tests build: - context: . + context: .. dockerfile: Dockerfile.unit-tests environment: - ASPNETCORE_ENVIRONMENT=Release diff --git a/Source/docker-compose.IntegrationTests.yml b/Source/docker-compose.IntegrationTests.yml deleted file mode 100644 index 0527004..0000000 --- a/Source/docker-compose.IntegrationTests.yml +++ /dev/null @@ -1,142 +0,0 @@ -# Docker compose for build pipeline - -version: '3.8' - -services: - mock-register: - container_name: mock-register - image: mock-register - hostname: mock-register - ports: - - "7000:7000" - - "7001:7001" - - "7002:7002" - - "7006:7006" - environment: - - ASPNETCORE_ENVIRONMENT=Release - # FIXME - MJS - commented out volumes below as volume is mounted as 1001:121 (vsts:docker) in build pipeline and causes issue with chown in dockerfile (appuser:appgroup), ie stops container from starting because of different user - # volumes: - # - "./_temp/mock-register/tmp:/tmp" - healthcheck: - test: ((wget --no-check-certificate --no-verbose --spider https://localhost:7006/health) && (wget --no-check-certificate --no-verbose --spider https://localhost:7002/idp/.well-known/openid-configuration)) || exit 1 - timeout: 15s - interval: 15s - retries: 20 - start_period: 5s - depends_on: - mssql: - condition: service_healthy - - mock-data-holder: - container_name: mock-data-holder - image: mock-data-holder - hostname: mock-data-holder - ports: - - "8000:8000" - - "8001:8001" - - "8002:8002" - - "8005:8005" - environment: - - ASPNETCORE_ENVIRONMENT=Release - # FIXME - MJS - commented out volumes below as volume is mounted as 1001:121 (vsts:docker) in build pipeline and causes issue with chown in dockerfile (appuser:appgroup), ie stops container from starting because of different user - # volumes: - # - "./_temp/mock-data-holder/tmp:/tmp" - healthcheck: - test: ((wget --no-check-certificate --no-verbose --spider https://localhost:8005/health) && (wget --no-check-certificate --no-verbose --spider https://localhost:8001/health) && (wget --no-check-certificate --no-verbose --spider https://localhost:3000)) || exit 1 - timeout: 15s - interval: 15s - retries: 20 - start_period: 5s - depends_on: - mssql: - condition: service_healthy - mock-register: - condition: service_healthy - - mock-data-holder-energy: - container_name: mock-data-holder-energy - image: mock-data-holder-energy - hostname: mock-data-holder-energy - ports: - - "8100:8100" - - "8101:8101" - - "8102:8102" - - "8105:8105" - environment: - - ASPNETCORE_ENVIRONMENT=Release - # FIXME - MJS - commented out volumes below as volume is mounted as 1001:121 (vsts:docker) in build pipeline and causes issue with chown in dockerfile (appuser:appgroup), ie stops container from starting because of different user - # volumes: - # - "./_temp/mock-data-holder-energy/tmp:/tmp" - healthcheck: - test: ((wget --no-check-certificate --no-verbose --spider https://localhost:8105/health) && (wget --no-check-certificate --no-verbose --spider https://localhost:8101/health) && (wget --no-check-certificate --no-verbose --spider https://localhost:3100)) || exit 1 - timeout: 15s - interval: 15s - retries: 20 - start_period: 5s - depends_on: - mssql: - condition: service_healthy - mock-register: - condition: service_healthy - mock-data-holder: - condition: service_healthy - - mock-data-recipient: - container_name: mock-data-recipient - image: mock-data-recipient - hostname: mock-data-recipient - ports: - - "9001:9001" - build: - context: . - dockerfile: Dockerfile - environment: - - ASPNETCORE_ENVIRONMENT=Release - # FIXME - MJS - commented out volumes below as volume is mounted as 1001:121 (vsts:docker) in build pipeline and causes issue with chown in dockerfile (appuser:appgroup), ie stops container from starting because of different user - # volumes: - # - "./_temp/mock-data-recipient/tmp:/tmp" - healthcheck: - test: wget --no-check-certificate --no-verbose --spider https://localhost:9001/health || exit 1 - timeout: 15s - interval: 15s - retries: 20 - start_period: 10s - depends_on: - mssql: - condition: service_healthy - mock-register: - condition: service_healthy - mock-data-holder: - condition: service_healthy - mock-data-holder-energy: - condition: service_healthy - - mock-data-recipient-integration-tests: - container_name: mock-data-recipient-integration-tests - image: mock-data-recipient-integration-tests - build: - context: . - dockerfile: Dockerfile.integration-tests - environment: - - ASPNETCORE_ENVIRONMENT=Release - volumes: - - "./_temp/mock-data-recipient-integration-tests/tmp:/tmp" - - "./_temp/mock-data-recipient-integration-tests/testresults:/testresults" - depends_on: - mock-data-recipient: - condition: service_healthy - - mssql: - container_name: sql1 - image: 'mcr.microsoft.com/mssql/server:2019-latest' - ports: - - "1433:1433" - environment: - - ACCEPT_EULA=Y - - SA_PASSWORD=Pa{}w0rd2019 - healthcheck: - test: /opt/mssql-tools/bin/sqlcmd -S . -U sa -P "Pa{}w0rd2019" -Q "SELECT 1" || exit 1 - timeout: 15s - interval: 15s - retries: 20 - start_period: 5s From ce94d75472c29aa9d3dcef74b1198519dabbf8f0 Mon Sep 17 00:00:00 2001 From: CDR-AmirM <88067035+CDR-AmirM@users.noreply.github.com> Date: Wed, 29 Nov 2023 11:26:46 +1100 Subject: [PATCH 3/3] Fixed urls used for Readme images to display correctly in Docker Hub (#75) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4fc95c1..10abca6 100644 --- a/README.md +++ b/README.md @@ -66,11 +66,11 @@ To get help on launching and debugging the solutions as containers and switching ## Mock Data Recipient - Architecture The following diagram outlines the high level architecture of the Mock Data Recipient: -[Mock Data Recipient - Architecture](./mock-data-recipient-architecture.png?raw=true) +![Mock Data Recipient - Architecture](./mock-data-recipient-architecture.png?raw=true) Dynamic Client Registration Interface: -[Dynamic Client Registration Interface](./mock-data-recipient-dcr-architecture.png?raw=true) +![Dynamic Client Registration Interface](./mock-data-recipient-dcr-architecture.png?raw=true) ## Mock Data Recipient - Components The Mock Data Recipient contains the following components: @@ -125,4 +125,4 @@ See our [security policy](./SECURITY.md) for information on security controls, r [MIT License](./LICENSE) # Notes -The Mock Data Recipient is provided as a development tool only. It conforms to the Consumer Data Standards. \ No newline at end of file +The Mock Data Recipient is provided as a development tool only. It conforms to the Consumer Data Standards.