Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Execute app service tests against static app service plans #1362

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
152 changes: 59 additions & 93 deletions source/Calamari.AzureAppService.Tests/AppServiceBehaviourFixture.cs

Large diffs are not rendered by default.

133 changes: 71 additions & 62 deletions source/Calamari.AzureAppService.Tests/AppServiceIntegrationTest.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Azure;
using Azure.Core;
using Azure.ResourceManager;
using Azure.ResourceManager.AppService;
using Azure.ResourceManager.AppService.Models;
using Azure.ResourceManager.Resources;
using Calamari.Azure;
using Calamari.AzureAppService.Azure;
Expand All @@ -30,22 +29,23 @@ public abstract class AppServiceIntegrationTest
protected string ClientSecret { get; private set; }
protected string TenantId { get; private set; }
protected string SubscriptionId { get; private set; }
protected string ResourceGroupName { get; private set; }
protected string ResourceGroupLocation { get; private set; }

protected string greeting = "Calamari";
protected string Greeting = "Calamari";

protected ArmClient ArmClient { get; private set; }

protected SubscriptionResource SubscriptionResource { get; private set; }
protected ResourceGroupResource ResourceGroupResource { get; private set; }
protected WebSiteResource WebSiteResource { get; private protected set; }
protected string ResourceGroupName => ResourceGroupResource.Data.Name;
protected AppServicePlanResource LinuxAppServicePlanResource { get; private set; }

private readonly HttpClient client = new HttpClient();
protected AppServicePlanResource WindowsAppServicePlanResource { get; private set; }
protected AppServicePlanResource WindowsContainerAppServicePlanResource { get; private set; }
protected WebSiteResource WebSiteResource { get; private protected set; }

protected virtual string DefaultResourceGroupLocation => RandomAzureRegion.GetRandomRegionWithExclusions();
readonly HttpClient client = new HttpClient();

static readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();
readonly CancellationToken cancellationToken = CancellationTokenSource.Token;
protected readonly CancellationToken CancellationToken = CancellationTokenSource.Token;
SubscriptionResource subscriptionResource;

[OneTimeSetUp]
public async Task Setup()
Expand All @@ -55,15 +55,10 @@ public async Task Setup()
var activeDirectoryEndpointBaseUri =
Environment.GetEnvironmentVariable(AccountVariables.ActiveDirectoryEndPoint) ?? DefaultVariables.ActiveDirectoryEndpoint;

ResourceGroupName = $"{DateTime.UtcNow:yyyyMMdd}-{Guid.NewGuid():N}";

ClientId = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionClientId, cancellationToken);
ClientSecret = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionPassword, cancellationToken);
TenantId = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionTenantId, cancellationToken);
SubscriptionId = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionId, cancellationToken);
ResourceGroupLocation = Environment.GetEnvironmentVariable("AZURE_NEW_RESOURCE_REGION") ?? DefaultResourceGroupLocation;

TestContext.Progress.WriteLine($"Resource group location: {ResourceGroupLocation}");
ClientId = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionClientId, CancellationToken);
ClientSecret = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionPassword, CancellationToken);
TenantId = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionTenantId, CancellationToken);
SubscriptionId = await ExternalVariables.Get(ExternalVariable.AzureSubscriptionId, CancellationToken);

var servicePrincipalAccount = new AzureServicePrincipalAccount(SubscriptionId,
ClientId,
Expand All @@ -83,12 +78,28 @@ public async Task Setup()
});

//create the resource group
SubscriptionResource = ArmClient.GetSubscriptionResource(SubscriptionResource.CreateResourceIdentifier(SubscriptionId));
var response = await SubscriptionResource
subscriptionResource = ArmClient.GetSubscriptionResource(SubscriptionResource.CreateResourceIdentifier(SubscriptionId));
ResourceGroupResource staticResourceGroupResource = await subscriptionResource.GetResourceGroupAsync("calamari-testing-static-rg", CancellationToken);

WindowsAppServicePlanResource = await staticResourceGroupResource.GetAppServicePlanAsync("calamari-testing-static-win-plan", CancellationToken);
LinuxAppServicePlanResource = await staticResourceGroupResource.GetAppServicePlanAsync("calamari-testing-static-linux-plan", CancellationToken);
WindowsContainerAppServicePlanResource = await staticResourceGroupResource.GetAppServicePlanAsync("calamari-testing-static-container-win-plan", CancellationToken);
LinuxAppServicePlanResource = await staticResourceGroupResource.GetAppServicePlanAsync("calamari-testing-static-linux-plan", CancellationToken);
}

[SetUp]
public virtual async Task SetUp()
{
var sw = Stopwatch.StartNew();
var name = $"{DateTime.UtcNow:yyyyMMdd}-{Guid.NewGuid():N}";

TestContext.WriteLine($"Creating resource group '{name}'");

var response = await subscriptionResource
.GetResourceGroups()
.CreateOrUpdateAsync(WaitUntil.Completed,
ResourceGroupName,
new ResourceGroupData(new AzureLocation(ResourceGroupLocation))
name,
new ResourceGroupData(AzureLocation.AustraliaEast)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be AustraliaEast as the static resource groups are in AustraliaEast

{
Tags =
{
Expand All @@ -97,27 +108,33 @@ public async Task Setup()
// We keep them for 14 days just in case we need to do debugging/investigation
["LifetimeInDays"] = "14"
}
});
},
CancellationToken);

ResourceGroupResource = response.Value;

await ConfigureTestResources(ResourceGroupResource);
sw.Stop();
TestContext.WriteLine($"Created resource group '{name}' in {sw.Elapsed:g}");
}

protected abstract Task ConfigureTestResources(ResourceGroupResource resourceGroup);

[OneTimeTearDown]
public virtual async Task Cleanup()
[TearDown]
public virtual async Task TearDown()
{
await ArmClient.GetResourceGroupResource(ResourceGroupResource.CreateResourceIdentifier(SubscriptionId, ResourceGroupName))
.DeleteAsync(WaitUntil.Started);
TestContext.WriteLine($"Deleting web app '{WebSiteResource.Data.Name}' (with no waiting)");

//we explicitly delete the website so we can set deleteEmptyServerFarm to be false (otherwise cleaning up the resource group _sometimes_ deletes the app service plan)
await RetryPolicies.TestsTransientArmOperationsErrorsPolicy.ExecuteAsync(async ct => await WebSiteResource.DeleteAsync(WaitUntil.Started, deleteEmptyServerFarm: false, cancellationToken: ct), CancellationToken);

TestContext.WriteLine($"Deleting resource group '{ResourceGroupResource.Data.Name}' (with no waiting)");
//delete the rest of the resources
await RetryPolicies.TestsTransientArmOperationsErrorsPolicy.ExecuteAsync(async ct => await ResourceGroupResource.DeleteAsync(WaitUntil.Started, cancellationToken: ct), CancellationToken);
}

protected async Task AssertContent(string hostName, string actualText, string rootPath = null)
{
var response = await RetryPolicies.TestsTransientHttpErrorsPolicy.ExecuteAsync(async context =>
var response = await RetryPolicies.TestsTransientHttpErrorsPolicy.ExecuteAsync(async (context, ct) =>
{
var r = await client.GetAsync($"https://{hostName}/{rootPath}");
var r = await client.GetAsync($"https://{hostName}/{rootPath}", CancellationToken);
if (!r.IsSuccessStatusCode)
{
var messageContent = await r.Content.ReadAsStringAsync();
Expand All @@ -127,7 +144,8 @@ protected async Task AssertContent(string hostName, string actualText, string ro
r.EnsureSuccessStatusCode();
return r;
},
contextData: new Dictionary<string, object>());
contextData: new Dictionary<string, object>(),
cancellationToken: CancellationToken);

var result = await response.Content.ReadAsStringAsync();
result.Should().Contain(actualText);
Expand Down Expand Up @@ -167,34 +185,25 @@ protected void AddAzureVariables(VariableDictionary variables)
variables.Add(SpecialVariables.Action.Azure.WebAppName, WebSiteResource.Data.Name);
}

protected async Task<(AppServicePlanResource, WebSiteResource)> CreateAppServicePlanAndWebApp(
ResourceGroupResource resourceGroup,
AppServicePlanData appServicePlanData = null,
WebSiteData webSiteData = null)
protected async Task<WebSiteResource> CreateWebApp(AppServicePlanResource appServicePlanResource, WebSiteData webSiteData = null)
{
appServicePlanData ??= new AppServicePlanData(resourceGroup.Data.Location)
{
Sku = new AppServiceSkuDescription
{
Name = "P1V3",
Tier = "PremiumV3"
}
};

var servicePlanResponse = await resourceGroup.GetAppServicePlans()
.CreateOrUpdateAsync(WaitUntil.Completed,
resourceGroup.Data.Name,
appServicePlanData);

webSiteData ??= new WebSiteData(resourceGroup.Data.Location);
webSiteData.AppServicePlanId = servicePlanResponse.Value.Id;

var webSiteResponse = await resourceGroup.GetWebSites()
.CreateOrUpdateAsync(WaitUntil.Completed,
resourceGroup.Data.Name,
webSiteData);

return (servicePlanResponse.Value, webSiteResponse.Value);
var sw = Stopwatch.StartNew();

webSiteData ??= new WebSiteData(ResourceGroupResource.Data.Location);
webSiteData.AppServicePlanId = appServicePlanResource.Id;

TestContext.WriteLine($"Creating web app '{ResourceGroupName}'");
var webSiteResponse = await ResourceGroupResource.GetWebSites()
.CreateOrUpdateAsync(WaitUntil.Completed,
ResourceGroupName,
webSiteData,
CancellationToken);


sw.Stop();
TestContext.WriteLine($"Created web app '{ResourceGroupName}' in {sw.Elapsed:g}");

return webSiteResponse.Value;
}

protected (string json, IEnumerable<AppSetting> setting) BuildAppSettingsJson(IEnumerable<(string name, string value, bool isSlotSetting)> settings)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ public class AppServiceSettingsBehaviorFixture : AppServiceIntegrationTest
AppServiceConfigurationDictionary existingSettings;
ConnectionStringDictionary existingConnectionStrings;

protected override async Task ConfigureTestResources(ResourceGroupResource resourceGroup)
public override async Task SetUp()
{
var (_, webSiteResource) = await CreateAppServicePlanAndWebApp(resourceGroup);
WebSiteResource = webSiteResource;

await base.SetUp();

WebSiteResource = await CreateWebApp(WindowsAppServicePlanResource);

existingSettings = new AppServiceConfigurationDictionary
{
Properties =
Expand Down
Loading