public async Task SyndicatedTag() { string expectedManifest1 = @"image: mcr.microsoft.com/repo:sharedtag2 tags: [sharedtag1] manifests: - image: mcr.microsoft.com/repo:tag1 platform: architecture: amd64 os: linux "; string expectedManifest2 = @"image: mcr.microsoft.com/repo2:sharedtag2a tags: [sharedtag2b] manifests: - image: mcr.microsoft.com/repo2:tag2 platform: architecture: amd64 os: linux "; bool manifest1Found = false; bool manifest2Found = false; Mock <IManifestToolService> manifestToolService = new Mock <IManifestToolService>(); manifestToolService .Setup(o => o.PushFromSpec(It.IsAny <string>(), false)) .Callback((string manifestFile, bool isDryRun) => { string manifestContents = File.ReadAllText(manifestFile); if (manifestContents == expectedManifest1) { manifest1Found = true; } else if (manifestContents == expectedManifest2) { manifest2Found = true; } }); manifestToolService .Setup(o => o.Inspect(It.IsAny <string>(), false)) .Returns(ManifestToolServiceHelper.CreateTagManifest(ManifestToolService.ManifestListMediaType, "digest")); PublishManifestCommand command = new PublishManifestCommand( manifestToolService.Object, Mock.Of <ILoggerService>()); using TempFolderContext tempFolderContext = new TempFolderContext(); command.Options.Manifest = Path.Combine(tempFolderContext.Path, "manifest.json"); command.Options.ImageInfoPath = Path.Combine(tempFolderContext.Path, "image-info.json"); string dockerfile = CreateDockerfile("1.0/repo/os", tempFolderContext); ImageArtifactDetails imageArtifactDetails = new ImageArtifactDetails { Repos = { new RepoData { Repo = "repo", Images = { new ImageData { Platforms = { CreatePlatform(dockerfile, simpleTags: new List <string> { "tag1", "tag2" }) }, Manifest = new ManifestData { SharedTags = { "sharedtag1", "sharedtag2" } } } } } } }; File.WriteAllText(command.Options.ImageInfoPath, JsonHelper.SerializeObject(imageArtifactDetails)); const string syndicatedRepo2 = "repo2"; Platform platform; Manifest manifest = CreateManifest( CreateRepo("repo", CreateImage( new Platform[] { platform = CreatePlatform(dockerfile, Array.Empty <string>()) }, new Dictionary <string, Tag> { { "sharedtag2", new Tag { Syndication = new TagSyndication { Repo = syndicatedRepo2, DestinationTags = new string[] { "sharedtag2a", "sharedtag2b" } } } }, { "sharedtag1", new Tag() } })) ); manifest.Registry = "mcr.microsoft.com"; platform.Tags = new Dictionary <string, Tag> { { "tag1", new Tag() }, { "tag2", new Tag { Syndication = new TagSyndication { Repo = syndicatedRepo2, DestinationTags = new string[] { "tag2" } } } }, }; File.WriteAllText(command.Options.Manifest, JsonHelper.SerializeObject(manifest)); command.LoadManifest(); await command.ExecuteAsync(); Assert.True(manifest1Found); Assert.True(manifest2Found); manifestToolService .Verify(o => o.PushFromSpec(It.IsAny <string>(), false), Times.Exactly(2)); }
public async Task ImageInfoTagOutput() { Mock <IManifestToolService> manifestToolService = new Mock <IManifestToolService>(); manifestToolService .Setup(o => o.Inspect("repo1:sharedtag2", false)) .Returns(ManifestToolServiceHelper.CreateTagManifest(ManifestToolService.ManifestListMediaType, "digest1")); manifestToolService .Setup(o => o.Inspect("repo2:sharedtag3", false)) .Returns(ManifestToolServiceHelper.CreateTagManifest(ManifestToolService.ManifestListMediaType, "digest2")); PublishManifestCommand command = new PublishManifestCommand( manifestToolService.Object, Mock.Of <ILoggerService>()); using TempFolderContext tempFolderContext = new TempFolderContext(); command.Options.Manifest = Path.Combine(tempFolderContext.Path, "manifest.json"); command.Options.ImageInfoPath = Path.Combine(tempFolderContext.Path, "image-info.json"); string dockerfile1 = CreateDockerfile("1.0/repo1/os", tempFolderContext); string dockerfile2 = CreateDockerfile("1.0/repo2/os", tempFolderContext); string dockerfile3 = CreateDockerfile("1.0/repo3/os", tempFolderContext); ImageArtifactDetails imageArtifactDetails = new ImageArtifactDetails { Repos = { new RepoData { Repo = "repo1", Images = { new ImageData { Platforms = { CreatePlatform(dockerfile1), new PlatformData { } }, Manifest = new ManifestData { SharedTags = { "sharedtag1", "sharedtag2" } } } } }, new RepoData { Repo = "repo2", Images = { new ImageData { Platforms = { CreatePlatform(dockerfile2) }, Manifest = new ManifestData { SharedTags = { "sharedtag1", "sharedtag3" } } } } }, new RepoData { Repo = "repo3", Images = { new ImageData { Platforms = { CreatePlatform(dockerfile3) } } } } } }; File.WriteAllText(command.Options.ImageInfoPath, JsonHelper.SerializeObject(imageArtifactDetails)); Manifest manifest = CreateManifest( CreateRepo("repo1", CreateImage( new Platform[] { CreatePlatform(dockerfile1, new string[] { "tag1" }) }, new Dictionary <string, Tag> { { "sharedtag2", new Tag() }, { "sharedtag1", new Tag() } })), CreateRepo("repo2", CreateImage( new Platform[] { CreatePlatform(dockerfile2, new string[] { "tag2" }) }, new Dictionary <string, Tag> { { "sharedtag3", new Tag() }, { "sharedtag1", new Tag() } })), CreateRepo("repo3", CreateImage( new Platform[] { CreatePlatform(dockerfile3, new string[] { "tag3" }) })), CreateRepo("unpublishedrepo", CreateImage( new Platform[] { CreatePlatform( CreateDockerfile("1.0/unpublishedrepo/os", tempFolderContext), new string[] { "tag" }) }, new Dictionary <string, Tag> { { "sharedtag", new Tag() } })) ); File.WriteAllText(command.Options.Manifest, JsonHelper.SerializeObject(manifest)); command.LoadManifest(); await command.ExecuteAsync(); string actualOutput = File.ReadAllText(command.Options.ImageInfoPath); ImageArtifactDetails actualImageArtifactDetails = JsonConvert.DeserializeObject <ImageArtifactDetails>(actualOutput); // Since we don't know what the exact Created time will be that the command has calculated, we're going to // pull it from the data, verify that it's recent and then use it for constructing our expected data value. DateTime actualCreatedDate = actualImageArtifactDetails.Repos[0].Images[0].Manifest.Created; Assert.True(actualCreatedDate > (DateTime.Now.ToUniversalTime() - TimeSpan.FromMinutes(1))); Assert.True(actualCreatedDate < (DateTime.Now.ToUniversalTime() + TimeSpan.FromMinutes(1))); imageArtifactDetails.Repos[0].Images[0].Manifest.Digest = "repo1@digest1"; imageArtifactDetails.Repos[0].Images[0].Manifest.Created = actualCreatedDate; imageArtifactDetails.Repos[1].Images[0].Manifest.Digest = "repo2@digest2"; imageArtifactDetails.Repos[1].Images[0].Manifest.Created = actualCreatedDate; string expectedOutput = JsonHelper.SerializeObject(imageArtifactDetails); Assert.Equal(expectedOutput, actualOutput); }
public async Task DuplicatePlatform() { string expectedManifest1 = @"image: mcr.microsoft.com/repo1:sharedtag2 tags: [sharedtag1] manifests: - image: mcr.microsoft.com/repo1:tag1 platform: architecture: amd64 os: linux "; string expectedManifest2 = @"image: mcr.microsoft.com/repo1:sharedtag3 manifests: - image: mcr.microsoft.com/repo1:tag1 platform: architecture: amd64 os: linux "; bool manifest1Found = false; bool manifest2Found = false; Mock <IManifestService> manifestToolService = new Mock <IManifestService>(); manifestToolService .Setup(o => o.PushFromSpec(It.IsAny <string>(), false)) .Callback((string manifestFile, bool isDryRun) => { string manifestContents = File.ReadAllText(manifestFile); if (manifestContents.NormalizeLineEndings(expectedManifest1) == expectedManifest1) { manifest1Found = true; } else if (manifestContents.NormalizeLineEndings(expectedManifest2) == expectedManifest2) { manifest2Found = true; } }); manifestToolService .Setup(o => o.GetManifestAsync(It.IsAny <string>(), It.IsAny <IRegistryCredentialsHost>(), false)) .ReturnsAsync(new ManifestQueryResult("digest", new JsonObject())); PublishManifestCommand command = new PublishManifestCommand( manifestToolService.Object, Mock.Of <ILoggerService>(), Mock.Of <IDateTimeService>()); using TempFolderContext tempFolderContext = new TempFolderContext(); command.Options.Manifest = Path.Combine(tempFolderContext.Path, "manifest.json"); command.Options.ImageInfoPath = Path.Combine(tempFolderContext.Path, "image-info.json"); string dockerfile = CreateDockerfile("1.0/repo1/os", tempFolderContext); ImageArtifactDetails imageArtifactDetails = new ImageArtifactDetails { Repos = { new RepoData { Repo = "repo1", Images = { new ImageData { Platforms = { CreatePlatform(dockerfile, simpleTags: new List <string> { "tag1", "tag2" }) }, Manifest = new ManifestData { SharedTags = { "sharedtag1", "sharedtag2" } } }, new ImageData { Platforms = { CreatePlatform(dockerfile) }, Manifest = new ManifestData { SharedTags = { "sharedtag3" } } } } } } }; File.WriteAllText(command.Options.ImageInfoPath, JsonHelper.SerializeObject(imageArtifactDetails)); Manifest manifest = CreateManifest( CreateRepo("repo1", CreateImage( new Platform[] { CreatePlatform(dockerfile, new string[] { "tag1", "tag2" }) }, new Dictionary <string, Tag> { { "sharedtag2", new Tag() }, { "sharedtag1", new Tag() } }), CreateImage( new Platform[] { CreatePlatform(dockerfile, Array.Empty <string>()) }, new Dictionary <string, Tag> { { "sharedtag3", new Tag() } })) ); manifest.Registry = "mcr.microsoft.com"; File.WriteAllText(command.Options.Manifest, JsonHelper.SerializeObject(manifest)); command.LoadManifest(); await command.ExecuteAsync(); Assert.True(manifest1Found); Assert.True(manifest2Found); manifestToolService .Verify(o => o.PushFromSpec(It.IsAny <string>(), false), Times.Exactly(2)); }
public async Task SyndicatedTag() { string expectedManifest1 = @"image: mcr.microsoft.com/repo:sharedtag2 tags: [sharedtag1] manifests: - image: mcr.microsoft.com/repo:tag1 platform: architecture: amd64 os: linux - image: mcr.microsoft.com/repo:tag3 platform: architecture: amd64 os: linux "; string expectedManifest2 = @"image: mcr.microsoft.com/repo2:sharedtag2a tags: [sharedtag2b] manifests: - image: mcr.microsoft.com/repo2:tag2 platform: architecture: amd64 os: linux "; bool manifest1Found = false; bool manifest2Found = false; Mock <IManifestService> manifestToolService = new Mock <IManifestService>(); manifestToolService .Setup(o => o.PushFromSpec(It.IsAny <string>(), false)) .Callback((string manifestFile, bool isDryRun) => { string manifestContents = File.ReadAllText(manifestFile); if (manifestContents.NormalizeLineEndings(expectedManifest1) == expectedManifest1) { manifest1Found = true; } else if (manifestContents.NormalizeLineEndings(expectedManifest2) == expectedManifest2) { manifest2Found = true; } }); manifestToolService .Setup(o => o.GetManifestAsync(It.IsAny <string>(), It.IsAny <IRegistryCredentialsHost>(), false)) .ReturnsAsync(new ManifestQueryResult("digest", new JsonObject())); DateTime manifestCreatedDate = DateTime.UtcNow; IDateTimeService dateTimeService = Mock.Of <IDateTimeService>(o => o.UtcNow == manifestCreatedDate); PublishManifestCommand command = new PublishManifestCommand( manifestToolService.Object, Mock.Of <ILoggerService>(), dateTimeService); using TempFolderContext tempFolderContext = new TempFolderContext(); command.Options.Manifest = Path.Combine(tempFolderContext.Path, "manifest.json"); command.Options.ImageInfoPath = Path.Combine(tempFolderContext.Path, "image-info.json"); string dockerfile1 = CreateDockerfile("1.0/repo/os", tempFolderContext); string dockerfile2 = CreateDockerfile("1.0/repo/os2", tempFolderContext); ImageArtifactDetails imageArtifactDetails = new ImageArtifactDetails { Repos = { new RepoData { Repo = "repo", Images = { new ImageData { Platforms = { CreatePlatform(dockerfile1, simpleTags: new List <string> { "tag1", "tag2" }) }, Manifest = new ManifestData { SharedTags = { "sharedtag1", "sharedtag2" } } } } } } }; File.WriteAllText(command.Options.ImageInfoPath, JsonHelper.SerializeObject(imageArtifactDetails)); const string syndicatedRepo2 = "repo2"; Platform platform1; Platform platform2; Manifest manifest = CreateManifest( CreateRepo("repo", CreateImage( new Platform[] { platform1 = CreatePlatform(dockerfile1, Array.Empty <string>()), platform2 = CreatePlatform(dockerfile2, Array.Empty <string>()) }, new Dictionary <string, Tag> { { "sharedtag2", new Tag { Syndication = new TagSyndication { Repo = syndicatedRepo2, DestinationTags = new string[] { "sharedtag2a", "sharedtag2b" } } } }, { "sharedtag1", new Tag() } })) ); manifest.Registry = "mcr.microsoft.com"; platform1.Tags = new Dictionary <string, Tag> { { "tag1", new Tag() }, { "tag2", new Tag { Syndication = new TagSyndication { Repo = syndicatedRepo2, DestinationTags = new string[] { "tag2" } } } }, }; platform2.Tags = new Dictionary <string, Tag> { { "tag3", new Tag() } }; File.WriteAllText(command.Options.Manifest, JsonHelper.SerializeObject(manifest)); command.LoadManifest(); await command.ExecuteAsync(); Assert.True(manifest1Found); Assert.True(manifest2Found); manifestToolService .Verify(o => o.PushFromSpec(It.IsAny <string>(), false), Times.Exactly(2)); ImageArtifactDetails expectedImageArtifactDetails = new ImageArtifactDetails { Repos = { new RepoData { Repo = "repo", Images = { new ImageData { Platforms = { CreatePlatform(dockerfile1, simpleTags: new List <string> { "tag1", "tag2" }) }, Manifest = new ManifestData { Digest = "mcr.microsoft.com/repo@digest", Created = manifestCreatedDate, SyndicatedDigests = new List <string> { "mcr.microsoft.com/repo2@digest" }, SharedTags = { "sharedtag1", "sharedtag2" } } } } } } }; string expectedOutput = JsonHelper.SerializeObject(expectedImageArtifactDetails); string actualOutput = File.ReadAllText(command.Options.ImageInfoPath); Assert.Equal(expectedOutput, actualOutput); }
public async Task ImageInfoTagOutput() { Mock <IManifestService> manifestToolService = new Mock <IManifestService>(); manifestToolService .Setup(o => o.GetManifestAsync("repo1:sharedtag2", It.IsAny <IRegistryCredentialsHost>(), false)) .ReturnsAsync(new ManifestQueryResult("digest1", new JsonObject())); manifestToolService .Setup(o => o.GetManifestAsync("repo2:sharedtag3", It.IsAny <IRegistryCredentialsHost>(), false)) .ReturnsAsync(new ManifestQueryResult("digest2", new JsonObject())); DateTime manifestCreatedDate = DateTime.UtcNow; IDateTimeService dateTimeService = Mock.Of <IDateTimeService>(o => o.UtcNow == manifestCreatedDate); PublishManifestCommand command = new PublishManifestCommand( manifestToolService.Object, Mock.Of <ILoggerService>(), dateTimeService); using TempFolderContext tempFolderContext = new TempFolderContext(); command.Options.Manifest = Path.Combine(tempFolderContext.Path, "manifest.json"); command.Options.ImageInfoPath = Path.Combine(tempFolderContext.Path, "image-info.json"); string dockerfile1 = CreateDockerfile("1.0/repo1/os", tempFolderContext); string dockerfile2 = CreateDockerfile("1.0/repo2/os", tempFolderContext); string dockerfile3 = CreateDockerfile("1.0/repo3/os", tempFolderContext); const string digest1 = "sha256:123"; const string digest2 = "sha256:ABC"; const string digest3 = "sha256:DEF"; ImageArtifactDetails imageArtifactDetails = new ImageArtifactDetails { Repos = { new RepoData { Repo = "repo1", Images = { new ImageData { Platforms = { CreatePlatform(dockerfile1, digest: digest1, simpleTags: new List <string>{ "tag1" }), new PlatformData { } }, Manifest = new ManifestData { SharedTags = { "sharedtag1", "sharedtag2" } } } } }, new RepoData { Repo = "repo2", Images = { new ImageData { Platforms = { CreatePlatform(dockerfile2, digest: digest2, simpleTags: new List <string>{ "tag2" }) }, Manifest = new ManifestData { SharedTags = { "sharedtag1", "sharedtag3" } } } } }, new RepoData { Repo = "repo3", Images = { new ImageData { Platforms = { CreatePlatform(dockerfile3, digest: digest3, simpleTags: new List <string>{ "tag3" }) } } } } } }; File.WriteAllText(command.Options.ImageInfoPath, JsonHelper.SerializeObject(imageArtifactDetails)); Manifest manifest = CreateManifest( CreateRepo("repo1", CreateImage( new Platform[] { CreatePlatform(dockerfile1, new string[] { "tag1" }) }, new Dictionary <string, Tag> { { "sharedtag2", new Tag() }, { "sharedtag1", new Tag() } })), CreateRepo("repo2", CreateImage( new Platform[] { CreatePlatform(dockerfile2, new string[] { "tag2" }) }, new Dictionary <string, Tag> { { "sharedtag3", new Tag() }, { "sharedtag1", new Tag() } })), CreateRepo("repo3", CreateImage( new Platform[] { CreatePlatform(dockerfile3, new string[] { "tag3" }) })), CreateRepo("unpublishedrepo", CreateImage( new Platform[] { CreatePlatform( CreateDockerfile("1.0/unpublishedrepo/os", tempFolderContext), new string[] { "tag" }) }, new Dictionary <string, Tag> { { "sharedtag", new Tag() } })) ); File.WriteAllText(command.Options.Manifest, JsonHelper.SerializeObject(manifest)); command.LoadManifest(); await command.ExecuteAsync(); string actualOutput = File.ReadAllText(command.Options.ImageInfoPath); ImageArtifactDetails actualImageArtifactDetails = JsonConvert.DeserializeObject <ImageArtifactDetails>(actualOutput); ImageArtifactDetails expectedImageArtifactDetails = new() { Repos = { new RepoData { Repo = "repo1", Images = { new ImageData { Platforms = { new PlatformData { Dockerfile = "1.0/repo1/os/Dockerfile", OsType = "Linux", OsVersion = "focal", Architecture = "amd64", Digest = digest1, SimpleTags = new List <string> { "tag1" } }, new PlatformData() }, Manifest = new ManifestData { Created = manifestCreatedDate, Digest = "repo1@digest1", SharedTags = { "sharedtag1", "sharedtag2" } } } } }, new RepoData { Repo = "repo2", Images = { new ImageData { Platforms = { new PlatformData { Dockerfile = "1.0/repo2/os/Dockerfile", OsType = "Linux", OsVersion = "focal", Architecture = "amd64", Digest = digest2, SimpleTags = new List <string> { "tag2" } } }, Manifest = new ManifestData { Created = manifestCreatedDate, Digest = "repo2@digest2", SharedTags = { "sharedtag1", "sharedtag3" } } } } }, new RepoData { Repo = "repo3", Images = { new ImageData { Platforms = { new PlatformData { Dockerfile = "1.0/repo3/os/Dockerfile", OsType = "Linux", OsVersion = "focal", Architecture = "amd64", Digest = digest3, SimpleTags = new List <string> { "tag3" } } } } } } } }; string expectedOutput = JsonHelper.SerializeObject(expectedImageArtifactDetails); Assert.Equal(expectedOutput, actualOutput); }