using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Strata.ContinuousImprovement.Biz.DbContexts.Snowflake; using Strata.ContinuousImprovement.Biz.Exploration; using Strata.ContinuousImprovement.Biz.Exploration.CaseTypeFamilies; using Strata.ContinuousImprovement.Biz.Exploration.Filters; using Strata.ContinuousImprovement.Biz.FiscalMonths; using Strata.ContinuousImprovement.Biz.Test.Unit.Utilities; using Strata.ContinuousImprovement.Biz.Utilities; using Strata.ContinuousImprovement.JazzEntityFrameworkStub; using Strata.CoreLib.Claims; using Strata.StrataSphereCompare.Client; using Strata.StrataSphereCompare.Client.Models; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using static Strata.ContinuousImprovement.Biz.Exploration.ExplorationService; using ExplorationFilter = Strata.ContinuousImprovement.Biz.Exploration.Filters.Filter; namespace Strata.ContinuousImprovement.Biz.Test.Unit.Exploration { [TestFixture, Category("Unit")] public class ExplorationServiceBenchmarkingUnitTests { private const string FeatureFlagKey = "cibenchmarkingenabled"; private const string CaseTypeFamilyName = "Sample CTF"; private Mock _snowflakeDatabaseContextMock; private Mock _fiscalMonthResolverMock; private Mock _claimsPrincipalAccessorMock; private Mock _strataSphereCompareServiceMock; private Mock> _explorationServiceLoggerMock; private Mock _explorationFilterServiceMock; private ExplorationInfo _explorationInfo; [OneTimeSetUp] public void OneTimeSetUp() { _snowflakeDatabaseContextMock = new Mock(); _fiscalMonthResolverMock = new Mock(); _explorationServiceLoggerMock = new Mock>(); var principal = TestUtilities.GetClaimsPrincipalAccessor(); var defaultUser = principal.GetCurrentClaimsPrincipal(); _claimsPrincipalAccessorMock = new Mock(); _claimsPrincipalAccessorMock.Setup(a => a.GetCurrentClaimsPrincipal()).Returns(defaultUser); _strataSphereCompareServiceMock = new Mock(); _explorationFilterServiceMock = new Mock(); // Setup ExplorationFilterService mock _explorationFilterServiceMock .Setup(s => s.GetFilterStringsAsync(It.IsAny>(), It.IsAny(), It.IsAny())) .ReturnsAsync(("", "")); _explorationFilterServiceMock .Setup(s => s.BuildDataFiltersAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(new CostDetailsFilterDto()); // Setup 1: For GetCaseTypeFamilySummariesAsync (no drill down filter) _strataSphereCompareServiceMock .Setup(s => s.GetCostDetailsAsync( It.IsAny(), It.Is(filter => filter.CostDetailsFilterDrillDown == null), It.IsAny())) .ReturnsAsync(new[] { new CostDetailsDto { AprDrgCaseTypeFamilyName = CaseTypeFamilyName, P50th_VariableDirectCost = 250.75m, P50th_Alos = 5.2m } }); // Setup 2: For GetCaseTypeFamilySummaryDetailsAsync (with drill down filter) _strataSphereCompareServiceMock .Setup(s => s.GetCostDetailsAsync( It.IsAny(), It.Is(filter => filter.CostDetailsFilterDrillDown != null), It.IsAny())) .ReturnsAsync(new[] { new CostDetailsDto { SphChargeCodeCostDriver = "LOS", P50th_VariableDirectCost = 150.50m, P50th_Alos = 3.2m }, new CostDetailsDto { SphChargeCodeCostDriver = "Surgery", P50th_VariableDirectCost = 300.25m, P50th_Alos = 4.8m } }); // Summary Mock Data _snowflakeDatabaseContextMock .Setup(s => s.QueryAsync( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(new[] { new CaseTypeFamilySummaryInfo { CaseTypeFamilyName = CaseTypeFamilyName } }); // Summary Detail Mock Data - for GetCaseTypeFamilySummaryDetailsAsync _snowflakeDatabaseContextMock .Setup(s => s.QueryAsync( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(new[] { new CaseTypeFamilyEncounterInfo { CaseTypeFamilyName = CaseTypeFamilyName, CostDriver = "LOS" }, new CaseTypeFamilyEncounterInfo { CaseTypeFamilyName = CaseTypeFamilyName, CostDriver = "Surgery" } }); _explorationInfo = new ExplorationCostDriverInfo { CaseTypeFamilyId = 1, PeerGroupId = 1, ExclusionCriteria = new ExclusionCriteria { LosExclusionType = ExclusionCriteriaType.None, CostExclusionType = ExclusionCriteriaType.None }, Filters = new ExplorationFilter // Use the alias { FilterChipItems = new List { new FilterChipItem { ChipType = ChipType.DateRange, Key = ChipKey.DischargeDateID, DateRange = new List { new DateTime(2024, 1, 1), new DateTime(2024, 12, 31) } } } } }; } [Test] public async Task GetCaseTypeFamilySummariesAsync_FeatureFlagOn_PopulatesPeerMetrics() { // Arrange var jazzFactory = new JazzEntityFrameworkFactory(); await jazzFactory.CreateDbContextAsync(CancellationToken.None); var featureFlagWrapper = Mock.Of(); Mock.Get(featureFlagWrapper) .Setup(f => f.IsCiBenchmarkingEnabled(It.IsAny())) .ReturnsAsync(true); var service = new ExplorationService( jazzFactory, _snowflakeDatabaseContextMock.Object, _fiscalMonthResolverMock.Object, featureFlagWrapper, _strataSphereCompareServiceMock.Object, _explorationFilterServiceMock.Object, _explorationServiceLoggerMock.Object); // Act var summaries = await service.GetCaseTypeFamilySummariesAsync(_explorationInfo, CancellationToken.None); var summary = summaries.Single(s => s.Name == CaseTypeFamilyName); // Assert Assert.That(summary.Data.PeerMedianCost, Is.EqualTo(250.75d)); Assert.That(summary.Data.PeerMedianALos, Is.EqualTo(5.2d)); } [Test] public async Task GetCaseTypeFamilySummariesAsync_FeatureFlagOff_DefaultPeerMetrics() { // Arrange var jazzFactory = new JazzEntityFrameworkFactory(); await jazzFactory.CreateDbContextAsync(CancellationToken.None); var featureFlagWrapper = Mock.Of(); Mock.Get(featureFlagWrapper) .Setup(f => f.IsCiBenchmarkingEnabled(It.IsAny())) .ReturnsAsync(false); var service = new ExplorationService( jazzFactory, _snowflakeDatabaseContextMock.Object, _fiscalMonthResolverMock.Object, featureFlagWrapper, _strataSphereCompareServiceMock.Object, _explorationFilterServiceMock.Object, _explorationServiceLoggerMock.Object); // Act var summaries = await service.GetCaseTypeFamilySummariesAsync(_explorationInfo, CancellationToken.None); var summary = summaries.Single(s => s.Name == CaseTypeFamilyName); // Assert Assert.That(summary.Data.PeerMedianCost, Is.EqualTo(0d)); Assert.That(summary.Data.PeerMedianALos, Is.EqualTo(0d)); } [Test, Ignore("Feature flag is not enabled, this might need additional refactoring")] public async Task GetCaseTypeFamilySummaryDetailsAsync_FeatureFlagOn_PopulatesPeerMetrics() { // Arrange var jazzFactory = new JazzEntityFrameworkFactory(); await jazzFactory.CreateDbContextAsync(CancellationToken.None); var featureFlagWrapper = Mock.Of(); Mock.Get(featureFlagWrapper) .Setup(f => f.IsCiBenchmarkingEnabled(It.IsAny())) .ReturnsAsync(true); var service = new ExplorationService( jazzFactory, _snowflakeDatabaseContextMock.Object, _fiscalMonthResolverMock.Object, featureFlagWrapper, _strataSphereCompareServiceMock.Object, _explorationFilterServiceMock.Object, _explorationServiceLoggerMock.Object); // Act var summaries = await service.GetCaseTypeFamilySummaryDetailsAsync(_explorationInfo, CancellationToken.None); var summary = summaries.Single(); // Assert Assert.That(summary, Is.Not.Null); Assert.That(summary.Name, Is.EqualTo(CaseTypeFamilyName)); Assert.That(summary.Children, Is.Not.Null.And.Not.Empty); var losChild = summary.Children.FirstOrDefault(c => c.Name == "LOS"); if (losChild != null) { Assert.That(losChild.Data.PeerMedianCost, Is.EqualTo(150.50d)); } var surgeryChild = summary.Children.FirstOrDefault(c => c.Name == "Surgery"); if (surgeryChild != null) { Assert.That(surgeryChild.Data.PeerMedianCost, Is.EqualTo(300.25d)); } } [Test] public async Task GetCaseTypeFamilySummaryDetailsAsync_FeatureFlagOff_DefaultPeerMetrics() { // Arrange var jazzFactory = new JazzEntityFrameworkFactory(); await jazzFactory.CreateDbContextAsync(CancellationToken.None); var featureFlagWrapper = Mock.Of(); Mock.Get(featureFlagWrapper) .Setup(f => f.IsCiBenchmarkingEnabled(It.IsAny())) .ReturnsAsync(false); var service = new ExplorationService( jazzFactory, _snowflakeDatabaseContextMock.Object, _fiscalMonthResolverMock.Object, featureFlagWrapper, _strataSphereCompareServiceMock.Object, _explorationFilterServiceMock.Object, _explorationServiceLoggerMock.Object); // Act var summaries = await service.GetCaseTypeFamilySummaryDetailsAsync(_explorationInfo as ExplorationCostDriverInfo, CancellationToken.None); var summary = summaries.Single(); // Assert Assert.That(summary, Is.Not.Null); Assert.That(summary.Name, Is.EqualTo(CaseTypeFamilyName)); if (summary.Children != null && summary.Children.Any()) { foreach (var child in summary.Children) { Assert.That(child.Data.PeerMedianCost, Is.EqualTo(0d)); Assert.That(child.Data.PeerMedianALos, Is.EqualTo(0d)); } } } } }