Skip to content

Commit

Permalink
Add ACR delete tag methods (Azure#19680)
Browse files Browse the repository at this point in the history
- Add delete tag methods to ContainerRepositoryClient
- Use Track 1 mgmt plane ACR client library to import images for delete tests
- Refactor client tests so that tests setting read/write attributes to false are marked NonParallelizable

Addresses tag delete in Azure#19547
  • Loading branch information
annelo-msft authored and Mohit-Chakraborty committed Mar 23, 2021
1 parent b0f727f commit f2461aa
Show file tree
Hide file tree
Showing 81 changed files with 589 additions and 17,982 deletions.
1 change: 1 addition & 0 deletions eng/Packages.Data.props
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@
<PackageReference Update="Microsoft.Azure.Graph.RBAC" Version="2.2.2-preview" />
<PackageReference Update="Microsoft.Azure.KeyVault.Core" Version="3.0.3" />
<PackageReference Update="Microsoft.Azure.Management.ContainerRegistry" Version="2.0.0" />
<PackageReference Update="Microsoft.Azure.Management.ContainerRegistry.Fluent" Version="1.37.1" />
<PackageReference Update="Microsoft.Azure.Management.EventGrid" Version="4.0.1-preview" />
<PackageReference Update="Microsoft.Azure.Management.EventHub" Version="2.5.0" />
<PackageReference Update="Microsoft.Azure.Management.HDInsight" Version="4.1.0-preview" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ protected ContainerRepositoryClient() { }
public ContainerRepositoryClient(System.Uri endpoint, string repository, string username, string password) { }
public ContainerRepositoryClient(System.Uri endpoint, string repository, string username, string password, Azure.Containers.ContainerRegistry.ContainerRegistryClientOptions options) { }
public virtual System.Uri Endpoint { get { throw null; } }
public virtual Azure.Response DeleteTag(string tag, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public virtual System.Threading.Tasks.Task<Azure.Response> DeleteTagAsync(string tag, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public virtual Azure.Response<Azure.Containers.ContainerRegistry.RepositoryProperties> GetProperties(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Containers.ContainerRegistry.RepositoryProperties>> GetPropertiesAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public virtual Azure.Response<Azure.Containers.ContainerRegistry.TagProperties> GetTagProperties(string tag, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Specialized;
using System.Threading;
using System.Web;

using Azure.Core;
using Azure.Core.Pipeline;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,5 +205,41 @@ public virtual Response SetTagProperties(string tag, ContentProperties value, Ca
throw;
}
}

/// <summary> Delete tag. </summary>
/// <param name="tag"> Tag name. </param>
/// <param name="cancellationToken"> The cancellation token to use. </param>
public virtual async Task<Response> DeleteTagAsync(string tag, CancellationToken cancellationToken = default)
{
using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(ContainerRepositoryClient)}.{nameof(DeleteTag)}");
scope.Start();
try
{
return await _restClient.DeleteTagAsync(_repository, tag, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
scope.Failed(e);
throw;
}
}

/// <summary> Delete tag. </summary>
/// <param name="tag"> Tag name. </param>
/// <param name="cancellationToken"> The cancellation token to use. </param>
public virtual Response DeleteTag(string tag, CancellationToken cancellationToken = default)
{
using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(ContainerRepositoryClient)}.{nameof(DeleteTag)}");
scope.Start();
try
{
return _restClient.DeleteTag(_repository, tag, cancellationToken);
}
catch (Exception e)
{
scope.Failed(e);
throw;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
<ItemGroup>
<PackageReference Include="NUnit" />
<PackageReference Include="NUnit3TestAdapter" />
<PackageReference Include="Microsoft.Azure.Management.ContainerRegistry" VersionOverride="4.0.0" />
<PackageReference Include="Microsoft.Azure.Management.ContainerRegistry.Fluent" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Moq" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@ public class ContainerRegistryTestEnvironment : TestEnvironment
public string Endpoint => GetRecordedVariable("CONTAINERREGISTRY_ENDPOINT");
public string UserName => GetRecordedVariable("CONTAINERREGISTRY_USERNAME", options => options.IsSecret());
public string Password => GetRecordedVariable("CONTAINERREGISTRY_PASSWORD", options => options.IsSecret());
public string Registry => GetRecordedVariable("CONTAINERREGISTRY_REGISTRY_NAME");

public bool IsTestModeLive => this.Mode != RecordedTestMode.Playback;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,147 +2,185 @@
// Licensed under the MIT License.

using System;
using System.Threading.Tasks;
using System.Collections.Generic;

using Azure.Core.TestFramework;

using Microsoft.Azure.Management.ContainerRegistry;
using Microsoft.Azure.Management.ContainerRegistry.Models;
using Microsoft.Azure.Management.ResourceManager.Fluent;
using Microsoft.Azure.Management.ResourceManager.Fluent.Authentication;
using NUnit.Framework;
using Task = System.Threading.Tasks.Task;

namespace Azure.Containers.ContainerRegistry.Tests
{
public class ContainerRepositoryClientLiveTests : RecordedTestBase<ContainerRegistryTestEnvironment>
{
private readonly string _repositoryName = "library/hello-world";
private readonly string _tagName = "latest";
private ContainerRepositoryClient _client;

public ContainerRepositoryClientLiveTests(bool isAsync) : base(isAsync)
{
}

[SetUp]
protected async Task CreateClient()
protected ContainerRepositoryClient CreateClient()
{
_client = InstrumentClient(new ContainerRepositoryClient(
return InstrumentClient(new ContainerRepositoryClient(
new Uri(TestEnvironment.Endpoint),
_repositoryName,
TestEnvironment.UserName,
TestEnvironment.Password,
InstrumentClientOptions(new ContainerRegistryClientOptions())
));

await InitializeRepositoryProperties();
await InitializeTagProperties();
}

[OneTimeTearDown]
public async Task TearDown()
{
await InitializeRepositoryProperties();
await InitializeTagProperties();
}

public async Task InitializeRepositoryProperties()
public async Task ImportImage(string tag)
{
await _client.SetPropertiesAsync(
new ContentProperties()
if (TestEnvironment.IsTestModeLive)
{
var credential = new AzureCredentials(
new ServicePrincipalLoginInformation
{
ClientId = TestEnvironment.ClientId,
ClientSecret = TestEnvironment.ClientSecret,
},
TestEnvironment.TenantId,
AzureEnvironment.AzureGlobalCloud);

var _registryClient = new ContainerRegistryManagementClient(credential.WithDefaultSubscription(TestEnvironment.SubscriptionId));
_registryClient.SubscriptionId = TestEnvironment.SubscriptionId;

var importSource = new ImportSource
{
CanList = true,
CanRead = true,
CanWrite = true,
CanDelete = true
});

RepositoryProperties properties = await _client.GetPropertiesAsync();

Assert.IsTrue(properties.WriteableProperties.CanList);
Assert.IsTrue(properties.WriteableProperties.CanRead);
Assert.IsTrue(properties.WriteableProperties.CanWrite);
Assert.IsTrue(properties.WriteableProperties.CanDelete);
}

public async Task InitializeTagProperties()
{
await _client.SetTagPropertiesAsync(
_tagName,
new ContentProperties()
{
CanList = true,
CanRead = true,
CanWrite = true,
CanDelete = true
});

RepositoryProperties properties = await _client.GetPropertiesAsync();

Assert.IsTrue(properties.WriteableProperties.CanList);
Assert.IsTrue(properties.WriteableProperties.CanRead);
Assert.IsTrue(properties.WriteableProperties.CanWrite);
Assert.IsTrue(properties.WriteableProperties.CanDelete);
SourceImage = "library/hello-world",
RegistryUri = "registry.hub.docker.com"
};

await _registryClient.Registries.ImportImageAsync(
resourceGroupName: TestEnvironment.ResourceGroup,
registryName: TestEnvironment.Registry,
parameters:
new ImportImageParameters
{
Mode = ImportMode.Force,
Source = importSource,
TargetTags = new List<string>()
{
$"library/hello-world:{tag}"
}
});
}
}

[RecordedTest]
public async Task CanGetRepositoryProperties()
{
RepositoryProperties properties = await _client.GetPropertiesAsync();
// Arrange
ContainerRepositoryClient client = CreateClient();

// Act
RepositoryProperties properties = await client.GetPropertiesAsync();

// Assert
Assert.AreEqual(_repositoryName, properties.Name);
Assert.AreEqual(new Uri(TestEnvironment.Endpoint).Host, properties.Registry);
}

[RecordedTest, NonParallelizable]
public async Task CanSetRepositoryProperties([Values(true, false)] bool canList,
[Values(true, false)] bool canRead,
[Values(true, false)] bool canWrite,
[Values(true, false)] bool canDelete)
public async Task CanSetRepositoryProperties()
{
await _client.SetPropertiesAsync(
// Arrange
ContainerRepositoryClient client = CreateClient();
RepositoryProperties repositoryProperties = await client.GetPropertiesAsync();
ContentProperties originalContentProperties = repositoryProperties.WriteableProperties;

// Act
await client.SetPropertiesAsync(
new ContentProperties()
{
CanList = canList,
CanRead = canRead,
CanWrite = canWrite,
CanDelete = canDelete
CanList = false,
CanRead = false,
CanWrite = false,
CanDelete = false,
});

RepositoryProperties properties = await _client.GetPropertiesAsync();
// Assert
RepositoryProperties properties = await client.GetPropertiesAsync();

Assert.AreEqual(canList, properties.WriteableProperties.CanList);
Assert.AreEqual(canRead, properties.WriteableProperties.CanRead);
Assert.AreEqual(canWrite, properties.WriteableProperties.CanWrite);
Assert.AreEqual(canDelete, properties.WriteableProperties.CanDelete);
Assert.IsFalse(properties.WriteableProperties.CanList);
Assert.IsFalse(properties.WriteableProperties.CanRead);
Assert.IsFalse(properties.WriteableProperties.CanWrite);
Assert.IsFalse(properties.WriteableProperties.CanDelete);

// Cleanup
await client.SetPropertiesAsync(originalContentProperties);
}

[RecordedTest]
public async Task CanGetTagProperties()
{
TagProperties properties = await _client.GetTagPropertiesAsync(_tagName);
// Arrange
ContainerRepositoryClient client = CreateClient();
string tag = "latest";

// Act
TagProperties properties = await client.GetTagPropertiesAsync(tag);

Assert.AreEqual(_tagName, properties.Name);
// Assert
Assert.AreEqual(tag, properties.Name);
Assert.AreEqual(_repositoryName, properties.Repository);
Assert.AreEqual(new Uri(TestEnvironment.Endpoint).Host, properties.Registry);
}

[RecordedTest, NonParallelizable]
public async Task CanSetTagProperties([Values(true, false)] bool canList,
[Values(true, false)] bool canRead,
[Values(true, false)] bool canWrite,
[Values(true, false)] bool canDelete)
public async Task CanSetTagProperties()
{
await _client.SetTagPropertiesAsync(
_tagName,
// Arrange
ContainerRepositoryClient client = CreateClient();
string tag = "latest";
TagProperties tagProperties = await client.GetTagPropertiesAsync(tag);
ContentProperties originalContentProperties = tagProperties.ModifiableProperties;

// Act
await client.SetTagPropertiesAsync(
tag,
new ContentProperties()
{
CanList = canList,
CanRead = canRead,
CanWrite = canWrite,
CanDelete = canDelete
CanList = false,
CanRead = false,
CanWrite = false,
CanDelete = false
});

TagProperties properties = await _client.GetTagPropertiesAsync(_tagName);
// Assert
TagProperties properties = await client.GetTagPropertiesAsync(tag);

Assert.IsFalse(properties.ModifiableProperties.CanList);
Assert.IsFalse(properties.ModifiableProperties.CanRead);
Assert.IsFalse(properties.ModifiableProperties.CanWrite);
Assert.IsFalse(properties.ModifiableProperties.CanDelete);

// Cleanup
await client.SetTagPropertiesAsync(tag, originalContentProperties);
}

[RecordedTest, NonParallelizable]
public async Task CanDeleteTag()
{
// Arrange
ContainerRepositoryClient client = CreateClient();
string tag = "test-delete";
await ImportImage(tag);

// Act
await client.DeleteTagAsync(tag);

// Assert

// The delete takes some time, so if we call GetTagProperties() without a delay, we get a 200 response.
await Task.Delay(5000);

Assert.AreEqual(canList, properties.ModifiableProperties.CanList);
Assert.AreEqual(canRead, properties.ModifiableProperties.CanRead);
Assert.AreEqual(canWrite, properties.ModifiableProperties.CanWrite);
Assert.AreEqual(canDelete, properties.ModifiableProperties.CanDelete);
Assert.ThrowsAsync<RequestFailedException>(async () => { await client.GetTagPropertiesAsync(tag); });
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit f2461aa

Please sign in to comment.