Skip to content

Commit

Permalink
Refine Media Types (#441)
Browse files Browse the repository at this point in the history
* Update README.md

* Create HL7v2-templates.md

* Create HL7v2-FHIRValidator.md

* Create HL7v2-ImportantPoints.md

* Update README.md

* Update README.md

Updated STU3-R4 information for OSS FHIR Server

* Fix StyleCop Dependency (#397)

- Fix build-time dependency on StyleCop.Analyzers to no longer force consumers to use the same analyzers

* Bump Newtonsoft.Json in /src/Microsoft.Health.Fhir.TemplateManagement

Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 12.0.3 to 13.0.1.
- [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
- [Commits](JamesNK/Newtonsoft.Json@12.0.3...13.0.1)

---
updated-dependencies:
- dependency-name: Newtonsoft.Json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>

* Bump Newtonsoft.Json from 12.0.3 to 13.0.1 in src/Microsoft.Health.Fhir.TemplateManagement/Microsoft.Health.Fhir.Liquid.Converter.nuspec

* Exclude data folder

* Update the GeoPol

* Update version

* Remove StyleCop from Nuspec (#410)

- Remove StyleCop from the nuspec to prevent forcing consumers to import StyleCop

* Prepare new release for 5.0.3 (#413)

* Fix more than 3 digits for milliseconds in datetime (#409)

* fix

* fix

* Update version to 5.0.3 (#412)

Co-authored-by: sowu880 <[email protected]>

* Add NJsonSchema dependency to nuspec file (#423)

* Prepare new release for 5.0.5 (#425)

* Update version to 5.0.5 (#424)

* Interface to convert JObject (#416)

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: yankunhuang-pku <[email protected]>
Co-authored-by: ginalee-dotcom <[email protected]>
Co-authored-by: Irene Joseph <[email protected]>
Co-authored-by: Qiwei Jin <[email protected]>
Co-authored-by: Will Sugarman <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yankun Huang <[email protected]>
Co-authored-by: Yue Fei <[email protected]>
Co-authored-by: Will Sugarman <[email protected]>
Co-authored-by: QuanWanxx <[email protected]>
  • Loading branch information
11 people authored Nov 25, 2022
1 parent cfe5b02 commit 78ce2d9
Show file tree
Hide file tree
Showing 10 changed files with 367 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using EnsureThat;
using Microsoft.Health.Fhir.TemplateManagement.Client;
using Microsoft.Health.Fhir.TemplateManagement.Exceptions;
using Microsoft.Health.Fhir.TemplateManagement.Models;
Expand All @@ -18,7 +17,6 @@ namespace Microsoft.Health.Fhir.TemplateManagement.FunctionalTests
{
public class OciArtifactFunctionalTests : IAsyncLifetime
{
private const string _orasCacheEnvironmentVariableName = "ORAS_CACHE";
private static readonly string _testTarGzPath = Path.Join("TestData", "TarGzFiles");
private readonly string _containerRegistryServer;
private readonly string _baseLayerTemplatePath = Path.Join(_testTarGzPath, "layerbase.tar.gz");
Expand All @@ -31,8 +29,12 @@ public class OciArtifactFunctionalTests : IAsyncLifetime
private readonly string _testMultiLayersWithValidSequenceNumberImageReference;
private readonly string _testMultiLayersWithInValidSequenceNumberImageReference;
private readonly string _testInvalidCompressedImageReference;
private string _testOneLayerImageDigest;
private string _testMultiLayerImageDigest;
private bool _isOrasValid = true;
private readonly string _orasErrorMessage = "Oras tool invalid.";
private const string _orasCacheEnvironmentVariableName = "ORAS_CACHE";
private const string _defaultOrasCacheEnvironmentVariable = ".oras/cache";

public OciArtifactFunctionalTests()
{
Expand All @@ -43,6 +45,11 @@ public OciArtifactFunctionalTests()
_testMultiLayersWithValidSequenceNumberImageReference = _containerRegistryServer + "/templatetest:multilayers_valid_sequence";
_testMultiLayersWithInValidSequenceNumberImageReference = _containerRegistryServer + "/templatetest:multilayers_invalid_sequence";
_testInvalidCompressedImageReference = _containerRegistryServer + "/templatetest:invalid_image";

if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(_orasCacheEnvironmentVariableName)))
{
Environment.SetEnvironmentVariable(_orasCacheEnvironmentVariableName, _defaultOrasCacheEnvironmentVariable);
}
}

public async Task InitializeAsync()
Expand All @@ -64,7 +71,7 @@ public Task DisposeAsync()
private async Task PushOneLayerWithValidSequenceNumberAsync()
{
string command = $"push {_testOneLayerWithValidSequenceNumberImageReference} {_baseLayerTemplatePath}";
await ExecuteOrasCommandAsync(command);
_testOneLayerImageDigest = await ExecuteOrasCommandAsync(command);
}

private async Task PushOneLayerWithoutSequenceNumberAsync()
Expand All @@ -83,6 +90,7 @@ private async Task PushMultiLayersWithValidSequenceNumberAsync()
{
string command = $"push {_testMultiLayersWithValidSequenceNumberImageReference} {_baseLayerTemplatePath} {_userLayerTemplatePath}";
await ExecuteOrasCommandAsync(command);
_testMultiLayerImageDigest = await ExecuteOrasCommandAsync(command);
}

private async Task PushMultiLayersWithInValidSequenceNumberAsync()
Expand All @@ -97,18 +105,32 @@ private async Task PushInvalidCompressedImageAsync()
await ExecuteOrasCommandAsync(command);
}

private async Task ExecuteOrasCommandAsync(string command)
private async Task<string> ExecuteOrasCommandAsync(string command)
{
try
{
await OrasClient.OrasExecutionAsync(command, Directory.GetCurrentDirectory());
var output = await OrasClient.OrasExecutionAsync(command, Directory.GetCurrentDirectory());
var digest = GetImageDigest(output);
return digest.Value;
}
catch
{
_isOrasValid = false;
return null;
}
}

private Digest GetImageDigest(string input)
{
var digests = Digest.GetDigest(input);
if (digests.Count == 0)
{
throw new OciClientException(TemplateManagementErrorCode.OrasProcessFailed, "Failed to parse image digest.");
}

return digests[0];
}

// Pull one layer image with valid sequence number, successfully pulled with base layer copied.
[Fact]
public async Task GivenOneLayerImage_WhenPulled_ArtifactsWillBePulledWithBaseLayerCopiedAsync()
Expand Down Expand Up @@ -143,6 +165,20 @@ public async Task GivenOneLayerImageWithoutSequenceNumber_WhenPulled_ArtifactsWi
DirectoryHelper.ClearFolder(outputFolder);
}

[Fact]
public async Task GivenOneLayerImage_WhenPulledUsingDigest_ArtifactsWillBePulledWithBaseLayerCopiedAsync()
{
Assert.True(_isOrasValid, _orasErrorMessage);
string outputFolder = "TestData/testOneLayerWithDigest";
DirectoryHelper.ClearFolder(outputFolder);

var testManager = new OciFileManager(_containerRegistryServer, outputFolder);
await testManager.PullOciImageAsync("templatetest", _testOneLayerImageDigest, true);
Assert.Equal(843, Directory.EnumerateFiles(outputFolder, "*.*", SearchOption.AllDirectories).Count());
Assert.Single(Directory.EnumerateFiles(Path.Combine(outputFolder, ".image", "base"), "*.tar.gz", SearchOption.AllDirectories));
DirectoryHelper.ClearFolder(outputFolder);
}

// Pull one layer image with invalid sequence number, successfully pulled with base layer copied.
[Fact]
public async Task GivenOneLayerImageWithInvalidSequenceNumber_WhenPulled_ArtifactsWillBePulledWithBaseLayerCopiedAsync()
Expand Down Expand Up @@ -194,6 +230,20 @@ public async Task GivenMultiLayersImageWithInvalidSequenceNumber_WhenPulled_Arti
DirectoryHelper.ClearFolder(outputFolder);
}

[Fact]
public async Task GivenMultiLayerImage_WhenPulledUsingDigest_ArtifactsWillBePulledWithBaseLayerCopiedAsync()
{
Assert.True(_isOrasValid, _orasErrorMessage);
string outputFolder = "TestData/testMultiLayerWithDigest";
DirectoryHelper.ClearFolder(outputFolder);

var testManager = new OciFileManager(_containerRegistryServer, outputFolder);
await testManager.PullOciImageAsync("templatetest", _testMultiLayerImageDigest, true);
Assert.Equal(10, Directory.EnumerateFiles(outputFolder, "*.*", SearchOption.AllDirectories).Count());
Assert.Single(Directory.EnumerateFiles(Path.Combine(outputFolder, ".image", "base"), "*.tar.gz", SearchOption.AllDirectories));
DirectoryHelper.ClearFolder(outputFolder);
}

// Pull invalid image, exception will be thrown.
[Fact]
public async Task GivenInvalidCompressedImage_WhenPulled_ExceptionWillBeThrownAsync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
using Microsoft.Health.Fhir.Liquid.Converter.Exceptions;
using Microsoft.Health.Fhir.Liquid.Converter.Models;
using Microsoft.Health.Fhir.Liquid.Converter.Processors;
using Microsoft.Health.Fhir.TemplateManagement.Client;
using Microsoft.Health.Fhir.TemplateManagement.Exceptions;
using Microsoft.Health.Fhir.TemplateManagement.Models;
using Microsoft.Health.Fhir.TemplateManagement.Utilities;
using Newtonsoft.Json.Linq;
using Xunit;

Expand All @@ -40,13 +42,24 @@ public class TemplateCollectionFunctionalTests : IAsyncLifetime
private readonly string _defaultStu3ToR4TemplateImageReference = "microsofthealth/stu3tor4templates:default";
private readonly string testOneLayerImageReference;
private readonly string testMultiLayerImageReference;
private readonly string testOneLayerOCIImageReference;
private readonly string testMultiLayerOCIImageReference;
private readonly string testInvalidImageReference;
private readonly string testInvalidTemplateImageReference;
private string testOneLayerImageDigest;
private string testMultiLayerImageDigest;
private readonly ContainerRegistry _containerRegistry = new ContainerRegistry();
private readonly ContainerRegistryInfo _containerRegistryInfo;
private static readonly string _templateDirectory = Path.Join("..", "..", "data", "Templates");
private static readonly string _sampleDataDirectory = Path.Join("..", "..", "data", "SampleData");
private static readonly string _testTarGzPath = Path.Join("TestData", "TarGzFiles");
private readonly string _baseLayerTemplatePath = Path.Join(_testTarGzPath, "layerbase.tar.gz");
private readonly string _userLayerTemplatePath = Path.Join(_testTarGzPath, "layer2.tar.gz");
private static readonly ProcessorSettings _processorSettings = new ProcessorSettings();
private bool _isOrasValid = true;
private readonly string _orasErrorMessage = "Oras tool invalid.";
private const string _orasCacheEnvironmentVariableName = "ORAS_CACHE";
private const string _defaultOrasCacheEnvironmentVariable = ".oras/cache";

public TemplateCollectionFunctionalTests()
{
Expand All @@ -60,7 +73,14 @@ public TemplateCollectionFunctionalTests()
testMultiLayerImageReference = _containerRegistryInfo.ContainerRegistryServer + "/templatetest:multilayers";
testInvalidImageReference = _containerRegistryInfo.ContainerRegistryServer + "/templatetest:invalidlayers";
testInvalidTemplateImageReference = _containerRegistryInfo.ContainerRegistryServer + "/templatetest:invalidtemplateslayers";
testOneLayerOCIImageReference = _containerRegistryInfo.ContainerRegistryServer + "/templatetest:ocionelayer";
testMultiLayerOCIImageReference = _containerRegistryInfo.ContainerRegistryServer + "/templatetest:ocimultilayer";
token = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes($"{_containerRegistryInfo.ContainerRegistryUsername}:{_containerRegistryInfo.ContainerRegistryPassword}"));

if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(_orasCacheEnvironmentVariableName)))
{
Environment.SetEnvironmentVariable(_orasCacheEnvironmentVariableName, _defaultOrasCacheEnvironmentVariable);
}
}

public async Task InitializeAsync()
Expand All @@ -74,10 +94,15 @@ public async Task InitializeAsync()
await InitMultiLayerImageAsync();
await InitInvalidTarGzImageAsync();
await InitInvalidTemplateImageAsync();

await OrasLogin();
await PushOneLayerOCIImageAsync();
await PushMultiLayersOCIImageAsync();
}

public Task DisposeAsync()
{
DirectoryHelper.ClearFolder(Environment.GetEnvironmentVariable(_orasCacheEnvironmentVariableName));
return Task.CompletedTask;
}

Expand All @@ -87,6 +112,12 @@ public static IEnumerable<object[]> GetValidImageInfoWithTag()
yield return new object[] { new List<int> { 767, 838 }, "templatetest", "multilayers" };
}

public static IEnumerable<object[]> GetValidOCIImageInfoWithTag()
{
yield return new object[] { new List<int> { 838 }, "templatetest", "ocionelayer" };
yield return new object[] { new List<int> { 834, 838 }, "templatetest", "ocimultilayer" };
}

public static IEnumerable<object[]> GetHl7v2DataAndEntryTemplate()
{
var data = new List<object[]>
Expand Down Expand Up @@ -310,6 +341,50 @@ public async Task GiveImageReference_WhenGetTemplateCollection_ACorrectTemplateC
}
}

[Theory]
[MemberData(nameof(GetValidOCIImageInfoWithTag))]
public async Task GiveOCIImageReference_WhenGetTemplateCollection_ACorrectTemplateCollectionWillBeReturnedAsync(List<int> expectedTemplatesCounts, string imageName, string tag)
{
if (_containerRegistryInfo == null)
{
return;
}

Assert.True(_isOrasValid, _orasErrorMessage);

string imageReference = string.Format("{0}/{1}:{2}", _containerRegistryInfo.ContainerRegistryServer, imageName, tag);
TemplateCollectionProviderFactory factory = new TemplateCollectionProviderFactory(cache, Options.Create(_config));
var templateCollectionProvider = factory.CreateTemplateCollectionProvider(imageReference, token);
var templateCollection = await templateCollectionProvider.GetTemplateCollectionAsync();
Assert.Equal(expectedTemplatesCounts.Count(), templateCollection.Count());
for (var i = 0; i < expectedTemplatesCounts.Count(); i++)
{
Assert.Equal(expectedTemplatesCounts[i], templateCollection[i].Count());
}
}

[Fact]
public async Task GiveOCIImageReferenceWithDigest_WhenGetTemplateCollection_ACorrectTemplateCollectionWillBeReturnedAsync()
{
if (_containerRegistryInfo == null)
{
return;
}

Assert.True(_isOrasValid, _orasErrorMessage);

string imageReference = string.Format("{0}/{1}@{2}", _containerRegistryInfo.ContainerRegistryServer, "templatetest", testOneLayerImageDigest);
TemplateCollectionProviderFactory factory = new TemplateCollectionProviderFactory(cache, Options.Create(_config));
var templateCollectionProvider = factory.CreateTemplateCollectionProvider(imageReference, token);
var templateCollection = await templateCollectionProvider.GetTemplateCollectionAsync();
Assert.Single(templateCollection);

imageReference = string.Format("{0}/{1}@{2}", _containerRegistryInfo.ContainerRegistryServer, "templatetest", testMultiLayerImageDigest);
templateCollectionProvider = factory.CreateTemplateCollectionProvider(imageReference, token);
templateCollection = await templateCollectionProvider.GetTemplateCollectionAsync();
Assert.Equal(2, templateCollection.Count());
}

[Theory]
[MemberData(nameof(GetHl7v2DataAndEntryTemplate))]
public async Task GetTemplateCollectionFromAcr_WhenGivenHl7v2DataForConverting__ExpectedFhirResourceShouldBeReturnedAsync(string hl7v2Data, string entryTemplate)
Expand Down Expand Up @@ -486,5 +561,56 @@ private async Task InitInvalidTemplateImageAsync()
List<string> templateFiles = new List<string> { invalidTemplatePath };
await _containerRegistry.GenerateTemplateImageAsync(_containerRegistryInfo, testInvalidTemplateImageReference, templateFiles);
}

private async Task PushOneLayerOCIImageAsync()
{
string command = $"push {testOneLayerOCIImageReference} {_baseLayerTemplatePath}";
testOneLayerImageDigest = await ExecuteOrasCommandAsync(command);
}

private async Task PushMultiLayersOCIImageAsync()
{
string command = $"push {testMultiLayerOCIImageReference} {_baseLayerTemplatePath} {_userLayerTemplatePath}";
testMultiLayerImageDigest = await ExecuteOrasCommandAsync(command);
}

private async Task OrasLogin()
{
try
{
var command = $"login {_containerRegistryInfo.ContainerRegistryServer} -u {_containerRegistryInfo.ContainerRegistryUsername} -p {_containerRegistryInfo.ContainerRegistryPassword}";
await OrasClient.OrasExecutionAsync(command);
}
catch
{
_isOrasValid = false;
}
}

private async Task<string> ExecuteOrasCommandAsync(string command)
{
try
{
var output = await OrasClient.OrasExecutionAsync(command, Directory.GetCurrentDirectory());
var digest = GetImageDigest(output);
return digest.Value;
}
catch
{
_isOrasValid = false;
return null;
}
}

private Digest GetImageDigest(string input)
{
var digests = Digest.GetDigest(input);
if (digests.Count == 0)
{
throw new OciClientException(TemplateManagementErrorCode.OrasProcessFailed, "Failed to parse image digest.");
}

return digests[0];
}
}
}
Loading

0 comments on commit 78ce2d9

Please sign in to comment.