diff --git a/application/CohortManager/src/Functions/DemographicServices/ManageCaasSubscription/ManageCaasSubscription.cs b/application/CohortManager/src/Functions/DemographicServices/ManageCaasSubscription/ManageCaasSubscription.cs index 7aa79dd8f6..f39454fb37 100644 --- a/application/CohortManager/src/Functions/DemographicServices/ManageCaasSubscription/ManageCaasSubscription.cs +++ b/application/CohortManager/src/Functions/DemographicServices/ManageCaasSubscription/ManageCaasSubscription.cs @@ -11,12 +11,13 @@ namespace NHS.CohortManager.DemographicServices; using System.Text; using DataServices.Core; using Model; +using NHS.CohortManager.DemographicServices; public class ManageCaasSubscription { private readonly ILogger _logger; private readonly ICreateResponse _createResponse; - private readonly IOptions _config; + private readonly ManageCaasSubscriptionConfig _config; private readonly IMeshSendCaasSubscribe _meshSendCaasSubscribe; private readonly IRequestHandler _requestHandler; private readonly IDataServiceAccessor _nemsSubscriptionAccessor; @@ -33,7 +34,7 @@ public ManageCaasSubscription( { _logger = logger; _createResponse = createResponse; - _config = config; + _config = config.Value; _meshSendCaasSubscribe = meshSendCaasSubscribe; _requestHandler = requestHandler; _nemsSubscriptionAccessor = nemsSubscriptionAccessor; @@ -46,22 +47,17 @@ public async Task Subscribe([HttpTrigger(AuthorizationLevel.An try { var nhsNumber = req.Query["nhsNumber"]; - if (!ValidationHelper.ValidateNHSNumber(nhsNumber)) + if (!ValidationHelper.ValidateNHSNumber(nhsNumber!)) { return await _createResponse.CreateHttpResponseWithBodyAsync(HttpStatusCode.BadRequest, req, "NHS number is required and must be valid format."); } // Forward to MeshSendCaasSubscribeStub (Shared) - long.TryParse(nhsNumber, out var nhsNo); - var toMailbox = _config.Value.CaasToMailbox; - var fromMailbox = _config.Value.CaasFromMailbox; - if (string.IsNullOrWhiteSpace(toMailbox) || string.IsNullOrWhiteSpace(fromMailbox)) - { - _logger.LogError("CAAS mailbox configuration missing. CaasToMailbox or CaasFromMailbox not set."); - return await _createResponse.CreateHttpResponseWithBodyAsync(HttpStatusCode.InternalServerError, req, "CAAS mailbox configuration missing."); - } + var nhsNo = long.Parse(nhsNumber!); + var toMailbox = _config.CaasToMailbox!; + var fromMailbox = _config.CaasFromMailbox!; var messageId = await _meshSendCaasSubscribe.SendSubscriptionRequest(nhsNo, toMailbox, fromMailbox); - _logger.LogInformation("CAAS Subscribe forwarded to Mesh stub. NHS: {Nhs}, MessageId: {Msg}", nhsNo, messageId); + _logger.LogInformation("CAAS Subscribe forwarded to Mesh stub. MessageId: {Msg}", messageId); return await _createResponse.CreateHttpResponseWithBodyAsync(HttpStatusCode.OK, req, $"Subscription request accepted. MessageId: {messageId}"); } catch (Exception ex) @@ -75,12 +71,12 @@ public async Task Subscribe([HttpTrigger(AuthorizationLevel.An public async Task Unsubscribe([HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req) { var nhsNumber = req.Query["nhsNumber"]; - if (!ValidationHelper.ValidateNHSNumber(nhsNumber)) + if (!ValidationHelper.ValidateNHSNumber(nhsNumber!)) { return await _createResponse.CreateHttpResponseWithBodyAsync(HttpStatusCode.BadRequest, req, "NHS number is required and must be valid format."); } - _logger.LogInformation("[CAAS-Stub] Unsubscribe called for NHS: {Nhs}", nhsNumber); + _logger.LogInformation("[CAAS-Stub] Unsubscribe called"); return await _createResponse.CreateHttpResponseWithBodyAsync(HttpStatusCode.OK, req, "Stub: CAAS subscription would be removed."); } @@ -93,7 +89,7 @@ public async Task CheckSubscriptionStatus([HttpTrigger(Authori string? nhsNumber = req.Query["nhsNumber"]; - if (!ValidationHelper.ValidateNHSNumber(nhsNumber)) + if (!ValidationHelper.ValidateNHSNumber(nhsNumber!)) { _logger.LogError("NHS number is required and must be valid format"); return await _createResponse.CreateHttpResponseWithBodyAsync(HttpStatusCode.BadRequest, req, "NHS number is required and must be valid format."); @@ -135,7 +131,7 @@ public async Task NemsSubscriptionDataService([HttpTrigger(Aut [Function("PollMeshMailbox")] public async Task RunAsync([TimerTrigger("59 23 * * *")] TimerInfo myTimer) { - await _meshPoller.ExecuteHandshake(_config.Value.CaasFromMailbox); + await _meshPoller.ExecuteHandshake(_config.CaasFromMailbox!); } diff --git a/application/CohortManager/src/Functions/DemographicServices/ManageCaasSubscription/ManageCaasSubscriptionConfig.cs b/application/CohortManager/src/Functions/DemographicServices/ManageCaasSubscription/ManageCaasSubscriptionConfig.cs index f8d655c85a..4a9c640448 100644 --- a/application/CohortManager/src/Functions/DemographicServices/ManageCaasSubscription/ManageCaasSubscriptionConfig.cs +++ b/application/CohortManager/src/Functions/DemographicServices/ManageCaasSubscription/ManageCaasSubscriptionConfig.cs @@ -1,7 +1,8 @@ namespace NHS.CohortManager.DemographicServices; +using System.ComponentModel.DataAnnotations; + // Minimal config object for ManageCaasSubscription. -// Intentionally no [Required] attributes so binding does not fail if unset. public class ManageCaasSubscriptionConfig { // Optional URL for pass-through to the existing NEMS data service @@ -19,9 +20,10 @@ public class ManageCaasSubscriptionConfig public string? MeshCaasKeyPassword { get; set; } public string? MeshCaasPassword { get; set; } public required string MeshCaasSharedKey { get; set; } - public required string CaasToMailbox { get; set; } - public required string CaasFromMailbox { get; set; } - + [Required] + public string? CaasToMailbox { get; set; } + [Required] + public string? CaasFromMailbox { get; set; } // Controls whether shared implementations should use stubbed behavior public bool IsStubbed { get; set; } = true; diff --git a/tests/UnitTests/DemographicServicesTests/ManageCaasSubscriptionTests/ManageCaasSubscriptionTests.cs b/tests/UnitTests/DemographicServicesTests/ManageCaasSubscriptionTests/ManageCaasSubscriptionTests.cs index 6712cc4529..d37e5b8194 100644 --- a/tests/UnitTests/DemographicServicesTests/ManageCaasSubscriptionTests/ManageCaasSubscriptionTests.cs +++ b/tests/UnitTests/DemographicServicesTests/ManageCaasSubscriptionTests/ManageCaasSubscriptionTests.cs @@ -13,6 +13,8 @@ namespace NHS.CohortManager.Tests.UnitTests.DemographicServicesTests; using System.Net.Http; using DataServices.Core; using Model; +using System.ComponentModel.DataAnnotations; +using System.Linq; [TestClass] public class ManageCaasSubscriptionTests @@ -25,6 +27,7 @@ public class ManageCaasSubscriptionTests private readonly Mock _mesh = new(); private readonly Mock> _requestHandler = new(); private readonly Mock> _nemsAccessor = new(); + private readonly Mock _meshPoller = new(); public ManageCaasSubscriptionTests() { @@ -55,7 +58,8 @@ public ManageCaasSubscriptionTests() _config.Object, _mesh.Object, _requestHandler.Object, - _nemsAccessor.Object + _nemsAccessor.Object, + _meshPoller.Object ); } @@ -75,35 +79,6 @@ public async Task Subscribe_Invalid_ReturnsBadRequest() Assert.AreEqual(HttpStatusCode.BadRequest, res.StatusCode); } - [TestMethod] - public async Task Subscribe_MissingMailboxes_ReturnsInternalServerError() - { - // Arrange: missing config values - _config.Setup(x => x.Value).Returns(new ManageCaasSubscriptionConfig - { - ManageNemsSubscriptionDataServiceURL = null, - CaasToMailbox = null, - CaasFromMailbox = null - }); - - var sutMissing = new ManageCaasSubscription( - _logger.Object, - _createResponse, - _config.Object, - _mesh.Object, - _requestHandler.Object, - _nemsAccessor.Object - ); - - var req = _setupRequest.Setup(null, new NameValueCollection { { "nhsNumber", "9000000009" } }, HttpMethod.Post); - - // Act - var res = await sutMissing.Subscribe(req.Object); - - // Assert - Assert.AreEqual(HttpStatusCode.InternalServerError, res.StatusCode); - } - [TestMethod] public async Task Unsubscribe_Valid_ReturnsOk() { @@ -235,4 +210,40 @@ public async Task Subscribe_MeshThrows_ReturnsInternalServerError() var res = await _sut.Subscribe(req.Object); Assert.AreEqual(HttpStatusCode.InternalServerError, res.StatusCode); } + + [TestMethod] + public async Task PollMeshMailbox_UsesConfigFromMailbox() + { + // Ensure config has expected mailbox + _config.Setup(x => x.Value).Returns(new ManageCaasSubscriptionConfig + { + CaasFromMailbox = "TEST_FROM", + CaasToMailbox = "TEST_TO" + }); + + var sut = new ManageCaasSubscription( + _logger.Object, + _createResponse, + _config.Object, + _mesh.Object, + _requestHandler.Object, + _nemsAccessor.Object, + _meshPoller.Object + ); + + await sut.RunAsync(null); + _meshPoller.Verify(p => p.ExecuteHandshake("TEST_FROM"), Times.Once); + } + + [TestMethod] + public void Config_MissingMailboxes_FailsValidation() + { + var cfg = new ManageCaasSubscriptionConfig(); + var context = new ValidationContext(cfg); + var results = new System.Collections.Generic.List(); + var isValid = Validator.TryValidateObject(cfg, context, results, validateAllProperties: true); + Assert.IsFalse(isValid); + Assert.IsTrue(results.Any(r => r.MemberNames.Contains("CaasToMailbox"))); + Assert.IsTrue(results.Any(r => r.MemberNames.Contains("CaasFromMailbox"))); + } }