using FluentAssertions; using Moq; using NUnit.Framework; using Strata.ContinuousImprovement.Biz.All.Opportunities; using Strata.ContinuousImprovement.Biz.All.Opportunities.Filters; using Strata.ContinuousImprovement.Biz.Configuration; using Strata.ContinuousImprovement.Biz.DbContexts; using Strata.ContinuousImprovement.Biz.Encounter; using Strata.ContinuousImprovement.Biz.Filter; using Strata.ContinuousImprovement.Biz.Generics; using Strata.ContinuousImprovement.Biz.Initiatives; using Strata.ContinuousImprovement.Biz.Pagination; using Strata.ContinuousImprovement.Biz.Test.Unit.Utilities; using Strata.ContinuousImprovement.JazzEntityFrameworkStub; using Strata.Hangfire.Jazz.Client; using Strata.Hangfire.Jazz.Client.Models; using Strata.Schema.Client; using Strata.Schema.Client.Dtos; using Strata.Schema.Client.Dtos.Info; using Strata.SqlTools.Configuration.Common.AsyncFactory; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace Strata.ContinuousImprovement.Biz.Test.Unit.All.Opportunities { [TestFixture, Category("Unit")] public class AllOpportunityServiceTest { private IAllOpportunityService _allOpportunityService; private Mock> _dbContextFactoryMock; private Mock _jazzDbContextMock; private Mock _schemaServiceMock; private Mock _hangfireServiceMock; private Mock _configurationMock; private IInitiativeService _initiativeService; private IUpdateFactOpportunitySavingsService _updateFactOpportunitySavingsService; private static readonly ResourceFileExtractor _extractor = new ResourceFileExtractor(".Resource."); private List _configurations; internal static List ConfigGuids = new() { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }; internal static List ConfigNames = new() { "FY2021", "FY2022", "FY2023", "FY2024" }; private ScoreDimensionInfoDto _dimension; private List _hierarchies; private List _hierarchyNodes; private List _filterHelpers; private JobEnqueuedResponse _jobResponse; [SetUp] public void TestSetUp() { _dbContextFactoryMock = new Mock>(); _jazzDbContextMock = new Mock(); _schemaServiceMock = new Mock(); _hangfireServiceMock = new Mock(); _configurationMock = new Mock(); _initiativeService = Mock.Of(); _updateFactOpportunitySavingsService = Mock.Of(); Mock.Get(_initiativeService) .Setup(s => s.DeleteAsync(It.IsAny(), It.IsAny())) .Returns(Task.FromResult(true)); Mock.Get(_updateFactOpportunitySavingsService) .Setup(s => s.UpdateFactOpportunitySavings(It.IsAny())); _allOpportunityService = new AllOpportunityService(_dbContextFactoryMock.Object, null, null, _initiativeService, _updateFactOpportunitySavingsService); _configurations = new List { new() { ConfigurationGuid = ConfigGuids[0], Name = ConfigNames.First(), DepartmentRollupGlobalId = string.Empty, ServiceLineDimensionGuid = Guid.NewGuid() }, new() { ConfigurationGuid = ConfigGuids[1], Name = ConfigNames[1], DepartmentRollupGlobalId = "Department", ServiceLineDimensionGuid = Guid.NewGuid() }, new() { ConfigurationGuid = ConfigGuids[2], Name = ConfigNames[2], DepartmentRollupGlobalId = string.Empty, ServiceLineDimensionGuid = Guid.NewGuid() }, new() { ConfigurationGuid = ConfigGuids[3], Name = ConfigNames.Last(), DepartmentRollupGlobalId = string.Empty, ServiceLineDimensionGuid = Guid.NewGuid() } }; _dimension = new ScoreDimensionInfoDto { FriendlyName = "test", DimensionGuid = Guid.NewGuid(), DefaultHierarchyGuid = Guid.NewGuid() }; _hierarchies = new List { new ScoreHierarchyDto { FriendlyName = "test", HierarchyGuid = _dimension.DefaultHierarchyGuid } }; _hierarchyNodes = new List { new HierarchyNodeDto { Name = "Case Type", Path = "CaseType|CaseType|1" } }; _jobResponse = new JobEnqueuedResponse { JobId = Guid.NewGuid() }; _filterHelpers = new List { new FilterHelper { Text = "Case Type", Id = "CaseType|CaseType|1" } }; _hangfireServiceMock.Setup(moq => moq.EnqueueJobAsync(It.IsAny(), It.IsAny())) .Returns(Task.FromResult(_jobResponse)); _configurationMock.Setup(moq => moq.GetConfigurationAsync(It.Is(c => c == ConfigGuids[0]), It.IsAny())) .Returns(Task.FromResult(_configurations[0])); _configurationMock.Setup(moq => moq.GetConfigurationAsync(It.Is(c => c == ConfigGuids[1]), It.IsAny())) .Returns(Task.FromResult(_configurations[1])); _configurationMock.Setup(moq => moq.GetConfigurationAsync(It.Is(c => c == ConfigGuids[2]), It.IsAny())) .Returns(Task.FromResult(_configurations[2])); _configurationMock.Setup(moq => moq.GetConfigurationAsync(It.Is(c => c == _configurations.Last().ConfigurationGuid), It.IsAny())) .Returns(Task.FromResult(_configurations.Last())); _schemaServiceMock.Setup(moq => moq.GetDimensionByGlobalIdAsync(It.IsAny(), It.IsAny())) .Returns(Task.FromResult(_dimension)); _schemaServiceMock.Setup(moq => moq.GetDimensionByIdAsync(It.IsAny(), It.IsAny())) .Returns(Task.FromResult(_dimension)); _schemaServiceMock.Setup(moq => moq.GetScoreHierarchiesByGlobalIdAsync(It.IsAny(), It.IsAny())) .Returns(Task.FromResult(_hierarchies.AsEnumerable())); _schemaServiceMock.Setup(moq => moq.GetHierarchyNodesByHierarchyGuidAsync(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny())) .Returns(Task.FromResult(_hierarchyNodes.AsEnumerable())); } [Test] public async Task TestFirstPage_Sorted_Asc() { // arrange var framework = new JazzEntityFrameworkFactory(); await framework.CreateDbContextAsync(CancellationToken.None); var allOpportunityService = new AllOpportunityService(framework, null, null, _initiativeService, _updateFactOpportunitySavingsService); var filters = new AllFilters() { OpportunityTypes = new List(), IdentifiedSavings = 0, ViewVisible = true, ExcludeInitiatives = false, OpportunitySearch = "", ConfigurationGuid = JazzEntityFrameworkFactory.CurrentConfigurationGuid }; var pagingOptions = new PagingOptions("IdentifiedSavings", SortOrder.Asc); // act var taskResult = await allOpportunityService .GetPagedAsync(pagingOptions, filters, CancellationToken.None); // assert taskResult.Data.Should().NotBeNullOrEmpty() .And.AllBeOfType() .And.HaveCountGreaterThan(1); taskResult.Data.First().IdentifiedSavings .Should().BeLessThan(taskResult.Data.Last().IdentifiedSavings); } [Test] public async Task TestFirstPage_Sorted_Desc() { // arrange var framework = new JazzEntityFrameworkFactory(); await framework.CreateDbContextAsync(CancellationToken.None); var allOpportunityService = new AllOpportunityService(framework, null, null, _initiativeService, _updateFactOpportunitySavingsService); var filters = new AllFilters() { OpportunityTypes = new List(), IdentifiedSavings = 0, ViewVisible = true, ExcludeInitiatives = false, OpportunitySearch = "", ConfigurationGuid = JazzEntityFrameworkFactory.CurrentConfigurationGuid }; var pagingOptions = new PagingOptions("IdentifiedSavings", SortOrder.Desc); // act var taskResult = await allOpportunityService .GetPagedAsync(pagingOptions, filters, CancellationToken.None); // assert taskResult.Data.Should().NotBeNullOrEmpty() .And.AllBeOfType() .And.HaveCountGreaterThan(1); taskResult.Data.First().IdentifiedSavings .Should().BeGreaterThan(taskResult.Data.Last().IdentifiedSavings); } [TestCaseSource(nameof(GetFilterData))] public void TestValidateFilters(AllFilters filters) { if (filters == null) return; if (filters.OpportunityTypes.Any()) filters.OpportunityTypes.Should() .AllBeOfType() .And.NotBeNullOrEmpty(); } [Test] public async Task TestGetExcelWorkbook() { // arrange var framework = new JazzEntityFrameworkFactory(); await framework.CreateDbContextAsync(CancellationToken.None); var opp = framework.ENOpportunities.First(); var filters = new AllFilters() { ConfigurationGuid = framework.Configurations.First().ConfigurationGuid, OpportunityTypes = new[] {$"{(int)OpportunityTypes.Variation}", $"{(int)OpportunityTypes.QualityVariation}", $"{(int)OpportunityTypes.FreeForm}", $"{(int)OpportunityTypes.GeneralLedger}", $"{(int)OpportunityTypes.Payroll}", $"{(int)OpportunityTypes.Encounter}" }, }; var service = new AllOpportunityService(framework, null, null, _initiativeService, _updateFactOpportunitySavingsService); // act var wb = await service.ExportAsync(new SortOptions(), filters, CancellationToken.None); #pragma warning disable S125 // Sections of code should not be commented out //wb.SaveAs(System.IO.Path.Combine(@"C:\Git\continuousimprovement\tests\Strata.ContinuousImprovement.Biz.Test.Unit\Resource", "AllExcelFilter.xlsx")); #pragma warning restore S125 // Sections of code should not be commented out // assert wb.Worksheets.Should().HaveCount(1); var ws = wb.Worksheet(1); ws.Should().NotBeNull(); var expected = @"Examples.AllOpportunity.ExcelFilter.xlsx"; using (var expectedStream = _extractor.ReadFileFromResourceToStream(expected)) using (var actualStream = new MemoryStream()) { wb.SaveAs(actualStream); actualStream.Compare(expectedStream, out var message).Should().BeTrue(message); } } [Test] public async Task TestGetExcelWorkbookNullFilter() { // arrange var framework = new JazzEntityFrameworkFactory(); await framework.CreateDbContextAsync(CancellationToken.None); var service = new AllOpportunityService(framework, null, null, _initiativeService, _updateFactOpportunitySavingsService); // act var wb = await service.ExportAsync(null, null, CancellationToken.None); #pragma warning disable S125 // Sections of code should not be commented out //wb.SaveAs(System.IO.Path.Combine(@"C:\Git\continuousimprovement\tests\Strata.ContinuousImprovement.Biz.Test.Unit\Resource", "AllExcelNullFilter.xlsx")); #pragma warning restore S125 // Sections of code should not be commented out // assert wb.Worksheets.Should().HaveCount(1); var ws = wb.Worksheet(1); ws.Should().NotBeNull(); var expected = @"Examples.AllOpportunity.ExcelNullFilter.xlsx"; using (var expectedStream = _extractor.ReadFileFromResourceToStream(expected)) using (var actualStream = new MemoryStream()) { wb.SaveAs(actualStream); actualStream.Compare(expectedStream, out var message).Should().BeTrue(message); } } [TestCaseSource(typeof(JazzEntityFrameworkFactory), nameof(JazzEntityFrameworkFactory.GetFrameworksWithCancellation))] public async Task TestGetFilterOptionsAsync(JazzEntityFrameworkFactory jazzEntityFrameworkFactory, CancellationToken cancellationToken) { // arrange var opportunityService = new AllOpportunityService(jazzEntityFrameworkFactory, null, null, _initiativeService, _updateFactOpportunitySavingsService); try { // act var taskResult = await opportunityService .GetFilterOptionsAsync(new Guid("e96abe3e-1526-43ca-815e-ee30c5b34345"), cancellationToken); // assert if (string.IsNullOrEmpty(jazzEntityFrameworkFactory.TestName)) { taskResult.Should().BeNull(); return; } taskResult.Should() .BeOfType() .And.NotBeNull(); taskResult.OpportunityTypes.Should().AllBeOfType().And.NotBeNullOrEmpty() .And.NotContain(cd => string.IsNullOrEmpty(cd.Id)) .And.NotContain(cd => string.IsNullOrEmpty(cd.Text)); } catch (NotImplementedException nie) { nie.Should().BeOfType(); } catch (AssertionException ae) { ae.Should().BeOfType(); } catch (Exception e) { e.Should().BeOfType(); } } [Test, Ignore("Handled by the other services")] public async Task TestSetHidden() { // arrange var framework = new JazzEntityFrameworkFactory(); await framework.CreateDbContextAsync(CancellationToken.None); var opportunities = framework.ENOpportunities; var opportunity = opportunities.First(vo => !vo.IsHidden); var isHidden = opportunity.IsHidden; var service = new AllOpportunityService(framework, null, null, _initiativeService, _updateFactOpportunitySavingsService); // act await service.SetHiddenAsync(opportunity.OpportunityGuid, !isHidden, CancellationToken.None); // assert var result = await service.GetById(opportunity.OpportunityGuid, CancellationToken.None); result.IsHidden.Should().Be(!isHidden); } [TestCaseSource(typeof(JazzEntityFrameworkFactory), nameof(JazzEntityFrameworkFactory.GetFrameworksWithCancellation))] public async Task TestSetHiddenAsync(JazzEntityFrameworkFactory jazzEntityFrameworkFactory, CancellationToken cancellationToken) { // arrange var allOpportunityService = new AllOpportunityService(jazzEntityFrameworkFactory, null, null, _initiativeService, _updateFactOpportunitySavingsService); try { var opportunities = allOpportunityService.GetAllAsync(cancellationToken).Result; var opportunity = opportunities.FirstOrDefault(o => o.IsHidden); if (opportunity == null) return; var isHidden = opportunity.IsHidden; //act await allOpportunityService.SetHiddenAsync(opportunity.OpportunityGuid, !isHidden, cancellationToken); if (string.IsNullOrEmpty(jazzEntityFrameworkFactory.TestName)) return; var result = allOpportunityService.GetById(opportunity.OpportunityGuid, cancellationToken).Result; result.IsHidden.Should().Be(!isHidden); } catch (Exception e) { switch (e.GetType().Name) { case "AggregateException": case "OperationCanceledException": return; } e.Should().NotBeOfType(); } } [TestCaseSource(typeof(JazzEntityFrameworkFactory), nameof(JazzEntityFrameworkFactory.GetFrameworksWithCancellation))] public async Task TestSetHiddenAsync_NoOpportunity(JazzEntityFrameworkFactory jazzEntityFrameworkFactory, CancellationToken cancellationToken) { // arrange var opportunity = jazzEntityFrameworkFactory.ENOpportunities.FirstOrDefault(o => o.IsHidden); if (opportunity == null) return; var isHidden = opportunity.IsHidden; var allOpportunityService = new AllOpportunityService(jazzEntityFrameworkFactory, null, null, _initiativeService, _updateFactOpportunitySavingsService); try { // act await allOpportunityService.SetHiddenAsync(Guid.Empty, !isHidden, cancellationToken); } catch (Exception e) { e.Should().BeOfType(); } } [TestCaseSource(typeof(JazzEntityFrameworkFactory), nameof(JazzEntityFrameworkFactory.GetFrameworksWithCancellation))] public async Task TestSetNoteAsync(JazzEntityFrameworkFactory jazzEntityFrameworkFactory, CancellationToken cancellationToken) { // arrange var allOpportunityService = new AllOpportunityService(jazzEntityFrameworkFactory, null, null, _initiativeService, _updateFactOpportunitySavingsService); try { var opportunities = allOpportunityService.GetAllAsync(cancellationToken).Result; var opportunity = opportunities.FirstOrDefault(o => o.Note == string.Empty); if (opportunity == null) return; var note = "new test note"; // act await allOpportunityService.SetNoteAsync(opportunity.OpportunityGuid, note, CancellationToken.None); if (string.IsNullOrEmpty(jazzEntityFrameworkFactory.TestName)) return; var result = allOpportunityService.GetById(opportunity.OpportunityGuid, cancellationToken).Result; result.Note.Should().Be(note); // assert } catch (Exception e) { switch (e.GetType().Name) { case "AggregateException": case "OperationCanceledException": return; } e.Should().NotBeOfType(); } } [Test, Ignore("Handled by the other services")] public async Task TestSetNote() { // arrange var framework = new JazzEntityFrameworkFactory(); await framework.CreateDbContextAsync(CancellationToken.None); var opportunities = framework.ENOpportunities; var opportunity = opportunities.First(vo => string.IsNullOrEmpty(vo.Note)); var note = opportunity.Note; var expected = "Now is the time for all good engineers to write great code!"; var service = new AllOpportunityService(framework, null, null, _initiativeService, _updateFactOpportunitySavingsService); // act await service.SetNoteAsync(opportunity.OpportunityGuid, expected, CancellationToken.None); // assert var result = await service.GetById(opportunity.OpportunityGuid, CancellationToken.None); result.Note.Should().NotBeNullOrEmpty() .And.NotBe(note) .And.Be(expected); } [TestCaseSource(typeof(JazzEntityFrameworkFactory), nameof(JazzEntityFrameworkFactory.GetFrameworksWithCancellation))] public async Task TestSetNoteAsync_NoOpportunity(JazzEntityFrameworkFactory jazzEntityFrameworkFactory, CancellationToken cancellationToken) { // arrange var opportunity = jazzEntityFrameworkFactory.ENOpportunities.FirstOrDefault(o => o.Note == string.Empty); if (opportunity == null) return; var note = "new test note"; var allOpportunityService = new AllOpportunityService(jazzEntityFrameworkFactory, null, null, _initiativeService, _updateFactOpportunitySavingsService); try { // act await allOpportunityService.SetNoteAsync(Guid.Empty, note, cancellationToken); // assert } catch (Exception e) { e.Should().BeOfType(); } } [TestCaseSource(typeof(JazzEntityFrameworkFactory), nameof(JazzEntityFrameworkFactory.GetFrameworks))] public async Task TestGetAllAsync(JazzEntityFrameworkFactory jazzEntityFrameworkFactory) { // arrange var allOpportunityService = new AllOpportunityService(jazzEntityFrameworkFactory, null, null, _initiativeService, _updateFactOpportunitySavingsService); // act var taskResult = await allOpportunityService.GetAllAsync(CancellationToken.None); // assert if (string.IsNullOrEmpty(jazzEntityFrameworkFactory.TestName)) { taskResult.Should().BeNullOrEmpty(); } else { taskResult.Should().NotBeNullOrEmpty(); } } [TestCaseSource(typeof(JazzEntityFrameworkFactory), nameof(JazzEntityFrameworkFactory.GetFrameworks))] public async Task TestGetById(JazzEntityFrameworkFactory jazzEntityFrameworkFactory) { // arrange var allOpportunityService = new AllOpportunityService(jazzEntityFrameworkFactory, null, null, _initiativeService, _updateFactOpportunitySavingsService); // act var tempResult = await allOpportunityService.GetAllAsync(CancellationToken.None); var taskResult = await allOpportunityService.GetById(tempResult.FirstOrDefault()?.OpportunityGuid ?? Guid.Empty, CancellationToken.None); // assert if (string.IsNullOrEmpty(jazzEntityFrameworkFactory.TestName)) { taskResult.Should().BeNull(); } else { taskResult.Should().NotBeNull() .And.BeOfType(); } } [TestCaseSource(typeof(JazzEntityFrameworkFactory), nameof(JazzEntityFrameworkFactory.GetFrameworks))] public async Task TestGetByIds(JazzEntityFrameworkFactory jazzEntityFrameworkFactory) { // arrange var allOpportunityService = new AllOpportunityService(jazzEntityFrameworkFactory, null, null, _initiativeService, _updateFactOpportunitySavingsService); // act var tempResult = await allOpportunityService.GetAllAsync(CancellationToken.None); var ids = tempResult.Select(o => o.OpportunityGuid); var taskResult = await allOpportunityService.GetByIds(ids, CancellationToken.None); // assert if (string.IsNullOrEmpty(jazzEntityFrameworkFactory.TestName)) { taskResult.Should().BeNullOrEmpty(); } else { taskResult.Should().NotBeNullOrEmpty() .And.AllBeOfType() .And.HaveCount(ids.Count()); } } [TearDown] public void TestTearDown() { // Method intentionally left empty. } #region TestCaseData public static IEnumerable GetFilterData() { yield return new TestCaseData(new AllFilters { ConfigurationGuid = new Guid("e96abe3e-1526-43ca-815e-ee30c5b34345") }).SetName("No Filters"); yield return new TestCaseData(new AllFilters { ViewVisible = true, ConfigurationGuid = new Guid("e96abe3e-1526-43ca-815e-ee30c5b34345") }).SetName("View Visible"); yield return new TestCaseData(new AllFilters { ViewVisible = false, ConfigurationGuid = new Guid("e96abe3e-1526-43ca-815e-ee30c5b34345") }).SetName("Not View Visible"); yield return new TestCaseData(new AllFilters { IdentifiedSavings = 1999, ViewVisible = true, ConfigurationGuid = new Guid("e96abe3e-1526-43ca-815e-ee30c5b34345") }).SetName( "By Identified Savings"); yield return new TestCaseData(new AllFilters { IdentifiedSavings = 999, ViewVisible = false, ConfigurationGuid = new Guid("e96abe3e-1526-43ca-815e-ee30c5b34345") }).SetName( "By Identified Savings Not ViewVisible"); yield return new TestCaseData(new AllFilters { OpportunityTypes = new[] { "Entity" }, ViewVisible = true, ConfigurationGuid = new Guid("e96abe3e-1526-43ca-815e-ee30c5b34345") }) .SetName("By OpportunityTypes"); yield return new TestCaseData(new AllFilters { OpportunityTypes = new[] { "Provider" }, ConfigurationGuid = new Guid("e96abe3e-1526-43ca-815e-ee30c5b34345"), ViewVisible = false }) .SetName("By OpportunityTypes Not ViewVisible"); yield return new TestCaseData(new AllFilters { OpportunitySearch = "EN - 101", ConfigurationGuid = new Guid("e96abe3e-1526-43ca-815e-ee30c5b34345") }).SetName("Search By Id"); yield return new TestCaseData(new AllFilters { ExcludeInitiatives = true, ConfigurationGuid = new Guid("e96abe3e-1526-43ca-815e-ee30c5b34345") }).SetName("Exclude Opportunities with Initiatives"); } //public static IEnumerable GetAllOpportunityDataModel() //{ // return from configGuid in ConfigGuids // from EncounterGroup encounterGroup in Enum.GetValues(typeof(EncounterGroup)) // where encounterGroup != EncounterGroup.Both // from EncounterOpportunityLevel encounterOpportunityLevel in Enum.GetValues(typeof(EncounterOpportunityLevel)) // from encounterGroups in new[] { true, false } // from OpportunityTypes in new[] { true, false } // select new TestCaseData(new AllOpportunityDataModel // { // ConfigurationGuid = configGuid, // EncounterGroup = (int)encounterGroup, // EncounterOpportunityLevel = encounterOpportunityLevel, // HasAllEncounterGroups = encounterGroups, // CaseTypes = encounterGroup == EncounterGroup.CaseType // ? new List // { // new() {Text = $"{encounterGroup}", Id = "Id"} // } // : new List(), // PatientPopulations = encounterGroup == EncounterGroup.PatientPopulation // ? new List // { // new () {Text = $"{encounterGroup}", Id = "Id"} // } // : new List(), // HasAllOpportunityTypes = OpportunityTypes, // Entities = encounterOpportunityLevel == EncounterOpportunityLevel.Entity // ? new List // { // new () {Text = $"{encounterOpportunityLevel}", Id = "Id"} // } // : new List(), // ServiceLines = encounterOpportunityLevel == EncounterOpportunityLevel.ServiceLine // ? new List // { // new () {Text = $"{encounterOpportunityLevel}", Id = "Id"} // } // : new List(), // Specialties = encounterOpportunityLevel == EncounterOpportunityLevel.Specialty // ? new List // { // new () {Text = $"{encounterOpportunityLevel}", Id = "Id"} // } // : new List(), // Providers = encounterOpportunityLevel == EncounterOpportunityLevel.Provider // ? new List // { // new () {Text = $"{encounterOpportunityLevel}", Id = "Id"} // } // : new List() // }).SetName($"{nameof(TestCreateAsync)} {ConfigNames[ConfigGuids.IndexOf(configGuid)]} IsUsingCustomEntityDim: {(ConfigGuids.IndexOf(configGuid) == 1)} IsUsingSg2: {(ConfigGuids.IndexOf(configGuid) == 3)} {encounterGroup} {encounterOpportunityLevel}"); //} #endregion } }