-
Notifications
You must be signed in to change notification settings - Fork 572
Populating 'instantiates' field of CapabilityStatement. #5241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
262ff56
367d8dd
42780eb
0e96683
d758fad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| // ------------------------------------------------------------------------------------------------- | ||
| // 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 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 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; | ||
| private readonly List<IInstantiateCapability> _capabilities; | ||
|
|
||
| public InstantiatesCapabilityProviderTests() | ||
| { | ||
| _capabilities = new List<IInstantiateCapability>(); | ||
| var s = Substitute.For<IScoped<IEnumerable<IInstantiateCapability>>>(); | ||
| 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<string>(StringComparer.OrdinalIgnoreCase); | ||
| var builder = Substitute.For<ICapabilityStatementBuilder>(); | ||
| builder.Apply(Arg.Any<Action<ListedCapabilityStatement>>()).Returns( | ||
| x => | ||
| { | ||
| var action = (Action<ListedCapabilityStatement>)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<IEnumerable<string>>())); | ||
| builder.Received(urls.Any() ? 1 : 0).Apply(Arg.Any<Action<ListedCapabilityStatement>>()); | ||
| } | ||
|
|
||
| private List<string> AddCapabilities(int[] counts) | ||
| { | ||
| _capabilities.Clear(); | ||
| var capabilityUrls = new List<string>(); | ||
| 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<IInstantiateCapability>(); | ||
| cap.TryGetUrls(out Arg.Any<IEnumerable<string>>()).Returns( | ||
| x => | ||
| { | ||
| var c = count; | ||
| var copy = new List<string>(urls); | ||
| if (c > 0) | ||
| { | ||
| x[0] = copy; | ||
| return true; | ||
| } | ||
|
|
||
| x[0] = null; | ||
| return false; | ||
| }); | ||
|
|
||
| _capabilities.Add(cap); | ||
| capabilityUrls.AddRange(urls); | ||
| i++; | ||
| } | ||
|
|
||
| return capabilityUrls; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| // ------------------------------------------------------------------------------------------------- | ||
| // 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 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] | ||
| [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); | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<string> urls); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<IScoped<IEnumerable<IInstantiateCapability>>> _instantiateCapabilityDelegate; | ||
|
|
||
| public InstantiatesCapabilityProvider( | ||
| Func<IScoped<IEnumerable<IInstantiateCapability>>> instantiateCapabilityDelegate) | ||
| { | ||
| EnsureArg.IsNotNull(instantiateCapabilityDelegate, nameof(instantiateCapabilityDelegate)); | ||
|
|
||
| _instantiateCapabilityDelegate = instantiateCapabilityDelegate; | ||
| } | ||
|
|
||
| public Task BuildAsync( | ||
| ICapabilityStatementBuilder builder, | ||
| CancellationToken cancellationToken) | ||
| { | ||
| EnsureArg.IsNotNull(builder, nameof(builder)); | ||
|
|
||
| var instantiateUrls = new HashSet<string>(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; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,42 @@ | ||||||||||||||||||||||||||||||||
| // ------------------------------------------------------------------------------------------------- | ||||||||||||||||||||||||||||||||
| // 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 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> securityConfiguration) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| EnsureArg.IsNotNull(securityConfiguration?.Value, nameof(securityConfiguration)); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| _securityConfiguration = securityConfiguration.Value; | ||||||||||||||||||||||||||||||||
Check warningCode scanning / CodeQL Dereferenced variable may be null Warning
Variable
securityConfiguration Error loading related location Loading this Error loading related location Loading
Copilot AutofixAI 4 days ago General approach: ensure the Best concrete fix in this snippet: change the constructor’s guard so that we first check Changes (all in
No new methods or imports are needed; we already use
Suggested changeset
1
src/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/SmartV2InstantiateCapability.cs
Copilot is powered by AI and may make mistakes. Always verify output.
Refresh and try again.
|
||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| public bool TryGetUrls(out IEnumerable<string> urls) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| urls = null; | ||||||||||||||||||||||||||||||||
| if (_securityConfiguration.Authorization.Enabled | ||||||||||||||||||||||||||||||||
| || _securityConfiguration.Authorization.EnableSmartWithoutAuth) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| urls = Urls; | ||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<string> urls) | ||
| { | ||
| urls = Urls; | ||
| return true; | ||
| } | ||
| } | ||
| } |
Check notice
Code scanning / CodeQL
Missed opportunity to use Where Note
Copilot Autofix
AI 4 days ago
In general, to fix this kind of issue you move the predicate from inside the loop into a LINQ
Whereclause on the sequence being iterated. This makes the loop iterate only over elements that satisfy the predicate, reducing nesting and clearly expressing the intent.For this specific code, we need to keep access to both the
IInstantiateCapabilityinstance and the correspondingurlsobtained viaTryGetUrls. BecauseTryGetUrlsuses anoutparameter, we can’t directly put it inside theWherepredicate without losing theurlsvalue. A clean approach is to project the original sequence into a sequence of(instantiate, urls)pairs for whichTryGetUrlssucceeded andurlsis non-null and non-empty. We can achieve this withSelect, callingTryGetUrlsonce per element, thenWhereto filter only successful cases, and finally iterate over the filtered projection. Inside the loop, we then iterate overpair.urlsto populateinstantiateUrls, preserving the original behavior.Concretely, in
BuildAsyncinsrc/Microsoft.Health.Fhir.Shared.Core/Features/Conformance/InstantiatesCapabilityProvider.cs, replace the outerforeach (var instantiate in instantiates.Value)loop and its internalif (instantiate.TryGetUrls(...))with a LINQ pipeline:urlsvariable in a small lambda soTryGetUrlscan assign it.Selectto turn eachinstantiateinto an anonymous object{ Instantiate = instantiate, Urls = urls }.Whereto filter to those entries whereUrlsis not null and has any items.foreachand add each URL toinstantiateUrls.No new using directives or external dependencies are needed;
System.Linqis already imported.