src/Bicep.Core.Samples/DataSetsExtensions.cs (116 lines of code) (raw):

// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Collections.Immutable; using Bicep.Core.Configuration; using Bicep.Core.Diagnostics; using Bicep.Core.Features; using Bicep.Core.FileSystem; using Bicep.Core.Modules; using Bicep.Core.Registry; using Bicep.Core.Registry.Oci; using Bicep.Core.Semantics; using Bicep.Core.SourceGraph; using Bicep.Core.Syntax; using Bicep.Core.UnitTests; using Bicep.Core.UnitTests.Features; using Bicep.Core.UnitTests.Mock; using Bicep.Core.UnitTests.Utils; using Bicep.IO.Abstraction; using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using static Bicep.Core.UnitTests.Utils.RegistryHelper; namespace Bicep.Core.Samples { public static class DataSetsExtensions { public static IEnumerable<object[]> ToDynamicTestData(this IEnumerable<DataSet> source) => source.Select(ToDynamicTestData); public static object[] ToDynamicTestData(this DataSet ds) => [ds]; public static bool HasCrLfNewlines(this DataSet dataSet) => dataSet.Name.EndsWith("_CRLF", StringComparison.Ordinal); public static string SaveFilesToTestDirectory(this DataSet dataSet, TestContext testContext) => FileHelper.SaveEmbeddedResourcesWithPathPrefix(testContext, typeof(DataSet).Assembly, dataSet.GetStreamPrefix()); public static async Task<(Compilation compilation, string outputDirectory, Uri fileUri)> SetupPrerequisitesAndCreateCompilation(this DataSet dataSet, TestContext testContext, FeatureProviderOverrides? features = null) { features ??= new(testContext, RegistryEnabled: dataSet.HasExternalModules); var outputDirectory = dataSet.SaveFilesToTestDirectory(testContext); var clientFactory = dataSet.CreateMockRegistryClients(); await dataSet.PublishModulesToRegistryAsync(clientFactory); var templateSpecRepositoryFactory = dataSet.CreateMockTemplateSpecRepositoryFactory(testContext); var compiler = ServiceBuilder.Create(s => s.AddSingleton(templateSpecRepositoryFactory).AddSingleton(clientFactory).WithFeatureOverrides(features).WithAnalyzersCodesToDisableConfiguration(BicepTestConstants.TestAnalyzersToSkip)).GetCompiler(); var fileUri = PathHelper.FilePathToFileUrl(Path.Combine(outputDirectory, DataSet.TestFileMain)); var compilation = await compiler.CreateCompilation(fileUri); return (compilation, outputDirectory, fileUri); } public static IContainerRegistryClientFactory CreateMockRegistryClients( this DataSet dataSet, params RepoDescriptor[] additionalClients) => CreateMockRegistryClients(dataSet.RegistryModules, additionalClients); public static IContainerRegistryClientFactory CreateMockRegistryClients( ImmutableDictionary<string, DataSet.ExternalModuleInfo> registryModules, params RepoDescriptor[] additionalClients) { var services = ServiceBuilder.Create(s => s.WithDisabledAnalyzersConfiguration() .AddSingleton(BicepTestConstants.ClientFactory) .AddSingleton(BicepTestConstants.TemplateSpecRepositoryFactory)); var dispatcher = services.Construct<IModuleDispatcher>(); var sourceFileFactory = services.Construct<ISourceFileFactory>(); var dummyReferencingFile = BicepTestConstants.DummyBicepFile; var clients = new List<RepoDescriptor>(); foreach (var (moduleName, publishInfo) in registryModules) { var target = publishInfo.Metadata.Target; if (!dispatcher.TryGetArtifactReference(dummyReferencingFile, ArtifactType.Module, target).IsSuccess(out var @ref) || @ref is not OciArtifactReference targetReference) { throw new InvalidOperationException($"Module '{moduleName}' has an invalid target reference '{target}'. Specify a reference to an OCI artifact."); } clients.Add(new(targetReference.Registry, targetReference.Repository, ["tag"])); } return RegistryHelper.CreateMockRegistryClient([.. clients, .. additionalClients]); } public static ITemplateSpecRepositoryFactory CreateEmptyTemplateSpecRepositoryFactory() => CreateMockTemplateSpecRepositoryFactory(ImmutableDictionary<string, DataSet.ExternalModuleInfo>.Empty); public static ITemplateSpecRepositoryFactory CreateMockTemplateSpecRepositoryFactory(this DataSet dataSet, TestContext _) => CreateMockTemplateSpecRepositoryFactory(dataSet.TemplateSpecs); public static ITemplateSpecRepositoryFactory CreateMockTemplateSpecRepositoryFactory(ImmutableDictionary<string, DataSet.ExternalModuleInfo> templateSpecs) { var services = ServiceBuilder.Create(s => s.WithDisabledAnalyzersConfiguration() .AddSingleton(BicepTestConstants.ClientFactory) .AddSingleton(BicepTestConstants.TemplateSpecRepositoryFactory)); var dispatcher = services.Construct<IModuleDispatcher>(); var sourceFileFactory = services.Construct<ISourceFileFactory>(); var dummyReferencingFile = BicepTestConstants.DummyBicepFile; var repositoryMocksBySubscription = new Dictionary<string, Mock<ITemplateSpecRepository>>(); foreach (var (moduleName, templateSpecInfo) in templateSpecs) { if (!dispatcher.TryGetArtifactReference(dummyReferencingFile, ArtifactType.Module, templateSpecInfo.Metadata.Target).IsSuccess(out var @ref) || @ref is not TemplateSpecModuleReference reference) { throw new InvalidOperationException($"Module '{moduleName}' has an invalid target reference '{templateSpecInfo.Metadata.Target}'. Specify a reference to a template spec."); } repositoryMocksBySubscription.TryAdd(reference.SubscriptionId, StrictMock.Of<ITemplateSpecRepository>()); repositoryMocksBySubscription[reference.SubscriptionId] .Setup(x => x.FindTemplateSpecByIdAsync(reference.TemplateSpecResourceId, It.IsAny<CancellationToken>())) .ReturnsAsync(new TemplateSpecEntity(templateSpecInfo.ModuleSource)); } var repositoryFactoryMock = StrictMock.Of<ITemplateSpecRepositoryFactory>(); repositoryFactoryMock .Setup(x => x.CreateRepository(It.IsAny<RootConfiguration>(), It.IsAny<string>())) .Returns<RootConfiguration, string>((_, subscriptionId) => repositoryMocksBySubscription.TryGetValue(subscriptionId, out var repository) ? repository.Object : throw new InvalidOperationException($"No mock client was registered for subscription '{subscriptionId}'.")); return repositoryFactoryMock.Object; } public static async Task PublishModulesToRegistryAsync(this DataSet dataSet, IContainerRegistryClientFactory clientFactory, bool publishSource = true) => await PublishModulesToRegistryAsync(dataSet.RegistryModules, clientFactory, publishSource); public static async Task PublishModulesToRegistryAsync(ImmutableDictionary<string, DataSet.ExternalModuleInfo> registryModules, IContainerRegistryClientFactory clientFactory, bool publishSource) { foreach (var (moduleName, publishInfo) in registryModules) { await RegistryHelper.PublishModuleToRegistryAsync( new ServiceBuilder(), clientFactory, BicepTestConstants.FileSystem, new(publishInfo.Metadata.Target, publishInfo.ModuleSource, WithSource: publishSource, DocumentationUri: null)); } } } }