Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Commit

Permalink
fix: Extractor/exclude product api from apis template (#856)
Browse files Browse the repository at this point in the history
* Remove api-products resources from apis template
* Add product api extraction tests
* Add product extractor tests for two cases. apiName null or non-empty

Co-authored-by: Farhad Alizada <[email protected]>
  • Loading branch information
f-alizada and Farhad Alizada authored Jan 9, 2023
1 parent 6f0a809 commit a056ef0
Show file tree
Hide file tree
Showing 18 changed files with 387 additions and 47 deletions.
7 changes: 3 additions & 4 deletions src/ArmTemplates/Commands/Executors/ExtractorExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -323,13 +323,12 @@ await FileWriter.SaveAsJsonAsync(
/// <returns>generated products template</returns>
public async Task<Template<ProductTemplateResources>> GenerateProductsTemplateAsync(
string singleApiName,
string baseFilesGenerationDirectory,
List<ProductApiTemplateResource> productApiResources)
string baseFilesGenerationDirectory)
{
this.logger.LogInformation("Started generation of products template...");

var productTemplate = await this.productExtractor.GenerateProductsTemplateAsync(
singleApiName, productApiResources, baseFilesGenerationDirectory, this.extractorParameters);
singleApiName, baseFilesGenerationDirectory, this.extractorParameters);

if (productTemplate?.HasResources() == true)
{
Expand Down Expand Up @@ -1164,7 +1163,7 @@ async Task GenerateTemplates(

var globalServicePolicyTemplate = await this.GeneratePolicyTemplateAsync(baseFilesGenerationDirectory);
var productApiTemplate = await this.GenerateProductApisTemplateAsync(singleApiName, multipleApiNames, baseFilesGenerationDirectory);
var productTemplate = await this.GenerateProductsTemplateAsync(singleApiName, baseFilesGenerationDirectory, apiTemplate.TypedResources.ApiProducts);
var productTemplate = await this.GenerateProductsTemplateAsync(singleApiName, baseFilesGenerationDirectory);
var apiVersionSetTemplate = await this.GenerateApiVersionSetTemplateAsync(singleApiName, baseFilesGenerationDirectory, apiTemplate.TypedResources.Apis);
var authorizationServerTemplate = await this.GenerateAuthorizationServerTemplateAsync(singleApiName, baseFilesGenerationDirectory, apiTemplate.TypedResources.Apis);
var tagTemplate = await this.GenerateTagTemplateAsync(singleApiName, apiTemplate.TypedResources, productTemplate.TypedResources, baseFilesGenerationDirectory);
Expand Down
6 changes: 0 additions & 6 deletions src/ArmTemplates/Extractor/EntityExtractors/APIExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,6 @@ public async Task<ApiTemplateResources> GetApiRelatedTemplateResourcesAsync(stri
apiTemplateResources.ApiPolicies.Add(apiPolicyResource);
}

var apiProducts = await this.productApisExtractor.GenerateSingleApiTemplateAsync(apiName, extractorParameters, addDependsOnParameter: true);
if (!apiProducts.IsNullOrEmpty())
{
apiTemplateResources.ApiProducts = apiProducts;
}

var apiTags = await this.tagExtractor.GenerateTagResourcesLinkedToApiAsync(apiName, extractorParameters);
if (!apiTags.IsNullOrEmpty())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,5 @@ Task<Template<ProductApiTemplateResources>> GenerateProductApisTemplateAsync(
string singleApiName,
List<string> multipleApiNames,
ExtractorParameters extractorParameters);

Task<List<ProductApiTemplateResource>> GenerateSingleApiTemplateAsync(
string singleApiName,
ExtractorParameters extractorParameters,
bool addDependsOnParameter = false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ public interface IProductExtractor
{
Task<Template<ProductTemplateResources>> GenerateProductsTemplateAsync(
string singleApiName,
List<ProductApiTemplateResource> productApiTemplateResources,
string baseFilesGenerationDirectory,
ExtractorParameters extractorParameters);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public Template<MasterTemplateResources> GenerateLinkedMasterTemplate(
// api dependsOn
var apiDependsOn = new List<string>();
var productApiDependsOn = new List<string>();
var productsDependsOn = new List<string>();
var apiTagDependsOn = new List<string>();
var globalPolicyDependsOn = new List<string>();

Expand All @@ -86,6 +87,7 @@ public Template<MasterTemplateResources> GenerateLinkedMasterTemplate(
const string NamedValuesTemplateName = "namedValuesTemplate";

dependsOnNamedValues = new string[] { $"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{NamedValuesTemplateName}')]" };
productsDependsOn.AddRange(dependsOnNamedValues);
globalPolicyDependsOn.AddRange(dependsOnNamedValues);
apiDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{NamedValuesTemplateName}')]");
var namedValuesUri = this.GenerateLinkedTemplateUri(fileNames.NamedValues, extractorParameters);
Expand Down Expand Up @@ -139,16 +141,27 @@ public Template<MasterTemplateResources> GenerateLinkedMasterTemplate(
masterResources.DeploymentResources.Add(apiVersionSetDeployment);
}

if (groupTemplateResources?.HasContent() == true)
{
this.logger.LogDebug("Adding groups to master template");
const string GroupsTemplate = "groupsTemplate";
productsDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{GroupsTemplate}')]");

var groupsUri = this.GenerateLinkedTemplateUri(fileNames.Groups, extractorParameters);
var groupsDeployment = CreateLinkedMasterTemplateResource(GroupsTemplate, groupsUri, Array.Empty<string>());

masterResources.DeploymentResources.Add(groupsDeployment);
}

if (productsTemplateResources?.HasContent() == true)
{
this.logger.LogDebug("Adding products to master template");
const string ProductsTemplate = "productsTemplate";

apiDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{ProductsTemplate}')]");
productApiDependsOn.Add($"[resourceId('{ResourceTypeConstants.ArmDeployments}', '{ProductsTemplate}')]");
var productsUri = this.GenerateLinkedTemplateUri(fileNames.Products, extractorParameters);

var productDeployment = CreateLinkedMasterTemplateResource(ProductsTemplate, productsUri, dependsOnNamedValues);
var productDeployment = CreateLinkedMasterTemplateResource(ProductsTemplate, productsUri, productsDependsOn.ToArray());

if (extractorParameters.PolicyXMLBaseUrl is not null)
{
Expand Down Expand Up @@ -269,17 +282,6 @@ public Template<MasterTemplateResources> GenerateLinkedMasterTemplate(
masterResources.DeploymentResources.Add(apiTagsDeployment);
}

if (groupTemplateResources?.HasContent() == true)
{
this.logger.LogDebug("Adding groups to master template");
const string GroupsTemplate = "groupsTemplate";

var groupsUri = this.GenerateLinkedTemplateUri(fileNames.Groups, extractorParameters);
var groupsDeployment = CreateLinkedMasterTemplateResource(GroupsTemplate, groupsUri, Array.Empty<string>());

masterResources.DeploymentResources.Add(groupsDeployment);
}

if (identityProviderTemplateResources?.HasContent() == true)
{
this.logger.LogDebug("Adding identity providers to master template");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ async Task<List<ProductApiTemplateResource>> GenerateProductApiTemplateResources
}

productApiResources.Add(productApi);

}
}
catch (Exception ex)
Expand Down
13 changes: 9 additions & 4 deletions src/ArmTemplates/Extractor/EntityExtractors/ProductExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ public ProductExtractor(

public async Task<Template<ProductTemplateResources>> GenerateProductsTemplateAsync(
string singleApiName,
List<ProductApiTemplateResource> productApiTemplateResources,
string baseFilesGenerationDirectory,
ExtractorParameters extractorParameters)
{
Expand All @@ -61,15 +60,21 @@ public async Task<Template<ProductTemplateResources>> GenerateProductsTemplateAs
.AddPolicyProperties(extractorParameters)
.Build<ProductTemplateResources>();

var products = await this.productsClient.GetAllAsync(extractorParameters);
var allProducts = await this.productsClient.GetAllAsync(extractorParameters);

foreach (var productTemplateResource in products)
List<ProductApiTemplateResource> apiProducts = new List<ProductApiTemplateResource>();
if (!singleApiName.IsNullOrEmpty())
{
apiProducts = await this.productsClient.GetAllLinkedToApiAsync(singleApiName, extractorParameters);
}

foreach (var productTemplateResource in allProducts)
{
productTemplateResource.Name = $"[concat(parameters('{ParameterNames.ApimServiceName}'), '/{productTemplateResource.NewName}')]";
productTemplateResource.ApiVersion = GlobalConstants.ApiVersion;

// only extract the product if this is a full extraction, or in the case of a single api, if it is found in products associated with the api
if (singleApiName == null || productApiTemplateResources.Any(p => p.Name.Contains($"/{productTemplateResource.NewName}/")))
if (singleApiName == null || apiProducts.Any(p => p.Name.Equals(productTemplateResource.NewName)))
{
this.logger.LogDebug("'{0}' product found", productTemplateResource.OriginalName);
productsTemplate.TypedResources.Products.Add(productTemplateResource);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public async Task GenerateAPIVersionSetTemplates_GeneratesApiTemplates()

var mockedProductExtractor = new Mock<IProductExtractor>(MockBehavior.Strict);
mockedProductExtractor
.Setup(x => x.GenerateProductsTemplateAsync(It.IsAny<string>(), It.IsAny<List<ProductApiTemplateResource>>(), It.IsAny<string>(), It.IsAny<ExtractorParameters>()))
.Setup(x => x.GenerateProductsTemplateAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<ExtractorParameters>()))
.ReturnsAsync(new Template<ProductTemplateResources>()
{
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public async Task GenerateApiTemplates_ProperlyLaysTheInformation()
apiTemplate.Parameters.Should().ContainKey(ParameterNames.ApiLoggerId);
apiTemplate.Parameters.Should().ContainKey(ParameterNames.PolicyXMLBaseUrl);
apiTemplate.Parameters.Should().ContainKey(ParameterNames.PolicyXMLSasToken);
apiTemplate.Resources.Count().Should().Be(33);
apiTemplate.Resources.Count().Should().Be(30);

// apis
apiTemplate.TypedResources.Apis.Count().Should().Be(3);
Expand All @@ -133,11 +133,6 @@ public async Task GenerateApiTemplates_ProperlyLaysTheInformation()
apiTemplate.TypedResources.Tags.Count().Should().Be(6);
apiTemplate.TypedResources.Tags.All(x => x.Type == ResourceTypeConstants.APITag).Should().BeTrue();

// api products
apiTemplate.TypedResources.ApiProducts.Count().Should().Be(3);
apiTemplate.TypedResources.ApiProducts.All(x => x.Type == ResourceTypeConstants.ProductApi).Should().BeTrue();
apiTemplate.TypedResources.ApiProducts.All(x => x.Properties is not null).Should().BeTrue();

// api policies
apiTemplate.TypedResources.ApiPolicies.Count().Should().Be(3);
apiTemplate.TypedResources.ApiPolicies.All(x => x.Properties is not null).Should().BeTrue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Commands.Executors;
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.API.Utils;
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.Constants;
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common.Templates.Builders;
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Extractor.EntityExtractors;
Expand Down Expand Up @@ -77,5 +78,115 @@ public async Task GenerateProductApisTemplates_ProperlyLaysTheInformation()
productApi.DependsOn.Should().BeNullOrEmpty();
}
}

[Fact]
public async Task GenerateProductApisTemplates_GeneratesAllRelatedProductApis_GivenApiNameParameterProvided()
{
// arrange
var apiName = "api-name";
var currentTestDirectory = Path.Combine(this.OutputDirectory, nameof(GenerateProductApisTemplates_GeneratesAllRelatedProductApis_GivenApiNameParameterProvided));

var extractorConfig = this.GetDefaultExtractorConsoleAppConfiguration(apiName: apiName);
var extractorParameters = new ExtractorParameters(extractorConfig);

var getSingleApiResponseFileLocation = Path.Combine(MockClientUtils.ApiClientJsonResponsesPath, "ApiManagementGetApiContract_success_response.json");
var getRelatedProductsResponseFileLocation = Path.Combine(MockClientUtils.ApiClientJsonResponsesPath, "ApiManagementListApiProducts_success_response.json");
var mockedApisClient = await MockApisClient.GetMockedHttpApiClient(
new MockClientConfiguration(responseFileLocation: getSingleApiResponseFileLocation, urlPath: $"apis/{apiName}?api-version={GlobalConstants.ApiVersion}"));
var mockedApiClientUtils = new ApiClientUtils(mockedApisClient, this.GetTestLogger<ApiClientUtils>());

var mockedServiceApisProductsApiClient = await MockProductsClient.GetMockedHttpProductClient(
new MockClientConfiguration(responseFileLocation: getRelatedProductsResponseFileLocation)
);

var productApisExtractor = new ProductApisExtractor(
this.GetTestLogger<ProductApisExtractor>(),
mockedServiceApisProductsApiClient,
mockedApisClient,
new TemplateBuilder());

var extractorExecutor = ExtractorExecutor.BuildExtractorExecutor(
this.GetTestLogger<ExtractorExecutor>(),
productApisExtractor: productApisExtractor);
extractorExecutor.SetExtractorParameters(extractorParameters);

// act
var productApisTemplate = await extractorExecutor.GenerateProductApisTemplateAsync(
singleApiName: apiName,
multipleApiNames: It.IsAny<List<string>>(),
currentTestDirectory);

// assert
File.Exists(Path.Combine(currentTestDirectory, extractorParameters.FileNames.ProductAPIs)).Should().BeTrue();

productApisTemplate.Parameters.Should().ContainKey(ParameterNames.ApimServiceName);
productApisTemplate.TypedResources.ProductApis.Count().Should().Be(1);
productApisTemplate.Resources.Count().Should().Be(1);

foreach (var productApi in productApisTemplate.TypedResources.ProductApis)
{
productApi.ApiVersion.Should().Be(GlobalConstants.ApiVersion);
productApi.Name.Should().NotBeNullOrEmpty();
productApi.Name.Contains($"/{apiName}").Should().BeTrue();
productApi.Type.Should().Be(ResourceTypeConstants.ProductApi);
productApi.Properties.DisplayName.Should().NotBeNullOrEmpty();
productApi.Properties.Description.Should().NotBeNullOrEmpty();
productApi.DependsOn.Should().BeNullOrEmpty();
}
}

[Fact]
public async Task GenerateProductApisTemplates_GeneratesAllRelatedProductApis_GivenAllApisAreExtracted()
{
// arrange
var currentTestDirectory = Path.Combine(this.OutputDirectory, nameof(GenerateProductApisTemplates_GeneratesAllRelatedProductApis_GivenAllApisAreExtracted));

var extractorConfig = this.GetDefaultExtractorConsoleAppConfiguration(apiName: string.Empty);
var extractorParameters = new ExtractorParameters(extractorConfig);

var getAllApisResponseFileLocation = Path.Combine(MockClientUtils.ApiClientJsonResponsesPath, "ApiManagementListApis_success_response.json");
var getRelatedProductsResponseFileLocation = Path.Combine(MockClientUtils.ApiClientJsonResponsesPath, "ApiManagementListApiProducts_success_response.json");
var mockedApisClient = await MockApisClient.GetMockedHttpApiClient(
new MockClientConfiguration(responseFileLocation: getAllApisResponseFileLocation));
var mockedApiClientUtils = new ApiClientUtils(mockedApisClient, this.GetTestLogger<ApiClientUtils>());

var mockedServiceApisProductsApiClient = await MockProductsClient.GetMockedHttpProductClient(
new MockClientConfiguration(responseFileLocation: getRelatedProductsResponseFileLocation)
);

var productApisExtractor = new ProductApisExtractor(
this.GetTestLogger<ProductApisExtractor>(),
mockedServiceApisProductsApiClient,
mockedApisClient,
new TemplateBuilder());

var extractorExecutor = ExtractorExecutor.BuildExtractorExecutor(
this.GetTestLogger<ExtractorExecutor>(),
productApisExtractor: productApisExtractor);
extractorExecutor.SetExtractorParameters(extractorParameters);

// act
var productApisTemplate = await extractorExecutor.GenerateProductApisTemplateAsync(
singleApiName: null,
multipleApiNames: It.IsAny<List<string>>(),
currentTestDirectory);

// assert
File.Exists(Path.Combine(currentTestDirectory, extractorParameters.FileNames.ProductAPIs)).Should().BeTrue();

productApisTemplate.Parameters.Should().ContainKey(ParameterNames.ApimServiceName);
productApisTemplate.TypedResources.ProductApis.Count().Should().Be(4);
productApisTemplate.Resources.Count().Should().Be(4);

foreach (var productApi in productApisTemplate.TypedResources.ProductApis)
{
productApi.ApiVersion.Should().Be(GlobalConstants.ApiVersion);
productApi.Name.Should().NotBeNullOrEmpty();
productApi.Type.Should().Be(ResourceTypeConstants.ProductApi);
productApi.Properties.DisplayName.Should().NotBeNullOrEmpty();
productApi.Properties.Description.Should().NotBeNullOrEmpty();
productApi.DependsOn.Should().BeNullOrEmpty();
}
}
}
}
Loading

0 comments on commit a056ef0

Please sign in to comment.