From 022525603e95ba3ae6832dbdb6f0f43150c1139f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 21:00:27 +0000 Subject: [PATCH 1/2] Initial plan From 2840e8464dbaac1e6aa041d7251dd9be33760ee3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 21:02:24 +0000 Subject: [PATCH 2/2] Fix AutoApiLogonOperators public mutability Co-authored-by: StuartFerguson <16325469+StuartFerguson@users.noreply.github.com> --- .../General/BootstrapperTests.cs | 32 +++++++++++++++++-- .../Bootstrapper/OperatorRegistry.cs | 4 +-- TransactionProcessor/Startup.cs | 11 ++++++- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/TransactionProcessor.Tests/General/BootstrapperTests.cs b/TransactionProcessor.Tests/General/BootstrapperTests.cs index 4ef336cb..dec26ab5 100644 --- a/TransactionProcessor.Tests/General/BootstrapperTests.cs +++ b/TransactionProcessor.Tests/General/BootstrapperTests.cs @@ -1,8 +1,9 @@ -namespace TransactionProcessor.Tests.General +namespace TransactionProcessor.Tests.General { using System; using System.Collections.Generic; using System.Diagnostics; + using System.Linq; using Lamar; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; @@ -38,6 +39,30 @@ public void VerifyBootstrapperIsValid() Startup.Container.AssertConfigurationIsValid(AssertMode.Full); } + [Fact] + public void ConfigureContainer_PopulatesAutoApiLogonOperators_WithoutDuplicates() + { + Mock hostingEnvironment = new Mock(); + hostingEnvironment.Setup(he => he.EnvironmentName).Returns("Development"); + hostingEnvironment.Setup(he => he.ContentRootPath).Returns("/home"); + hostingEnvironment.Setup(he => he.ApplicationName).Returns("Test Application"); + + Startup s = new Startup(hostingEnvironment.Object); + Startup.Configuration = this.SetupMemoryConfiguration(); + + ServiceRegistry firstServices = new ServiceRegistry(); + this.AddTestRegistrations(firstServices, hostingEnvironment.Object); + s.ConfigureContainer(firstServices); + + Assert.Equal(new[] { "Safaricom", "PataPawaPostPay" }, Startup.AutoApiLogonOperators.ToArray()); + + ServiceRegistry secondServices = new ServiceRegistry(); + this.AddTestRegistrations(secondServices, hostingEnvironment.Object); + s.ConfigureContainer(secondServices); + + Assert.Equal(new[] { "Safaricom", "PataPawaPostPay" }, Startup.AutoApiLogonOperators.ToArray()); + } + private IConfigurationRoot SetupMemoryConfiguration() { Dictionary configuration = new Dictionary(); @@ -54,6 +79,9 @@ private IConfigurationRoot SetupMemoryConfiguration() configuration.Add("AppSettings:SecurityService", "http://localhost"); configuration.Add("SecurityConfiguration:Authority", "http://localhost"); configuration.Add("ConnectionStrings:TransactionProcessorReadModel", "dbconnstring"); + configuration.Add("OperatorConfiguration:Safaricom:ApiLogonRequired", "true"); + configuration.Add("OperatorConfiguration:PataPawaPostPay:ApiLogonRequired", "true"); + configuration.Add("OperatorConfiguration:PataPawaPrePay:ApiLogonRequired", "false"); builder.AddInMemoryCollection(configuration); @@ -103,4 +131,4 @@ private void AddTestRegistrations(IServiceCollection services, // } // } //} -} \ No newline at end of file +} diff --git a/TransactionProcessor/Bootstrapper/OperatorRegistry.cs b/TransactionProcessor/Bootstrapper/OperatorRegistry.cs index fa286f25..6c725a00 100644 --- a/TransactionProcessor/Bootstrapper/OperatorRegistry.cs +++ b/TransactionProcessor/Bootstrapper/OperatorRegistry.cs @@ -68,10 +68,10 @@ private void ConfigureOperator(String operatorId) where T : class { BaseOperatorConfiguration cfg = configObject as BaseOperatorConfiguration; if (cfg.ApiLogonRequired) { - Startup.AutoApiLogonOperators.Add(operatorId); + Startup.AddAutoApiLogonOperator(operatorId); } } #endregion } -} \ No newline at end of file +} diff --git a/TransactionProcessor/Startup.cs b/TransactionProcessor/Startup.cs index 9d536234..b83eeb86 100644 --- a/TransactionProcessor/Startup.cs +++ b/TransactionProcessor/Startup.cs @@ -40,7 +40,7 @@ public class Startup public static Container Container; - public static List AutoApiLogonOperators = new List(); + private static readonly List AutoApiLogonOperatorsInternal = new List(); #endregion @@ -77,6 +77,8 @@ public Startup(IWebHostEnvironment webHostEnvironment) { public static IServiceProvider ServiceProvider { get; set; } + public static IReadOnlyCollection AutoApiLogonOperators => AutoApiLogonOperatorsInternal.AsReadOnly(); + /// /// Gets or sets the web host environment. /// @@ -135,6 +137,7 @@ public void Configure(IApplicationBuilder app, public void ConfigureContainer(ServiceRegistry services) { ConfigurationReader.Initialise(Startup.Configuration); + Startup.AutoApiLogonOperatorsInternal.Clear(); services.IncludeRegistry(); services.IncludeRegistry(); @@ -154,6 +157,12 @@ public void ConfigureContainer(ServiceRegistry services) { Startup.ServiceProvider = services.BuildServiceProvider(); } + internal static void AddAutoApiLogonOperator(String operatorId) { + if (Startup.AutoApiLogonOperatorsInternal.Contains(operatorId) == false) { + Startup.AutoApiLogonOperatorsInternal.Add(operatorId); + } + } + private void ConfigureEndpoints(IApplicationBuilder app) { app.UseEndpoints(endpoints => { endpoints.MapControllers();