From 262ff560e71206af77b841009fa5b65232e0febf Mon Sep 17 00:00:00 2001 From: Isao Yamauchi Date: Mon, 17 Nov 2025 15:21:40 -0800 Subject: [PATCH 1/3] Populating 'instantiates' field of CapabilityStatement. --- .../Models/ListedCapabilityStatement.cs | 2 + .../Modules/FhirModule.cs | 6 + .../InstantiatesCapabilityProviderTests.cs | 111 ++++++++++++++++++ .../SmartV2InstantiateCapabilityTests.cs | 47 ++++++++ ...ealth.Fhir.Shared.Core.UnitTests.projitems | 2 + .../Conformance/IInstantiateCapability.cs | 14 +++ .../InstantiatesCapabilityProvider.cs | 60 ++++++++++ .../SmartV2InstantiateCapability.cs | 43 +++++++ ...icrosoft.Health.Fhir.Shared.Core.projitems | 3 + 9 files changed, 288 insertions(+) create mode 100644 src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/InstantiatesCapabilityProviderTests.cs create mode 100644 src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/SmartV2InstantiateCapabilityTests.cs create mode 100644 src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/IInstantiateCapability.cs create mode 100644 src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/InstantiatesCapabilityProvider.cs create mode 100644 src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/SmartV2InstantiateCapability.cs diff --git a/src/Microsoft.Health.Fhir.Core/Features/Conformance/Models/ListedCapabilityStatement.cs b/src/Microsoft.Health.Fhir.Core/Features/Conformance/Models/ListedCapabilityStatement.cs index 14e1300f3c..a6cde93c0c 100644 --- a/src/Microsoft.Health.Fhir.Core/Features/Conformance/Models/ListedCapabilityStatement.cs +++ b/src/Microsoft.Health.Fhir.Core/Features/Conformance/Models/ListedCapabilityStatement.cs @@ -62,5 +62,7 @@ public ListedCapabilityStatement() public IDictionary AdditionalData { get; } public ICollection Profile { get; } + + public ICollection Instantiates { get; internal set; } } } diff --git a/src/Microsoft.Health.Fhir.Shared.Api/Modules/FhirModule.cs b/src/Microsoft.Health.Fhir.Shared.Api/Modules/FhirModule.cs index 028897374e..6fb147f142 100644 --- a/src/Microsoft.Health.Fhir.Shared.Api/Modules/FhirModule.cs +++ b/src/Microsoft.Health.Fhir.Shared.Api/Modules/FhirModule.cs @@ -216,6 +216,12 @@ ResourceElement SetMetadata(Resource resource, string versionId, DateTimeOffset services.AddTransient(typeof(IScopeProvider<>), typeof(ScopeProvider<>)); services.AddScoped(); + + services.TypesInSameAssembly(KnownAssemblies.All) + .AssignableTo() + .Transient() + .AsService(); + services.AddFactory>>(); } } } diff --git a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/InstantiatesCapabilityProviderTests.cs b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/InstantiatesCapabilityProviderTests.cs new file mode 100644 index 0000000000..669dd40865 --- /dev/null +++ b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/InstantiatesCapabilityProviderTests.cs @@ -0,0 +1,111 @@ +// ------------------------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Health.Extensions.DependencyInjection; +using Microsoft.Health.Fhir.Core.Features.Conformance; +using Microsoft.Health.Fhir.Core.Features.Conformance.Models; +using Microsoft.Health.Fhir.Shared.Core.Features.Conformance; +using NSubstitute; +using Xunit; + +namespace Microsoft.Health.Fhir.Shared.Core.UnitTests.Features.Conformance +{ + public class InstantiatesCapabilityProviderTests + { + private readonly InstantiatesCapabilityProvider _provider; + private readonly List _capabilities; + + public InstantiatesCapabilityProviderTests() + { + _capabilities = new List(); + var s = Substitute.For>>(); + s.Value.Returns(_capabilities); + + _provider = new InstantiatesCapabilityProvider(() => s); + } + + [Theory] + [InlineData(1)] + [InlineData(0)] + [InlineData(1, 0)] + [InlineData(0, 0, 0)] + [InlineData(1, 2, 3, 4)] + [InlineData(1, 0, 3, 0)] + public async Task GivenCapabilities_WhenBuilding_ThenInstantiatesFieldIsPopulated( + params int[] counts) + { + var urls = AddCapabilities(counts); + var instantiates = new HashSet(StringComparer.OrdinalIgnoreCase); + var builder = Substitute.For(); + builder.Apply(Arg.Any>()).Returns( + x => + { + var action = (Action)x[0]; + var statement = new ListedCapabilityStatement(); + action(statement); + if (statement.Instantiates != null) + { + foreach (var i in statement.Instantiates) + { + instantiates.Add(i); + } + } + + return builder; + }); + + await _provider.BuildAsync(builder, CancellationToken.None); + + Assert.Equal(urls.Count, instantiates.Count); + Assert.All( + urls, + x => + { + Assert.Contains(x, instantiates); + }); + _capabilities.ForEach(x => x.Received(1).TryGetUrls(out Arg.Any>())); + builder.Received(urls.Any() ? 1 : 0).Apply(Arg.Any>()); + } + + private List AddCapabilities(int[] counts) + { + _capabilities.Clear(); + var capabilityUrls = new List(); + var i = 0; + foreach (var count in counts) + { + var app = $"app{i}"; + var urls = Enumerable.Range(0, count).Select(x => $"http://hl7.org/fhir/{app}/CapabilityStatement/{x}"); + var cap = Substitute.For(); + cap.TryGetUrls(out Arg.Any>()).Returns( + x => + { + var c = count; + var copy = new List(urls); + if (c > 0) + { + x[0] = copy; + return true; + } + + x[0] = null; + return false; + }); + + _capabilities.Add(cap); + capabilityUrls.AddRange(urls); + i++; + } + + return capabilityUrls; + } + } +} diff --git a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/SmartV2InstantiateCapabilityTests.cs b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/SmartV2InstantiateCapabilityTests.cs new file mode 100644 index 0000000000..ae74ccf6e3 --- /dev/null +++ b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/SmartV2InstantiateCapabilityTests.cs @@ -0,0 +1,47 @@ +// ------------------------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using Microsoft.Extensions.Options; +using Microsoft.Health.Fhir.Core.Configs; +using Microsoft.Health.Fhir.Shared.Core.Features.Conformance; +using Xunit; + +namespace Microsoft.Health.Fhir.Shared.Core.UnitTests.Features.Conformance +{ + public class SmartV2InstantiateCapabilityTests + { + [Theory] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public void GivenSecurityConfiguration_WhenSmartV2IsEnabled_ThenInstantiateCapabilityUrlsAreReturned( + bool enabled, + bool enabledWithout) + { + var securityConfiguration = new SecurityConfiguration + { + Authorization = new AuthorizationConfiguration + { + Enabled = enabled, + EnableSmartWithoutAuth = enabledWithout, + }, + }; + + var instantiateCapability = new SmartV2InstantiateCapability( + Options.Create(securityConfiguration)); + if (instantiateCapability.TryGetUrls(out var urls)) + { + Assert.True(enabled || enabledWithout); + Assert.NotNull(urls); + Assert.NotEmpty(urls); + } + else + { + Assert.False(enabled || enabledWithout); + Assert.Null(urls); + } + } + } +} diff --git a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Microsoft.Health.Fhir.Shared.Core.UnitTests.projitems b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Microsoft.Health.Fhir.Shared.Core.UnitTests.projitems index 76c623a790..385c208745 100644 --- a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Microsoft.Health.Fhir.Shared.Core.UnitTests.projitems +++ b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Microsoft.Health.Fhir.Shared.Core.UnitTests.projitems @@ -17,6 +17,8 @@ + + diff --git a/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/IInstantiateCapability.cs b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/IInstantiateCapability.cs new file mode 100644 index 0000000000..dfa2366b92 --- /dev/null +++ b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/IInstantiateCapability.cs @@ -0,0 +1,14 @@ +// ------------------------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Collections.Generic; + +namespace Microsoft.Health.Fhir.Shared.Core.Features.Conformance +{ + public interface IInstantiateCapability + { + bool TryGetUrls(out IEnumerable urls); + } +} diff --git a/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/InstantiatesCapabilityProvider.cs b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/InstantiatesCapabilityProvider.cs new file mode 100644 index 0000000000..0839d9b258 --- /dev/null +++ b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/InstantiatesCapabilityProvider.cs @@ -0,0 +1,60 @@ +// ------------------------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using EnsureThat; +using Microsoft.Health.Extensions.DependencyInjection; +using Microsoft.Health.Fhir.Core.Features.Conformance; + +namespace Microsoft.Health.Fhir.Shared.Core.Features.Conformance +{ + public class InstantiatesCapabilityProvider : IProvideCapability + { + private readonly Func>> _instantiateCapabilityDelegate; + + public InstantiatesCapabilityProvider( + Func>> instantiateCapabilityDelegate) + { + EnsureArg.IsNotNull(instantiateCapabilityDelegate, nameof(instantiateCapabilityDelegate)); + + _instantiateCapabilityDelegate = instantiateCapabilityDelegate; + } + + public Task BuildAsync( + ICapabilityStatementBuilder builder, + CancellationToken cancellationToken) + { + EnsureArg.IsNotNull(builder, nameof(builder)); + + var instantiateUrls = new HashSet(StringComparer.OrdinalIgnoreCase); + using var instantiates = _instantiateCapabilityDelegate(); + foreach (var instantiate in instantiates.Value) + { + if (instantiate.TryGetUrls(out var urls) && urls != null && urls.Any()) + { + foreach (var url in urls) + { + instantiateUrls.Add(url); + } + } + } + + if (instantiateUrls.Any()) + { + builder.Apply( + x => + { + x.Instantiates = instantiateUrls; + }); + } + + return Task.CompletedTask; + } + } +} diff --git a/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/SmartV2InstantiateCapability.cs b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/SmartV2InstantiateCapability.cs new file mode 100644 index 0000000000..569748845f --- /dev/null +++ b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/SmartV2InstantiateCapability.cs @@ -0,0 +1,43 @@ +// ------------------------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using EnsureThat; +using Microsoft.Extensions.Options; +using Microsoft.Health.Fhir.Core.Configs; + +namespace Microsoft.Health.Fhir.Shared.Core.Features.Conformance +{ + public class SmartV2InstantiateCapability : IInstantiateCapability + { + private static readonly string[] Urls = + { + "http://hl7.org/fhir/smart-app-launch/CapabilityStatement/smart-app-state-server", + }; + + private readonly SecurityConfiguration _securityConfiguration; + + public SmartV2InstantiateCapability(IOptions securityConfiguration) + { + EnsureArg.IsNotNull(securityConfiguration?.Value, nameof(securityConfiguration)); + + _securityConfiguration = securityConfiguration.Value; + } + + public bool TryGetUrls(out IEnumerable urls) + { + urls = null; + if (_securityConfiguration.Authorization.Enabled + || _securityConfiguration.Authorization.EnableSmartWithoutAuth) + { + urls = Urls; + return true; + } + + return false; + } + } +} diff --git a/src/Microsoft.Health.Fhir.Shared.Core/Microsoft.Health.Fhir.Shared.Core.projitems b/src/Microsoft.Health.Fhir.Shared.Core/Microsoft.Health.Fhir.Shared.Core.projitems index db0242a3a9..55b8ec7cb5 100644 --- a/src/Microsoft.Health.Fhir.Shared.Core/Microsoft.Health.Fhir.Shared.Core.projitems +++ b/src/Microsoft.Health.Fhir.Shared.Core/Microsoft.Health.Fhir.Shared.Core.projitems @@ -18,6 +18,9 @@ + + + From 367d8dd806b8cc6b538d0fad16c1c978ca0ee235 Mon Sep 17 00:00:00 2001 From: Isao Yamauchi Date: Mon, 17 Nov 2025 15:55:58 -0800 Subject: [PATCH 2/3] Adding owning team and category attributes to the UTs. --- .../Conformance/InstantiatesCapabilityProviderTests.cs | 5 ++++- .../Conformance/SmartV2InstantiateCapabilityTests.cs | 4 ++++ .../Features/Conformance/SmartV2InstantiateCapability.cs | 1 - 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/InstantiatesCapabilityProviderTests.cs b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/InstantiatesCapabilityProviderTests.cs index 669dd40865..33daad5f93 100644 --- a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/InstantiatesCapabilityProviderTests.cs +++ b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/InstantiatesCapabilityProviderTests.cs @@ -4,7 +4,6 @@ // ------------------------------------------------------------------------------------------------- using System; -using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -13,11 +12,15 @@ using Microsoft.Health.Fhir.Core.Features.Conformance; using Microsoft.Health.Fhir.Core.Features.Conformance.Models; using Microsoft.Health.Fhir.Shared.Core.Features.Conformance; +using Microsoft.Health.Fhir.Tests.Common; +using Microsoft.Health.Test.Utilities; using NSubstitute; using Xunit; namespace Microsoft.Health.Fhir.Shared.Core.UnitTests.Features.Conformance { + [Trait(Traits.OwningTeam, OwningTeam.Fhir)] + [Trait(Traits.Category, Categories.Conformance)] public class InstantiatesCapabilityProviderTests { private readonly InstantiatesCapabilityProvider _provider; diff --git a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/SmartV2InstantiateCapabilityTests.cs b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/SmartV2InstantiateCapabilityTests.cs index ae74ccf6e3..f0234d2a68 100644 --- a/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/SmartV2InstantiateCapabilityTests.cs +++ b/src/Microsoft.Health.Fhir.Shared.Core.UnitTests/Features/Conformance/SmartV2InstantiateCapabilityTests.cs @@ -6,10 +6,14 @@ using Microsoft.Extensions.Options; using Microsoft.Health.Fhir.Core.Configs; using Microsoft.Health.Fhir.Shared.Core.Features.Conformance; +using Microsoft.Health.Fhir.Tests.Common; +using Microsoft.Health.Test.Utilities; using Xunit; namespace Microsoft.Health.Fhir.Shared.Core.UnitTests.Features.Conformance { + [Trait(Traits.OwningTeam, OwningTeam.Fhir)] + [Trait(Traits.Category, Categories.Conformance)] public class SmartV2InstantiateCapabilityTests { [Theory] diff --git a/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/SmartV2InstantiateCapability.cs b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/SmartV2InstantiateCapability.cs index 569748845f..78a84ecef4 100644 --- a/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/SmartV2InstantiateCapability.cs +++ b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/SmartV2InstantiateCapability.cs @@ -3,7 +3,6 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------------------------------------------- -using System; using System.Collections.Generic; using EnsureThat; using Microsoft.Extensions.Options; From 0e96683748a10fb8e080f6ec1338a74b1683f63a Mon Sep 17 00:00:00 2001 From: Isao Yamauchi Date: Fri, 28 Nov 2025 07:57:50 -0800 Subject: [PATCH 3/3] Adding a US Core 6 capability. --- .../USCore6InstantiateCapability.cs | 24 +++++++++++++++++++ ...icrosoft.Health.Fhir.Shared.Core.projitems | 1 + 2 files changed, 25 insertions(+) create mode 100644 src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/USCore6InstantiateCapability.cs diff --git a/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/USCore6InstantiateCapability.cs b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/USCore6InstantiateCapability.cs new file mode 100644 index 0000000000..850786c806 --- /dev/null +++ b/src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/USCore6InstantiateCapability.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Collections.Generic; +using Microsoft.Health.Fhir.Shared.Core.Features.Conformance; + +namespace Microsoft.Health.Fhir.Core.Features.Conformance +{ + public class USCore6InstantiateCapability : IInstantiateCapability + { + private static readonly string[] Urls = + { + "http://hl7.org/fhir/us/core/CapabilityStatement/us-core-server", + }; + + public bool TryGetUrls(out IEnumerable urls) + { + urls = Urls; + return true; + } + } +} diff --git a/src/Microsoft.Health.Fhir.Shared.Core/Microsoft.Health.Fhir.Shared.Core.projitems b/src/Microsoft.Health.Fhir.Shared.Core/Microsoft.Health.Fhir.Shared.Core.projitems index 55b8ec7cb5..066719b51c 100644 --- a/src/Microsoft.Health.Fhir.Shared.Core/Microsoft.Health.Fhir.Shared.Core.projitems +++ b/src/Microsoft.Health.Fhir.Shared.Core/Microsoft.Health.Fhir.Shared.Core.projitems @@ -22,6 +22,7 @@ +