public async Task ExternalModuleNotInCacheShouldThrow() { var dispatcher = StrictMock.Of <IModuleDispatcher>(); DiagnosticBuilder.ErrorBuilderDelegate?failureBuilder = null; const string UnqualifiedModuleRefStr = "example.azurecr.invalid/foo/bar:v3"; const string ModuleRefStr = "br:" + UnqualifiedModuleRefStr; var moduleReference = OciArtifactModuleReference.TryParse(null, UnqualifiedModuleRefStr, ConfigurationManager.GetBuiltInConfiguration(), out _) !; moduleReference.Should().NotBeNull(); dispatcher.Setup(m => m.TryGetModuleReference(ModuleRefStr, It.IsAny <RootConfiguration>(), out failureBuilder)).Returns(moduleReference); dispatcher.Setup(m => m.GetModuleRestoreStatus(moduleReference, out failureBuilder)).Returns(ModuleRestoreStatus.Unknown); var resolver = StrictMock.Of <IFileResolver>(); var handler = new BicepRegistryCacheRequestHandler(dispatcher.Object, resolver.Object, ConfigurationManager); var @params = new BicepRegistryCacheParams(ModuleRefStr); (await FluentActions .Awaiting(() => handler.Handle(@params, default)) .Should() .ThrowAsync <InvalidOperationException>()) .WithMessage($"The module '{ModuleRefStr}' has not yet been successfully restored."); }
public void TryGetModuleReference_ValidAlias_ReplacesReferenceValue(string aliasName, string referenceValue, string fullyQualifiedReferenceValue, RootConfiguration configuration) { var reference = OciArtifactModuleReference.TryParse(aliasName, referenceValue, configuration, out var errorBuilder); reference.Should().NotBeNull(); reference !.FullyQualifiedReference.Should().Be(fullyQualifiedReferenceValue); }
public async Task RestoredValidModuleShouldReturnSuccessfully() { var dispatcher = StrictMock.Of <IModuleDispatcher>(); // needed for mocking out parameters DiagnosticBuilder.ErrorBuilderDelegate?nullBuilder = null; DiagnosticBuilder.ErrorBuilderDelegate?readFailureBuilder = x => x.ErrorOccurredReadingFile("Mock file read failure."); string?fileContents = "mock file contents"; const string UnqualifiedModuleRefStr = "example.azurecr.invalid/foo/bar:v3"; const string ModuleRefStr = "br:" + UnqualifiedModuleRefStr; var moduleReference = OciArtifactModuleReference.TryParse(null, UnqualifiedModuleRefStr, ConfigurationManager.GetBuiltInConfiguration(), out _) !; moduleReference.Should().NotBeNull(); var fileUri = new Uri("file:///main.bicep"); dispatcher.Setup(m => m.TryGetModuleReference(ModuleRefStr, It.IsAny <RootConfiguration>(), out nullBuilder)).Returns(moduleReference); dispatcher.Setup(m => m.GetModuleRestoreStatus(moduleReference, out nullBuilder)).Returns(ModuleRestoreStatus.Succeeded); dispatcher.Setup(m => m.TryGetLocalModuleEntryPointUri(null, moduleReference, out nullBuilder)).Returns(fileUri); var resolver = StrictMock.Of <IFileResolver>(); resolver.Setup(m => m.TryRead(fileUri, out fileContents, out nullBuilder)).Returns(true); var handler = new BicepRegistryCacheRequestHandler(dispatcher.Object, resolver.Object, ConfigurationManager); var @params = new BicepRegistryCacheParams(ModuleRefStr); var response = await handler.Handle(@params, default); response.Should().NotBeNull(); response.Content.Should().Be(fileContents); }
public async Task ExternalModuleFailedEntryPointShouldThrow() { var dispatcher = StrictMock.Of <IModuleDispatcher>(); DiagnosticBuilder.ErrorBuilderDelegate?failureBuilder = null; const string UnqualifiedModuleRefStr = "example.azurecr.invalid/foo/bar:v3"; const string ModuleRefStr = "br:" + UnqualifiedModuleRefStr; var configuration = ConfigurationManager.GetBuiltInConfiguration(); var moduleReference = OciArtifactModuleReference.TryParse(null, UnqualifiedModuleRefStr, configuration, out _) !; moduleReference.Should().NotBeNull(); dispatcher.Setup(m => m.TryGetModuleReference(ModuleRefStr, It.IsAny <RootConfiguration>(), out failureBuilder)).Returns(moduleReference); dispatcher.Setup(m => m.GetModuleRestoreStatus(moduleReference, configuration, out failureBuilder)).Returns(ModuleRestoreStatus.Succeeded); dispatcher.Setup(m => m.TryGetLocalModuleEntryPointUri(null, moduleReference, configuration, out failureBuilder)).Returns <Uri?>(null); var resolver = StrictMock.Of <IFileResolver>(); var handler = new BicepRegistryCacheRequestHandler(dispatcher.Object, resolver.Object, ConfigurationManager); var @params = new BicepRegistryCacheParams("/main.bicep", ModuleRefStr); (await FluentActions .Awaiting(() => handler.Handle(@params, default)) .Should() .ThrowAsync <InvalidOperationException>()) .WithMessage($"Unable to obtain the entry point URI for module '{ModuleRefStr}'."); }
private static OciArtifactModuleReference Parse(string package) { var parsed = OciArtifactModuleReference.TryParse(null, package, BicepTestConstants.BuiltInConfigurationWithAnalyzersDisabled, out var failureBuilder); failureBuilder !.Should().BeNull(); parsed.Should().NotBeNull(); return(parsed !); }
public void TryParse_InvalidAliasName_ReturnsNullAndSetsErrorDiagnostic(string aliasName) { var reference = OciArtifactModuleReference.TryParse(aliasName, "", BicepTestConstants.BuiltInConfiguration, out var errorBuilder); reference.Should().BeNull(); errorBuilder !.Should().HaveCode("BCP211"); errorBuilder !.Should().HaveMessage($"The module alias name \"{aliasName}\" is invalid. Valid characters are alphanumeric, \"_\", or \"-\"."); }
public void TryParse_InvalidAlias_ReturnsNullAndSetsError(string aliasName, string referenceValue, RootConfiguration configuration, string expectedCode, string expectedMessage) { var reference = OciArtifactModuleReference.TryParse(aliasName, referenceValue, configuration, out var errorBuilder); reference.Should().BeNull(); ((object?)errorBuilder).Should().NotBeNull(); errorBuilder !.Should().HaveCode(expectedCode); errorBuilder !.Should().HaveMessage(expectedMessage); }
public void TryParse_AliasNotInConfiguration_ReturnsNullAndSetsError(string aliasName, string referenceValue, string?configurationPath, string expectedCode, string expectedMessage) { var configuration = BicepTestConstants.CreateMockConfiguration(configurationPath: configurationPath); var reference = OciArtifactModuleReference.TryParse(aliasName, referenceValue, configuration, out var errorBuilder); reference.Should().BeNull(); ((object?)errorBuilder).Should().NotBeNull(); errorBuilder !.Should().HaveCode(expectedCode); errorBuilder !.Should().HaveMessage(expectedMessage); }
public void InvalidReferencesShouldProduceExpectedError(string value, string expectedCode, string expectedError) { OciArtifactModuleReference.TryParse(null, value, BicepTestConstants.BuiltInConfigurationWithAnalyzersDisabled, out var failureBuilder).Should().BeNull(); failureBuilder !.Should().NotBeNull(); using (new AssertionScope()) { failureBuilder !.Should().HaveCode(expectedCode); failureBuilder !.Should().HaveMessage(expectedError); } }
public async Task FailureToReadEntryPointShouldThrow() { var dispatcher = StrictMock.Of <IModuleDispatcher>(); // needed for mocking out parameters DiagnosticBuilder.ErrorBuilderDelegate?nullBuilder = null; DiagnosticBuilder.ErrorBuilderDelegate?readFailureBuilder = x => x.ErrorOccurredReadingFile("Mock file read failure."); string?fileContents = null; const string UnqualifiedModuleRefStr = "example.azurecr.invalid/foo/bar:v3"; const string ModuleRefStr = "br:" + UnqualifiedModuleRefStr; var configuration = ConfigurationManager.GetBuiltInConfiguration(); var moduleReference = OciArtifactModuleReference.TryParse(null, UnqualifiedModuleRefStr, configuration, out _) !; moduleReference.Should().NotBeNull(); var fileUri = new Uri("file:///main.bicep"); dispatcher.Setup(m => m.TryGetModuleReference(ModuleRefStr, It.IsAny <RootConfiguration>(), out nullBuilder)).Returns(moduleReference); dispatcher.Setup(m => m.GetModuleRestoreStatus(moduleReference, configuration, out nullBuilder)).Returns(ModuleRestoreStatus.Succeeded); dispatcher.Setup(m => m.TryGetLocalModuleEntryPointUri(null, moduleReference, configuration, out nullBuilder)).Returns(fileUri); var resolver = StrictMock.Of <IFileResolver>(); resolver.Setup(m => m.TryRead(fileUri, out fileContents, out readFailureBuilder)).Returns(false); var handler = new BicepRegistryCacheRequestHandler(dispatcher.Object, resolver.Object, ConfigurationManager); var @params = new BicepRegistryCacheParams(fileUri.AbsolutePath, ModuleRefStr); (await FluentActions .Awaiting(() => handler.Handle(@params, default)) .Should() .ThrowAsync <InvalidOperationException>()) .WithMessage($"Unable to read file 'file:///main.bicep'. An error occurred reading file. Mock file read failure."); }
private static async Task <(OciManifest, Stream, string)> DownloadManifestAsync(OciArtifactModuleReference moduleReference, BicepRegistryBlobClient client) { Response <DownloadManifestResult> manifestResponse; try { manifestResponse = await client.DownloadManifestAsync(moduleReference.Tag, new DownloadManifestOptions(ContentType.ApplicationVndOciImageManifestV1Json)); } catch (RequestFailedException exception) when(exception.Status == 404) { // manifest does not exist throw new OciModuleRegistryException("The module does not exist in the registry.", exception); } ValidateManifestResponse(manifestResponse); // the SDK doesn't expose all the manifest properties we need // so we need to deserialize the manifest ourselves to get everything var stream = manifestResponse.Value.Content; stream.Position = 0; var deserialized = DeserializeManifest(stream); stream.Position = 0; return(deserialized, stream, manifestResponse.Value.Digest); }
private BicepRegistryBlobClient CreateBlobClient(Configuration.RootConfiguration configuration, OciArtifactModuleReference moduleReference) => this.clientFactory.CreateBlobClient(configuration, GetRegistryUri(moduleReference), moduleReference.Repository);
private static Uri GetRegistryUri(OciArtifactModuleReference moduleReference) => new Uri($"https://{moduleReference.Registry}");
public async Task PushArtifactAsync(Configuration.RootConfiguration configuration, OciArtifactModuleReference moduleReference, StreamDescriptor config, params StreamDescriptor[] layers) { // TODO: Add similar exception handling as in the pull* method // TODO: How do we choose this? Does it ever change? var algorithmIdentifier = DescriptorFactory.AlgorithmIdentifierSha256; var blobClient = this.CreateBlobClient(configuration, moduleReference); config.ResetStream(); var configDescriptor = DescriptorFactory.CreateDescriptor(algorithmIdentifier, config); config.ResetStream(); var configUploadResult = await blobClient.UploadBlobAsync(config.Stream); var layerDescriptors = new List <OciDescriptor>(layers.Length); foreach (var layer in layers) { layer.ResetStream(); var layerDescriptor = DescriptorFactory.CreateDescriptor(algorithmIdentifier, layer); layerDescriptors.Add(layerDescriptor); layer.ResetStream(); var layerUploadResult = await blobClient.UploadBlobAsync(layer.Stream); } var manifest = new OciManifest(2, configDescriptor, layerDescriptors); using var manifestStream = new MemoryStream(); OciSerialization.Serialize(manifestStream, manifest); manifestStream.Position = 0; // BUG: the client closes the stream :( var manifestUploadResult = await blobClient.UploadManifestAsync(manifestStream, new UploadManifestOptions(ContentType.ApplicationVndOciImageManifestV1Json, moduleReference.Tag)); }
public async Task <OciArtifactResult> PullArtifactAsync(Configuration.RootConfiguration configuration, OciArtifactModuleReference moduleReference) { var client = this.CreateBlobClient(configuration, moduleReference); var(manifest, manifestStream, manifestDigest) = await DownloadManifestAsync(moduleReference, client); var moduleStream = await ProcessManifest(client, manifest); return(new OciArtifactResult(manifestDigest, manifest, manifestStream, moduleStream)); }
public async Task <OciArtifactResult> PullArtifactAsync(RootConfiguration configuration, OciArtifactModuleReference moduleReference) { var client = this.CreateBlobClient(configuration, moduleReference); OciManifest manifest; Stream manifestStream; string manifestDigest; try { Trace.WriteLine($"Authenticated attempt to pull artifact for module {moduleReference.FullyQualifiedReference}."); // Try authenticated client first. (manifest, manifestStream, manifestDigest) = await DownloadManifestAsync(moduleReference, client); } catch (RequestFailedException exception) when(exception.Status == 401 || exception.Status == 403) { Trace.WriteLine($"Authenticated attempt to pull artifact for module {moduleReference.FullyQualifiedReference} failed, received code {exception.Status}. Fallback to anonymous pull."); // Fall back to anonymous client. client = this.CreateBlobClient(configuration, moduleReference, anonymousAccess: true); (manifest, manifestStream, manifestDigest) = await DownloadManifestAsync(moduleReference, client); } var moduleStream = await ProcessManifest(client, manifest); return(new OciArtifactResult(manifestDigest, manifest, manifestStream, moduleStream)); }
public async Task <OciArtifactResult> PullArtifactAsync(RootConfiguration configuration, OciArtifactModuleReference moduleReference) { var client = this.CreateBlobClient(configuration, moduleReference); OciManifest manifest; Stream manifestStream; string manifestDigest; try { // Try authenticated client first. (manifest, manifestStream, manifestDigest) = await DownloadManifestAsync(moduleReference, client); } catch (RequestFailedException exception) when(exception.Status == 401) { // Fall back to anonymous client. client = this.CreateBlobClient(configuration, moduleReference, anonymousAccess: true); (manifest, manifestStream, manifestDigest) = await DownloadManifestAsync(moduleReference, client); } var moduleStream = await ProcessManifest(client, manifest); return(new OciArtifactResult(manifestDigest, manifest, manifestStream, moduleStream)); }