diff --git a/.gitmodules b/.gitmodules index 5c6205a8..4deb9957 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,5 +1,8 @@ [submodule "src/dotnet-mesh-client"] - # path = src/Shared/dotnet-mesh-client path = src/dotnet-mesh-client url = https://github.com/NHSDigital/dotnet-mesh-client.git branch = main +[submodule "tests/mesh-sandbox"] + path = tests/mesh-sandbox + url = https://github.com/NHSDigital/mesh-sandbox + branch = main diff --git a/compose.yaml b/compose.yaml index 1512cfc2..db33be74 100644 --- a/compose.yaml +++ b/compose.yaml @@ -48,7 +48,7 @@ services: FileExtractQueueName: "${FileExtractQueueName}" FileTransformQueueName: "${FileTransformQueueName}" StaleHours: "${StaleHours}" - MeshApiBaseUrl: "http://mesh_sandbox:80/messageexchange" + MeshApiBaseUrl: "http://mesh-sandbox/messageexchange" NbssMailboxId: "${NbssMailboxId}" MeshPassword: "${MeshPassword}" MeshSharedKey: "${MeshSharedKey}" @@ -71,6 +71,8 @@ services: condition: service_healthy db: condition: service_healthy + mesh-sandbox: + condition: service_started volumes: - mesh-config-data:/azure-functions-host/Secrets/ networks: @@ -106,10 +108,12 @@ services: ports: - "1433:1433" user: "root" - volumes: - - db-data:/var/opt/mssql healthcheck: - test: ["CMD-SHELL", "pgrep -f sqlservr || exit 1"] + test: + [ + "CMD-SHELL", + "grep -q 'SQL Server is now ready for client connections' /var/opt/mssql/log/errorlog || exit 1", + ] interval: 20s timeout: 10s retries: 6 @@ -134,6 +138,27 @@ services: networks: - backend + mesh-sandbox: + container_name: mesh-sandbox + build: tests/mesh-sandbox/ + ports: + - "8700:80" + deploy: + restart_policy: + condition: on-failure + max_attempts: 3 + environment: + - SHARED_KEY=TestKey + - SSL=no + volumes: + # mount a different mailboxes.jsonl to pre created mailboxes + - ../mesh-sandbox/src/mesh_sandbox/store/data/mailboxes.jsonl:/app/mesh_sandbox/store/data/mailboxes.jsonl:ro + - ../mesh-sandbox/src/mesh_sandbox/test_plugin:/app/mesh_sandbox/plugins:ro + # you can mount a directory if you want access the stored messages + - ../mesh-sandbox/messages:/tmp/mesh_store + networks: + - backend + networks: backend: name: backend-network @@ -141,9 +166,6 @@ networks: volumes: azurite-data: name: azurite-data - db-data: - name: db-data - driver: local mesh-config-data: name: mesh-config-data driver: local diff --git a/scripts/tests/unit.sh b/scripts/tests/unit.sh index 2696f206..26257e33 100755 --- a/scripts/tests/unit.sh +++ b/scripts/tests/unit.sh @@ -7,7 +7,7 @@ if [[ "${1:-}" == "--no-build" ]]; then fi COVERAGE_DIR="coverage" -TEST_PROJECTS=$(find tests -name '*.csproj') +TEST_PROJECTS=$(find tests -name '*.csproj' -not -name "ServiceLayer.IntegrationTests.csproj") rm -rf "$COVERAGE_DIR" mkdir -p "$COVERAGE_DIR" diff --git a/src/ServiceLayer.Mesh/Functions/HealthCheckFunction.cs b/src/ServiceLayer.Mesh/Functions/HealthCheckFunction.cs new file mode 100644 index 00000000..3cd9f090 --- /dev/null +++ b/src/ServiceLayer.Mesh/Functions/HealthCheckFunction.cs @@ -0,0 +1,14 @@ +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; +using System.Net; + +namespace ServiceLayer.Mesh.Functions; + +public static class HealthCheckFunction +{ + [Function("HealthCheckFunction")] + public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "health")] HttpRequestData req) + { + return req.CreateResponse(HttpStatusCode.OK); + } +} diff --git a/src/ServiceLayer.sln b/src/ServiceLayer.sln index 915a1168..b14c8ad1 100644 --- a/src/ServiceLayer.sln +++ b/src/ServiceLayer.sln @@ -21,123 +21,138 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceLayer.Shared.Tests", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceLayer.TestUtilities", "..\tests\ServiceLayer.TestUtilities\ServiceLayer.TestUtilities.csproj", "{43AE0301-63CA-4254-9580-4FB07C9D1920}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceLayer.IntegrationTests", "..\tests\ServiceLayer.IntegrationTests\ServiceLayer.IntegrationTests.csproj", "{4BD85C4C-F9F8-427B-AF7F-2422F498FD81}" +EndProject Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Debug|x64.ActiveCfg = Debug|Any CPU - {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Debug|x64.Build.0 = Debug|Any CPU - {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Debug|x86.ActiveCfg = Debug|Any CPU - {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Debug|x86.Build.0 = Debug|Any CPU - {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Release|Any CPU.Build.0 = Release|Any CPU - {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Release|x64.ActiveCfg = Release|Any CPU - {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Release|x64.Build.0 = Release|Any CPU - {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Release|x86.ActiveCfg = Release|Any CPU - {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Release|x86.Build.0 = Release|Any CPU - {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Debug|x64.ActiveCfg = Debug|Any CPU - {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Debug|x64.Build.0 = Debug|Any CPU - {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Debug|x86.ActiveCfg = Debug|Any CPU - {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Debug|x86.Build.0 = Debug|Any CPU - {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Release|Any CPU.Build.0 = Release|Any CPU - {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Release|x64.ActiveCfg = Release|Any CPU - {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Release|x64.Build.0 = Release|Any CPU - {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Release|x86.ActiveCfg = Release|Any CPU - {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Release|x86.Build.0 = Release|Any CPU - {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Debug|x64.ActiveCfg = Debug|Any CPU - {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Debug|x64.Build.0 = Debug|Any CPU - {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Debug|x86.ActiveCfg = Debug|Any CPU - {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Debug|x86.Build.0 = Debug|Any CPU - {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Release|Any CPU.Build.0 = Release|Any CPU - {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Release|x64.ActiveCfg = Release|Any CPU - {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Release|x64.Build.0 = Release|Any CPU - {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Release|x86.ActiveCfg = Release|Any CPU - {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Release|x86.Build.0 = Release|Any CPU - {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Debug|x64.ActiveCfg = Debug|Any CPU - {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Debug|x64.Build.0 = Debug|Any CPU - {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Debug|x86.ActiveCfg = Debug|Any CPU - {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Debug|x86.Build.0 = Debug|Any CPU - {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Release|Any CPU.Build.0 = Release|Any CPU - {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Release|x64.ActiveCfg = Release|Any CPU - {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Release|x64.Build.0 = Release|Any CPU - {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Release|x86.ActiveCfg = Release|Any CPU - {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Release|x86.Build.0 = Release|Any CPU - {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Debug|x64.ActiveCfg = Debug|Any CPU - {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Debug|x64.Build.0 = Debug|Any CPU - {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Debug|x86.ActiveCfg = Debug|Any CPU - {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Debug|x86.Build.0 = Debug|Any CPU - {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Release|Any CPU.Build.0 = Release|Any CPU - {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Release|x64.ActiveCfg = Release|Any CPU - {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Release|x64.Build.0 = Release|Any CPU - {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Release|x86.ActiveCfg = Release|Any CPU - {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Release|x86.Build.0 = Release|Any CPU - {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Debug|x64.ActiveCfg = Debug|Any CPU - {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Debug|x64.Build.0 = Debug|Any CPU - {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Debug|x86.ActiveCfg = Debug|Any CPU - {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Debug|x86.Build.0 = Debug|Any CPU - {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Release|Any CPU.Build.0 = Release|Any CPU - {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Release|x64.ActiveCfg = Release|Any CPU - {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Release|x64.Build.0 = Release|Any CPU - {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Release|x86.ActiveCfg = Release|Any CPU - {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Release|x86.Build.0 = Release|Any CPU - {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Debug|x64.ActiveCfg = Debug|Any CPU - {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Debug|x64.Build.0 = Debug|Any CPU - {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Debug|x86.ActiveCfg = Debug|Any CPU - {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Debug|x86.Build.0 = Debug|Any CPU - {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Release|Any CPU.Build.0 = Release|Any CPU - {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Release|x64.ActiveCfg = Release|Any CPU - {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Release|x64.Build.0 = Release|Any CPU - {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Release|x86.ActiveCfg = Release|Any CPU - {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Release|x86.Build.0 = Release|Any CPU - {43AE0301-63CA-4254-9580-4FB07C9D1920}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {43AE0301-63CA-4254-9580-4FB07C9D1920}.Debug|Any CPU.Build.0 = Debug|Any CPU - {43AE0301-63CA-4254-9580-4FB07C9D1920}.Debug|x64.ActiveCfg = Debug|Any CPU - {43AE0301-63CA-4254-9580-4FB07C9D1920}.Debug|x64.Build.0 = Debug|Any CPU - {43AE0301-63CA-4254-9580-4FB07C9D1920}.Debug|x86.ActiveCfg = Debug|Any CPU - {43AE0301-63CA-4254-9580-4FB07C9D1920}.Debug|x86.Build.0 = Debug|Any CPU - {43AE0301-63CA-4254-9580-4FB07C9D1920}.Release|Any CPU.ActiveCfg = Release|Any CPU - {43AE0301-63CA-4254-9580-4FB07C9D1920}.Release|Any CPU.Build.0 = Release|Any CPU - {43AE0301-63CA-4254-9580-4FB07C9D1920}.Release|x64.ActiveCfg = Release|Any CPU - {43AE0301-63CA-4254-9580-4FB07C9D1920}.Release|x64.Build.0 = Release|Any CPU - {43AE0301-63CA-4254-9580-4FB07C9D1920}.Release|x86.ActiveCfg = Release|Any CPU - {43AE0301-63CA-4254-9580-4FB07C9D1920}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72} = {0AB3BF05-4346-4AA6-1389-037BE0695223} - {E5EF5B92-52DA-4EF3-956B-8AEE3D333428} = {0AB3BF05-4346-4AA6-1389-037BE0695223} - {9642EC3A-9BC3-4557-ACD1-807FE764D5F6} = {0AB3BF05-4346-4AA6-1389-037BE0695223} - {43AE0301-63CA-4254-9580-4FB07C9D1920} = {0AB3BF05-4346-4AA6-1389-037BE0695223} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {EEE06B13-019F-4618-A6EB-FD834B6EA7D7} - EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Debug|x64.ActiveCfg = Debug|Any CPU + {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Debug|x64.Build.0 = Debug|Any CPU + {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Debug|x86.ActiveCfg = Debug|Any CPU + {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Debug|x86.Build.0 = Debug|Any CPU + {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Release|Any CPU.Build.0 = Release|Any CPU + {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Release|x64.ActiveCfg = Release|Any CPU + {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Release|x64.Build.0 = Release|Any CPU + {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Release|x86.ActiveCfg = Release|Any CPU + {B56B41FF-FA39-0FDE-E266-6EC09B268DFB}.Release|x86.Build.0 = Release|Any CPU + {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Debug|x64.ActiveCfg = Debug|Any CPU + {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Debug|x64.Build.0 = Debug|Any CPU + {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Debug|x86.ActiveCfg = Debug|Any CPU + {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Debug|x86.Build.0 = Debug|Any CPU + {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Release|Any CPU.Build.0 = Release|Any CPU + {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Release|x64.ActiveCfg = Release|Any CPU + {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Release|x64.Build.0 = Release|Any CPU + {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Release|x86.ActiveCfg = Release|Any CPU + {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72}.Release|x86.Build.0 = Release|Any CPU + {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Debug|x64.ActiveCfg = Debug|Any CPU + {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Debug|x64.Build.0 = Debug|Any CPU + {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Debug|x86.ActiveCfg = Debug|Any CPU + {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Debug|x86.Build.0 = Debug|Any CPU + {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Release|Any CPU.Build.0 = Release|Any CPU + {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Release|x64.ActiveCfg = Release|Any CPU + {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Release|x64.Build.0 = Release|Any CPU + {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Release|x86.ActiveCfg = Release|Any CPU + {803E8A5E-A180-4799-8BE2-DD5BD3C34ED2}.Release|x86.Build.0 = Release|Any CPU + {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Debug|x64.ActiveCfg = Debug|Any CPU + {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Debug|x64.Build.0 = Debug|Any CPU + {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Debug|x86.ActiveCfg = Debug|Any CPU + {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Debug|x86.Build.0 = Debug|Any CPU + {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Release|Any CPU.Build.0 = Release|Any CPU + {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Release|x64.ActiveCfg = Release|Any CPU + {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Release|x64.Build.0 = Release|Any CPU + {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Release|x86.ActiveCfg = Release|Any CPU + {E5EF5B92-52DA-4EF3-956B-8AEE3D333428}.Release|x86.Build.0 = Release|Any CPU + {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Debug|x64.ActiveCfg = Debug|Any CPU + {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Debug|x64.Build.0 = Debug|Any CPU + {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Debug|x86.ActiveCfg = Debug|Any CPU + {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Debug|x86.Build.0 = Debug|Any CPU + {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Release|Any CPU.Build.0 = Release|Any CPU + {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Release|x64.ActiveCfg = Release|Any CPU + {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Release|x64.Build.0 = Release|Any CPU + {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Release|x86.ActiveCfg = Release|Any CPU + {F373FEBA-AD0B-4E0B-BEE3-31D22C7AD43D}.Release|x86.Build.0 = Release|Any CPU + {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Debug|x64.ActiveCfg = Debug|Any CPU + {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Debug|x64.Build.0 = Debug|Any CPU + {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Debug|x86.ActiveCfg = Debug|Any CPU + {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Debug|x86.Build.0 = Debug|Any CPU + {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Release|Any CPU.Build.0 = Release|Any CPU + {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Release|x64.ActiveCfg = Release|Any CPU + {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Release|x64.Build.0 = Release|Any CPU + {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Release|x86.ActiveCfg = Release|Any CPU + {B086BBF9-1A41-48C9-B019-F9C75CA634AF}.Release|x86.Build.0 = Release|Any CPU + {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Debug|x64.ActiveCfg = Debug|Any CPU + {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Debug|x64.Build.0 = Debug|Any CPU + {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Debug|x86.ActiveCfg = Debug|Any CPU + {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Debug|x86.Build.0 = Debug|Any CPU + {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Release|Any CPU.Build.0 = Release|Any CPU + {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Release|x64.ActiveCfg = Release|Any CPU + {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Release|x64.Build.0 = Release|Any CPU + {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Release|x86.ActiveCfg = Release|Any CPU + {9642EC3A-9BC3-4557-ACD1-807FE764D5F6}.Release|x86.Build.0 = Release|Any CPU + {43AE0301-63CA-4254-9580-4FB07C9D1920}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {43AE0301-63CA-4254-9580-4FB07C9D1920}.Debug|Any CPU.Build.0 = Debug|Any CPU + {43AE0301-63CA-4254-9580-4FB07C9D1920}.Debug|x64.ActiveCfg = Debug|Any CPU + {43AE0301-63CA-4254-9580-4FB07C9D1920}.Debug|x64.Build.0 = Debug|Any CPU + {43AE0301-63CA-4254-9580-4FB07C9D1920}.Debug|x86.ActiveCfg = Debug|Any CPU + {43AE0301-63CA-4254-9580-4FB07C9D1920}.Debug|x86.Build.0 = Debug|Any CPU + {43AE0301-63CA-4254-9580-4FB07C9D1920}.Release|Any CPU.ActiveCfg = Release|Any CPU + {43AE0301-63CA-4254-9580-4FB07C9D1920}.Release|Any CPU.Build.0 = Release|Any CPU + {43AE0301-63CA-4254-9580-4FB07C9D1920}.Release|x64.ActiveCfg = Release|Any CPU + {43AE0301-63CA-4254-9580-4FB07C9D1920}.Release|x64.Build.0 = Release|Any CPU + {43AE0301-63CA-4254-9580-4FB07C9D1920}.Release|x86.ActiveCfg = Release|Any CPU + {43AE0301-63CA-4254-9580-4FB07C9D1920}.Release|x86.Build.0 = Release|Any CPU + {4BD85C4C-F9F8-427B-AF7F-2422F498FD81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4BD85C4C-F9F8-427B-AF7F-2422F498FD81}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4BD85C4C-F9F8-427B-AF7F-2422F498FD81}.Debug|x64.ActiveCfg = Debug|Any CPU + {4BD85C4C-F9F8-427B-AF7F-2422F498FD81}.Debug|x64.Build.0 = Debug|Any CPU + {4BD85C4C-F9F8-427B-AF7F-2422F498FD81}.Debug|x86.ActiveCfg = Debug|Any CPU + {4BD85C4C-F9F8-427B-AF7F-2422F498FD81}.Debug|x86.Build.0 = Debug|Any CPU + {4BD85C4C-F9F8-427B-AF7F-2422F498FD81}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4BD85C4C-F9F8-427B-AF7F-2422F498FD81}.Release|Any CPU.Build.0 = Release|Any CPU + {4BD85C4C-F9F8-427B-AF7F-2422F498FD81}.Release|x64.ActiveCfg = Release|Any CPU + {4BD85C4C-F9F8-427B-AF7F-2422F498FD81}.Release|x64.Build.0 = Release|Any CPU + {4BD85C4C-F9F8-427B-AF7F-2422F498FD81}.Release|x86.ActiveCfg = Release|Any CPU + {4BD85C4C-F9F8-427B-AF7F-2422F498FD81}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {BA052DAE-6FD1-483A-A0AF-DCBCF9E38C72} = {0AB3BF05-4346-4AA6-1389-037BE0695223} + {E5EF5B92-52DA-4EF3-956B-8AEE3D333428} = {0AB3BF05-4346-4AA6-1389-037BE0695223} + {9642EC3A-9BC3-4557-ACD1-807FE764D5F6} = {0AB3BF05-4346-4AA6-1389-037BE0695223} + {43AE0301-63CA-4254-9580-4FB07C9D1920} = {0AB3BF05-4346-4AA6-1389-037BE0695223} + {4BD85C4C-F9F8-427B-AF7F-2422F498FD81} = {0AB3BF05-4346-4AA6-1389-037BE0695223} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EEE06B13-019F-4618-A6EB-FD834B6EA7D7} + EndGlobalSection EndGlobal diff --git a/tests/ServiceLayer.IntegrationTests/.env.tests b/tests/ServiceLayer.IntegrationTests/.env.tests new file mode 100644 index 00000000..08c011f7 --- /dev/null +++ b/tests/ServiceLayer.IntegrationTests/.env.tests @@ -0,0 +1,35 @@ +# Database +DATABASE_USER=SA +DATABASE_PASSWORD=YourStrong@Passw0rd +DATABASE_NAME=ServiceLayer +DATABASE_HOST=db +DatabaseConnectionString=Server=${DATABASE_HOST};Database=${DATABASE_NAME};User Id=${DATABASE_USER};Password=${DATABASE_PASSWORD};TrustServerCertificate=True + +# MESH +MeshSharedKey=TestKey +MeshPassword=password +NbssMailboxId=X26ABC1 +MeshApiBaseUrl=http://localhost:8700/messageexchange + +# Other +ASPNETCORE_ENVIRONMENT=Development +FileDiscoveryTimerExpression=*/5 * * * * * # Every 5 seconds so that the test doesn't have to wait too long +MeshHandshakeTimerExpression=0 0 0 * * * # Midnight +FileRetryTimerExpression=0 0 * * * * +FileExtractQueueName=file-extract +FileTransformQueueName=file-transform +StaleHours=12 +MeshBlobContainerName=incoming-mesh-files +API_PORT=7071 +MESH_INGEST_PORT=7072 + +# Event Grid +EVENT_GRID_TOPIC_URL=https://localhost:60101/api/events +EVENT_GRID_TOPIC_KEY=TheLocal+DevelopmentKey= + +# Azurite +AZURITE_ACCOUNT_KEY=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw== # Standard default Azurite key +AZURITE_CONNECTION_STRING=DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=${AZURITE_ACCOUNT_KEY};BlobEndpoint=http://azurite:10000/devstoreaccount1;QueueEndpoint=http://azurite:10001/devstoreaccount1;TableEndpoint=http://azurite/devstoreaccount1 +AZURITE_BLOB_PORT=10000 +AZURITE_QUEUE_PORT=10001 +AZURITE_TABLE_PORT=10002 diff --git a/tests/ServiceLayer.IntegrationTests/IntegrationTests.cs b/tests/ServiceLayer.IntegrationTests/IntegrationTests.cs new file mode 100644 index 00000000..669f5468 --- /dev/null +++ b/tests/ServiceLayer.IntegrationTests/IntegrationTests.cs @@ -0,0 +1,207 @@ +using System.Diagnostics; +using System.Net.Http.Headers; +using System.Text.Json; +using System.Text.Json.Serialization; +using Azure.Storage.Blobs; +using Azure.Storage.Blobs.Models; +using Microsoft.EntityFrameworkCore; +using ServiceLayer.Data; +using ServiceLayer.TestUtilities; + +namespace ServiceLayer.IntegrationTests; + +[CollectionDefinition("DockerComposeCollection")] +public class DockerComposeCollection : ICollectionFixture +{ +} + +[Collection("DockerComposeCollection")] +public class IntegrationTests +{ + private readonly string _azuriteAccountKey = Environment.GetEnvironmentVariable("AZURITE_ACCOUNT_KEY") + ?? throw new InvalidOperationException($"Environment variable 'AZURITE_ACCOUNT_KEY' is not set."); + private readonly string _azuriteAccountName = Environment.GetEnvironmentVariable("AZURITE_ACCOUNT_NAME") + ?? throw new InvalidOperationException($"Environment variable 'AZURITE_ACCOUNT_NAME' is not set."); + private readonly string _azuriteBlobPort = Environment.GetEnvironmentVariable("AZURITE_BLOB_PORT") + ?? throw new InvalidOperationException($"Environment variable 'AZURITE_BLOB_PORT' is not set."); + private readonly string _meshIngestPort = Environment.GetEnvironmentVariable("MESH_INGEST_PORT") + ?? throw new InvalidOperationException($"Environment variable 'MESH_INGEST_PORT' is not set."); + private readonly string _meshSandboxPort = Environment.GetEnvironmentVariable("MESH_SANDBOX_PORT") + ?? throw new InvalidOperationException($"Environment variable 'MESH_SANDBOX_PORT' is not set."); + private readonly string _meshBlobContainerName = Environment.GetEnvironmentVariable("MESH_BLOB_CONTAINER_NAME") + ?? throw new InvalidOperationException($"Environment variable 'MESH_BLOB_CONTAINER_NAME' is not set."); + private readonly string _databaseConnectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION_STRING") + ?? throw new InvalidOperationException($"Environment variable 'DATABASE_CONNECTION_STRING' is not set."); + + [Fact] + public async Task FileSentToMeshInbox_FileIsUploadedToBlobContainerAndInsertedIntoDb() + { + // Arrange + await WaitForHealthyService(); + + // Act + var fileId = await SendFileToMeshInbox("KMK_20250212095121_APPT_87.dat"); + + // Wait to allow functions to ingest the file + await Task.Delay(45000); + + // Assert + Assert.NotNull(fileId); + Assert.True(await WasFileUploadedToBlobContainer(fileId)); + Assert.True(await WasFileInsertedIntoDatabase(fileId)); + } + + private async Task WaitForHealthyService() + { + Console.WriteLine("Waiting for Mesh Ingest Service health check to pass..."); + + int attemptCounter = 0; + + while (attemptCounter < 10) + { + var response = await HttpHelper.SendHttpRequestAsync(HttpMethod.Get, $"http://localhost:{_meshIngestPort}/api/health"); + + if (response.IsSuccessStatusCode) + { + Console.WriteLine("Mesh Ingest Service is healthy and ready to start ingesting files."); + return; + } + + Console.WriteLine("Mesh Ingest Service is unhealthy"); + attemptCounter++; + await Task.Delay(5000); + } + + Console.WriteLine("Max attempts reached. Mesh Ingest Service is still unhealthy."); + throw new TimeoutException("Timed out waiting on Mesh Ingest Service health check"); + } + + private async Task SendFileToMeshInbox(string fileName) + { + byte[] binaryData = await File.ReadAllBytesAsync($"TestData/{fileName}"); + var content = new ByteArrayContent(binaryData); + content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); + + var response = await HttpHelper.SendHttpRequestAsync( + HttpMethod.Post, + $"http://localhost:{_meshSandboxPort}/messageexchange/X26ABC1/outbox", + content, + headers => + { + headers.Add("Authorization", "NHSMESH X26ABC1:a42f77b9-58de-4b45-b599-2d5bf320b44d:0:202407291437:e3005627136e01706efabcfe72269bc8da3192e90a840ab344ab7f82a39bb5c6"); + headers.Add("Mex-Filename", fileName); + headers.Add("Mex-From", "X26ABC1"); + headers.Add("Mex-To", "X26ABC1"); + headers.Add("Mex-Workflowid", "API-DOCS-TEST"); + } + ); + + string responseBody = await response.Content.ReadAsStringAsync(); + + var responseObject = JsonSerializer.Deserialize(responseBody); + + return responseObject?.MessageID; + } + + private async Task WasFileUploadedToBlobContainer(string fileId) + { + var blobConnectionString = $"DefaultEndpointsProtocol=http;AccountName={_azuriteAccountName};AccountKey={_azuriteAccountKey};BlobEndpoint=http://localhost:{_azuriteBlobPort}/{_azuriteAccountName}"; + + var containerClient = new BlobContainerClient(blobConnectionString, _meshBlobContainerName); + + try + { + var blobClient = containerClient.GetBlobClient($"NbssAppointmentEvents/{fileId}"); + + BlobProperties properties = await blobClient.GetPropertiesAsync(); + return true; // If we get properties, the blob exists + } + catch (Exception ex) + { + Console.WriteLine($"An error occurred: {ex.Message}"); + return false; + } + } + + private async Task WasFileInsertedIntoDatabase(string fileId) + { + var options = new DbContextOptionsBuilder() + .UseSqlServer(_databaseConnectionString) + .Options; + + var context = new ServiceLayerDbContext(options); + + return await context.MeshFiles.AnyAsync(x => x.FileId == fileId); + } + + public class MeshResponse + { + [JsonPropertyName("messageID")] + public required string MessageID { get; set; } + } +} + +public class DockerComposeFixture : IAsyncLifetime +{ + public async Task InitializeAsync() + { + Console.WriteLine("Starting up docker containers..."); + + var startInfo = new ProcessStartInfo + { + FileName = "docker", + Arguments = "compose --env-file .env.tests up -d svclyr-mesh-ingest mesh-sandbox azurite db db-migrations", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + + using var process = Process.Start(startInfo); + + if (process == null) + { + throw new Exception("Failed to start the Docker process."); + } + + await process.WaitForExitAsync(); + + if (process.ExitCode != 0) + { + throw new Exception($"Docker process started but failed, error: {process.StandardError.ReadToEnd()}"); + } + + Console.WriteLine("Docker containers successfully started"); + } + + public async Task DisposeAsync() + { + Console.WriteLine("Stopping docker containers..."); + + var stopInfo = new ProcessStartInfo + { + FileName = "docker", + Arguments = "compose down", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + + using var process = Process.Start(stopInfo); + + if (process == null) + { + throw new Exception("Failed to start the Docker process."); + } + + await process.WaitForExitAsync(); + + if (process.ExitCode != 0) + { + throw new Exception($"Docker process started but failed, error: {process.StandardError.ReadToEnd()}"); + } + + Console.WriteLine("Docker containers stopped"); + } +} diff --git a/tests/ServiceLayer.IntegrationTests/README.md b/tests/ServiceLayer.IntegrationTests/README.md new file mode 100644 index 00000000..621c7c52 --- /dev/null +++ b/tests/ServiceLayer.IntegrationTests/README.md @@ -0,0 +1,28 @@ +# Integration Tests + +The integration tests start up docker containers using [compose.yaml](../../compose.yaml) and provide them with the environment variables defined in [.env.tests](.env.tests). Once the containers are up, the integration tests are executed, after the tests have finished, the containers are stopped. + +## How to run the tests + +To run the integration tests, you also need to pass the following environment variables as arguments when executing `dotnet test`: + +- AZURITE_ACCOUNT_KEY +- AZURITE_ACCOUNT_NAME +- AZURITE_BLOB_PORT +- MESH_INGEST_PORT +- MESH_SANDBOX_PORT +- MESH_BLOB_CONTAINER_NAME +- DATABASE_CONNECTION_STRING + +E.g. + +```sh +dotnet test \ + -e AZURITE_ACCOUNT_KEY="Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" \ + -e AZURITE_ACCOUNT_NAME=devstoreaccount1 \ + -e AZURITE_BLOB_PORT=10000 \ + -e MESH_INGEST_PORT=7072 \ + -e MESH_SANDBOX_PORT=8700 \ + -e MESH_BLOB_CONTAINER_NAME=incoming-mesh-files \ + -e DATABASE_CONNECTION_STRING="Server=localhost;Database=ServiceLayer;User Id=SA;Password=YourStrong@Passw0rd;TrustServerCertificate=True" +``` diff --git a/tests/ServiceLayer.IntegrationTests/ServiceLayer.IntegrationTests.csproj b/tests/ServiceLayer.IntegrationTests/ServiceLayer.IntegrationTests.csproj new file mode 100644 index 00000000..37e8311b --- /dev/null +++ b/tests/ServiceLayer.IntegrationTests/ServiceLayer.IntegrationTests.csproj @@ -0,0 +1,38 @@ + + + + net9.0 + enable + enable + false + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + PreserveNewest + + + + diff --git a/tests/ServiceLayer.IntegrationTests/TestData/KMK_20250212095121_APPT_87.dat b/tests/ServiceLayer.IntegrationTests/TestData/KMK_20250212095121_APPT_87.dat new file mode 100644 index 00000000..0b1adc71 --- /dev/null +++ b/tests/ServiceLayer.IntegrationTests/TestData/KMK_20250212095121_APPT_87.dat @@ -0,0 +1,8 @@ +"NBSSAPPT_HDR"|"00000087"|"20250212"|"095121"|"000005" +"NBSSAPPT_FLDS"|"Sequence"|"BSO"|"Action"|"Clinic Code"|"Holding Clinic"|"Status"|"Attended Not Scr"|"Appointment ID"|"NHS Num"|"Epsiode Type"|"Episode Start"|"BatchID"|"Screen or Asses"|"Screen Appt num"|"Booked By"|"Cancelled By"|"Appt Date"|"Appt Time"|"Location"|"Clinic Name"|"Clinic Name (Let)"|"Clinic Address 1"|"Clinic Address 2"|"Clinic Address 3"|"Clinic Address 4"|"Clinic Address 5"|"Postcode"|"Action Timestamp" +"NBSSAPPT_DATA"|"000001"|"KMK"|"U"|"BU011"|"N"|"D"|""|"BU011-67246-RA1-DN-T1316-1"|"9619663241"|"G"|"2025-02-10"|"KMKG00581"|"S"|"1"|"H"|""|"20250210"|"1316"|"BU"|"BREAST CARE UNIT"|"BREAST CARE UNIT"|"BREAST CARE UNIT"|"MILTON KEYNES HOSPITAL"|"STANDING WAY"|"MILTON KEYNES"|"MK6 5LD"|"MK6 5LD"|"20250212-094011" +"NBSSAPPT_DATA"|"000002"|"KMK"|"U"|"BU011"|"N"|"D"|""|"BU011-67246-RA1-DN-T1345-1"|"9900798635"|"G"|"2025-02-10"|"KMKG00581"|"S"|"1"|"H"|""|"20250210"|"1345"|"BU"|"BREAST CARE UNIT"|"BREAST CARE UNIT"|"BREAST CARE UNIT"|"MILTON KEYNES HOSPITAL"|"STANDING WAY"|"MILTON KEYNES"|"MK6 5LD"|"MK6 5LD"|"20250212-094153" +"NBSSAPPT_DATA"|"000003"|"KMK"|"U"|"BU011"|"N"|"D"|""|"BU011-67246-RA1-DN-T1400-1"|"9612996474"|"G"|"2025-02-10"|"KMKG00581"|"S"|"1"|"H"|""|"20250210"|"1400"|"BU"|"BREAST CARE UNIT"|"BREAST CARE UNIT"|"BREAST CARE UNIT"|"MILTON KEYNES HOSPITAL"|"STANDING WAY"|"MILTON KEYNES"|"MK6 5LD"|"MK6 5LD"|"20250212-094408" +"NBSSAPPT_DATA"|"000004"|"KMK"|"U"|"BU011"|"N"|"D"|""|"BU011-67246-RA1-DN-T1416-1"|"9630806428"|"F"|"2025-01-31"|"KMK001329"|"S"|"1"|"H"|""|"20250210"|"1416"|"BU"|"BREAST CARE UNIT"|"BREAST CARE UNIT"|"BREAST CARE UNIT"|"MILTON KEYNES HOSPITAL"|"STANDING WAY"|"MILTON KEYNES"|"MK6 5LD"|"MK6 5LD"|"20250212-094418" +"NBSSAPPT_DATA"|"000005"|"KMK"|"B"|"DU101"|"Y"|"B"|""|"DU101-67248-RA1-DN-T0930-1"|"9900798961"|"G"|"2025-02-12"|"KMKG00581"|"S"|"1"|"H"|""|"20250212"|"0930"|"DU"|"DUMMY CLINIC"|"HOLDING CLINIC"|"SO USE ONLY, COVID 19"|""|""|""|""|""|"20250212-095013" +"NBSSAPPT_END"|"00000087"|"20250212"|"095122"|"000005" diff --git a/tests/ServiceLayer.TestUtilities/HttpHelper.cs b/tests/ServiceLayer.TestUtilities/HttpHelper.cs new file mode 100644 index 00000000..13fc2c38 --- /dev/null +++ b/tests/ServiceLayer.TestUtilities/HttpHelper.cs @@ -0,0 +1,33 @@ +using System.Net; +using System.Net.Http.Headers; + +namespace ServiceLayer.TestUtilities; + +public static class HttpHelper +{ + private static readonly HttpClient _client = new(); + + public static async Task SendHttpRequestAsync( + HttpMethod method, + string url, + HttpContent? content = null, + Action? configureHeaders = null) + { + var request = new HttpRequestMessage(method, url) + { + Content = content + }; + + configureHeaders?.Invoke(request.Headers); + + try + { + var response = await _client.SendAsync(request); + return response; + } + catch + { + return new HttpResponseMessage(HttpStatusCode.InternalServerError); + } + } +} diff --git a/tests/mesh-sandbox b/tests/mesh-sandbox new file mode 160000 index 00000000..9282e957 --- /dev/null +++ b/tests/mesh-sandbox @@ -0,0 +1 @@ +Subproject commit 9282e957e853c64c85053124e8f37252f74fb156