// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Threading.Tasks; using Microsoft.Azure.Management.AppService.Fluent; using Microsoft.Azure.Management.Fluent; using Microsoft.Azure.Management.ResourceManager.Fluent; using Microsoft.Azure.Management.ResourceManager.Fluent.Core; using Microsoft.Azure.Management.ResourceManager.Fluent.Models; using Microsoft.Azure.Management.Storage.Fluent; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Testing; using Microsoft.Rest; using Newtonsoft.Json.Linq; namespace Microsoft.AspNetCore.AzureAppServices.FunctionalTests { public class AzureFixture : IDisposable { public string Timestamp { get; set; } public AzureFixture() { TestLog = AssemblyTestLog.ForAssembly(typeof(AzureFixture).Assembly); // TODO: Temporary to see if it's useful and worth exposing var globalLoggerFactory = (ILoggerFactory) TestLog.GetType().GetField("_globalLoggerFactory", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(TestLog); var logger = globalLoggerFactory.CreateLogger(); ServiceClientTracing.IsEnabled = true; ServiceClientTracing.AddTracingInterceptor(new LoggingInterceptor(globalLoggerFactory.CreateLogger(nameof(ServiceClientTracing)))); var clientId = GetRequiredEnvironmentVariable("AZURE_AUTH_CLIENT_ID"); var clientSecret = GetRequiredEnvironmentVariable("AZURE_AUTH_CLIENT_SECRET"); var tenant = GetRequiredEnvironmentVariable("AZURE_AUTH_TENANT"); var credentials = SdkContext.AzureCredentialsFactory.FromServicePrincipal(clientId, clientSecret, tenant, AzureEnvironment.AzureGlobalCloud); Azure = Microsoft.Azure.Management.Fluent.Azure.Configure() .WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic) .Authenticate(credentials) .WithDefaultSubscription(); Timestamp = DateTime.Now.ToString("yyyyMMddhhmmss"); var testRunName = GetTimestampedName("FunctionalTests"); logger.LogInformation("Creating resource group {TestRunName}", testRunName); ResourceGroup = Azure.ResourceGroups .Define(testRunName) .WithRegion(Region.USWest2) .Create(); var servicePlanName = GetTimestampedName("TestPlan"); logger.LogInformation("Creating service plan {servicePlanName}", testRunName); Plan = Azure.AppServices.AppServicePlans.Define(servicePlanName) .WithRegion(Region.USWest2) .WithExistingResourceGroup(ResourceGroup) .WithFreePricingTier() .Create(); } public static string GetRequiredEnvironmentVariable(string name) { var authFile = Environment.GetEnvironmentVariable(name); if (string.IsNullOrEmpty(authFile)) { throw new InvalidOperationException($"{name} environment variable has to be set to run these tests."); } return authFile; } public IAppServicePlan Plan { get; set; } public IStorageAccount DeploymentStorageAccount { get; set; } public AssemblyTestLog TestLog { get; set; } public bool DeleteResourceGroup { get; set; } = true; public IResourceGroup ResourceGroup { get; set; } public IAzure Azure { get; set; } public string GetTimestampedName(string name) { return name + Timestamp; } public async Task Deploy(string template, IDictionary additionalArguments = null, [CallerMemberName] string baseName = null) { var siteName = GetTimestampedName(baseName); var parameters = new Dictionary { {"siteName", siteName}, {"hostingPlanName", Plan.Name}, {"resourceGroupName", ResourceGroup.Name}, }; foreach (var pair in additionalArguments ?? Enumerable.Empty>()) { parameters[pair.Key] = pair.Value; } var readAllText = File.ReadAllText(template); var deployment = await Azure.Deployments.Define(GetTimestampedName("Deployment")) .WithExistingResourceGroup(ResourceGroup) .WithTemplate(readAllText) .WithParameters(ToParametersObject(parameters)) .WithMode(DeploymentMode.Incremental) .CreateAsync(); deployment = await deployment.RefreshAsync(); var outputs = (JObject)deployment.Outputs; var siteIdOutput = outputs["siteId"]; if (siteIdOutput == null) { throw new InvalidOperationException("Deployment was expected to have 'siteId' output parameter"); } var siteId = siteIdOutput["value"].Value(); return await Azure.AppServices.WebApps.GetByIdAsync(siteId); } private JObject ToParametersObject(Dictionary parameters) { return new JObject( parameters.Select(parameter => new JProperty( parameter.Key, new JObject( new JProperty("value", parameter.Value))))); } public void Dispose() { TestLog.Dispose(); if (DeleteResourceGroup && ResourceGroup != null) { Azure.ResourceGroups.DeleteByName(ResourceGroup.Name); } } } }