21 changed files
Cache.cs + | ||
Function1.cs + | ||
GetLoaderioTestGroupActivity.cs + | ||
GetLoaderioTestGroupInput.cs + | ||
Helpers.cs + | ||
HitProxyUrlActivity.cs + | ||
host.json + | ||
LoaderioActivity.cs + | ||
LoaderioOrchestration.cs + | ||
LoaderioTest.cs + | ||
LoaderioTestGroup.cs + | ||
MasterOrchestration.cs + | ||
MasterOrchestrationInput.cs + | ||
RequestType.cs + | ||
RestartFunctionAppActivity.cs + | ||
ScaleChangeActivity.cs + | ||
SKUMatchActivity.cs + | ||
TableCommands.txt + | ||
TestScheduler.csproj + | ||
TestScheduler.sln + | ||
Webhook.cs + | ||
Add comment 1 Plus using Newtonsoft.Json.Linq;
Add comment 2 Plus using System.Collections.Generic;
Add comment 3 Plus
Add comment 4 Plus public static class Cache
Add comment 5 Plus {
Add comment 6 Plus public static void Initialize(string clientId, string servicePrincipalPassword, string tenantId, string loaderioKey)
Add comment 7 Plus {
Add comment 8 Plus FunctionappDomainToDetails = new Dictionary<string, JObject>();
Add comment 9 Plus Scenarios = new List<JObject>();
Add comment 10 Plus ScenariosSplitByOSAndSKU = new Dictionary<string, List<JObject>>();
Add comment 11 Plus ClientId = clientId;
Add comment 12 Plus ServicePrincipalPassword = servicePrincipalPassword;
Add comment 13 Plus TenantId = tenantId;
Add comment 14 Plus LoaderioKey = loaderioKey;
Add comment 15 Plus }
Add comment 16 Plus
Add comment 17 Plus public static IDictionary<string, JObject> FunctionappDomainToDetails;
Add comment 18 Plus public static List<JObject> Scenarios;
Add comment 19 Plus public static IDictionary<string, List<JObject>> ScenariosSplitByOSAndSKU;
Add comment 20 Plus public static string ClientId;
Add comment 21 Plus public static string ServicePrincipalPassword;
Add comment 22 Plus public static string TenantId;
Add comment 23 Plus public static string LoaderioKey;
Add comment 24 Plus }
Add comment 1 Plus using System;
Add comment 2 Plus using System.Collections.Generic;
Add comment 3 Plus using System.IO;
Add comment 4 Plus using System.Threading.Tasks;
Add comment 5 Plus using Microsoft.Azure.WebJobs;
Add comment 6 Plus using Microsoft.Azure.WebJobs.Extensions.DurableTask;
Add comment 7 Plus using Microsoft.Extensions.Configuration;
Add comment 8 Plus using Microsoft.Extensions.Logging;
Add comment 9 Plus using Newtonsoft.Json.Linq;
Add comment 10 Plus
Add comment 11 Plus namespace TestScheduler
Add comment 12 Plus {
Add comment 13 Plus public class Function1
Add comment 14 Plus {
Add comment 15 Plus private readonly ILogger _logger;
Add comment 16 Plus
Add comment 17 Plus public Function1(ILoggerFactory loggerFactory)
Add comment 18 Plus {
Add comment 19 Plus _logger = loggerFactory.CreateLogger("Microsoft.Azure.WebJobs.LoaderioTestScheduler");
Add comment 20 Plus }
Add comment 21 Plus
Add comment 22 Plus [FunctionName("Function1")]
Add comment 23 Plus public void Run(
Add comment 24 Plus Microsoft.Azure.WebJobs.ExecutionContext context,
Add comment 25 Plus [TimerTrigger("0 */8 * * *")]TimerInfo timeInfo,
Add comment 26 Plus [DurableClient] IDurableOrchestrationClient starter,
Add comment 27 Plus ILogger log)
Add comment 28 Plus {
Add comment 29 Plus _logger.LogInformation($"C# Timer trigger function executing at: {DateTime.UtcNow}");
Add comment 30 Plus
Add comment 31 Plus var config = new ConfigurationBuilder()
Add comment 32 Plus .SetBasePath(context.FunctionAppDirectory)
Add comment 33 Plus .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
Add comment 34 Plus .AddEnvironmentVariables()
Add comment 35 Plus .Build();
Add comment 36 Plus
Add comment 37 Plus string clientId = config["ClientId"];
Add comment 38 Plus string servicePrincipalPassword = config["ServicePrincipalPassword"];
Add comment 39 Plus string loaderioKey = config["LoaderioAPIKey"];
Add comment 40 Plus string loaderioTestURL = config["LoaderioTestsURL"];
Add comment 41 Plus string tenantId = config["TenantId"];
Add comment 42 Plus var masterOrchestrationsInGroups = new List<Task>();
Add comment 43 Plus
Add comment 44 Plus ClearAndPopulateCache(loaderioTestURL, clientId, servicePrincipalPassword, tenantId, loaderioKey);
Add comment 45 Plus
Add comment 46 Plus // Start Master orchestration for each group
Add comment 47 Plus foreach (string key in Cache.ScenariosSplitByOSAndSKU.Keys)
Add comment 48 Plus {
Add comment 49 Plus try
Add comment 50 Plus {
Add comment 51 Plus _logger.LogInformation($"Enqueuing master orchestration for group {key}");
Add comment 52 Plus // masterOrchestrationsInGroups.Add(starter.StartNewAsync(orchestratorFunctionName: "MasterOrchestration", input: key));
Add comment 53 Plus masterOrchestrationsInGroups.Add(starter.StartNewAsync(orchestratorFunctionName: "MasterOrchestration", input: new MasterOrchestrationInput(key, Cache.ScenariosSplitByOSAndSKU[key], clientId, servicePrincipalPassword, tenantId, loaderioKey)));
Add comment 54 Plus }
Add comment 55 Plus catch (Exception ex)
Add comment 56 Plus {
Add comment 57 Plus _logger.LogError(ex, $"Error while processing group key {key}");
Add comment 58 Plus }
Add comment 59 Plus }
Add comment 60 Plus
Add comment 61 Plus _logger.LogInformation($"C# Timer trigger function completed at: {DateTime.UtcNow}");
Add comment 62 Plus }
Add comment 63 Plus
Add comment 64 Plus private void ClearAndPopulateCache(string loaderioTestsUrl, string clientId, string servicePrincipalPassword, string tenantId, string loaderioKey)
Add comment 65 Plus {
Add comment 66 Plus try
Add comment 67 Plus {
Add comment 68 Plus using (StreamReader file = new StreamReader(Helpers.GetLoaderioTests(loaderioTestsUrl)))
Add comment 69 Plus {
Add comment 70 Plus string line = null;
Add comment 71 Plus Cache.Initialize(clientId, servicePrincipalPassword, tenantId, loaderioKey);
Add comment 72 Plus
Add comment 73 Plus while ((line = file.ReadLine()) != null)
Add comment 74 Plus {
Add comment 75 Plus try
Add comment 76 Plus {
Add comment 77 Plus JObject testGroup = JObject.Parse(line);
Add comment 78 Plus string appName = testGroup.Value<string>("AppName");
Add comment 79 Plus string domain = $"{appName}.azurewebsites.net";
Add comment 80 Plus
Add comment 81 Plus // Split
Add comment 82 Plus string[] SplitAppName = appName.Split('-');
Add comment 83 Plus string key = $"{SplitAppName[1].ToLower()}-{SplitAppName[2].ToLower()}"; // {SKU}-{OS}
Add comment 84 Plus if(appName.Contains("euap", StringComparison.OrdinalIgnoreCase))
Add comment 85 Plus {
Add comment 86 Plus key = "euap"; // EUAP apps belong to separate group
Add comment 87 Plus }
Add comment 88 Plus if(!Cache.ScenariosSplitByOSAndSKU.ContainsKey(key))
Add comment 89 Plus {
Add comment 90 Plus Cache.ScenariosSplitByOSAndSKU.Add(key, new List<JObject>());
Add comment 91 Plus }
Add comment 92 Plus Cache.ScenariosSplitByOSAndSKU[key].Add(testGroup);
Add comment 93 Plus _logger.LogInformation($"Added {testGroup} to group {key}");
Add comment 94 Plus
Add comment 95 Plus
Add comment 96 Plus Cache.Scenarios.Add(testGroup);
Add comment 97 Plus Cache.FunctionappDomainToDetails.Add(domain, testGroup);
Add comment 98 Plus }
Add comment 99 Plus catch (Exception ex)
Add comment 100 Plus {
Add comment 101 Plus _logger.LogError(ex, $"Exception while populating cache for line {line}");
Add comment 102 Plus }
Add comment 103 Plus }
Add comment 104 Plus
Add comment 105 Plus // For testing/debugging
Add comment 106 Plus foreach(var key in Cache.ScenariosSplitByOSAndSKU.Keys)
Add comment 107 Plus {
Add comment 108 Plus _logger.LogInformation($"{key} has a value count of {Cache.ScenariosSplitByOSAndSKU[key].Count}");
Add comment 109 Plus }
Add comment 110 Plus }
Add comment 111 Plus }
Add comment 112 Plus catch (Exception ex)
Add comment 113 Plus {
Add comment 114 Plus _logger.LogError(ex, $"Exception while clearing/populating cache");
Add comment 115 Plus }
Add comment 116 Plus }
Add comment 117 Plus }
Add comment 118 Plus }
Add comment 119 Plus
GetLoaderioTestGroupActivity.cs
/GetLoaderioTestGroupActivity.cs+107/GetLoaderioTestGroupActivity.cs
Add comment 1 Plus using System;
Add comment 2 Plus using System.Threading.Tasks;
Add comment 3 Plus using Microsoft.Azure.WebJobs;
Add comment 4 Plus using Microsoft.Azure.WebJobs.Extensions.DurableTask;
Add comment 5 Plus using Microsoft.Extensions.Logging;
Add comment 6 Plus using Newtonsoft.Json.Linq;
Add comment 7 Plus
Add comment 8 Plus namespace TestScheduler
Add comment 9 Plus {
Add comment 10 Plus public class GetLoaderioTestGroupActivity
Add comment 11 Plus {
Add comment 12 Plus
Add comment 13 Plus private readonly ILogger _logger;
Add comment 14 Plus
Add comment 15 Plus public GetLoaderioTestGroupActivity(ILoggerFactory loggerFactory)
Add comment 16 Plus {
Add comment 17 Plus _logger = loggerFactory.CreateLogger("Microsoft.Azure.WebJobs.GetLoaderioTestGroupActivity");
Add comment 18 Plus }
Add comment 19 Plus
Add comment 20 Plus [FunctionName("GetLoaderioTestGroupActivity")]
Add comment 21 Plus public async Task<LoaderioTestGroup> Run(
Add comment 22 Plus [ActivityTrigger] IDurableActivityContext context)
Add comment 23 Plus {
Add comment 24 Plus //JObject testGroup = context.GetInput<JObject>();
Add comment 25 Plus GetLoaderioTestGroupInput testGroupInput = context.GetInput<GetLoaderioTestGroupInput>();
Add comment 26 Plus JObject testGroup = testGroupInput.TestGroup;
Add comment 27 Plus
Add comment 28 Plus LoaderioTestGroup group = new LoaderioTestGroup();
Add comment 29 Plus string appName = testGroup.Value<string>("AppName");
Add comment 30 Plus bool shouldWarmUp = !appName.Contains("ep", StringComparison.OrdinalIgnoreCase) && !appName.Contains("cns", StringComparison.OrdinalIgnoreCase);
Add comment 31 Plus _logger.LogInformation($"Warmup value is {shouldWarmUp} for {appName}");
Add comment 32 Plus
Add comment 33 Plus group.SubscriptionId = testGroup.Value<string>("SubscriptionId");
Add comment 34 Plus group.ResourceGroup = testGroup.Value<string>("ResourceGroup");
Add comment 35 Plus group.AppName = appName;
Add comment 36 Plus group.ClientId = testGroupInput.ClientId;
Add comment 37 Plus group.ServicePrincipalPassword = testGroupInput.ServicePrincipalPassword;
Add comment 38 Plus group.TenantId = testGroupInput.TenantId;
Add comment 39 Plus
Add comment 40 Plus string[] testIds = (testGroup.Value<JArray>("LoaderioTestIDs")).ToObject<string[]>();
Add comment 41 Plus
Add comment 42 Plus foreach (string testId in testIds)
Add comment 43 Plus {
Add comment 44 Plus group.LoaderioTestsWithinGroup.Add(GetTestInvocationDetails(testId, testGroupInput.LoaderioKey, shouldWarmUp));
Add comment 45 Plus }
Add comment 46 Plus
Add comment 47 Plus // Wait time between tests
Add comment 48 Plus group.WaitTimeBetweenTestsInMinutes = 30;
Add comment 49 Plus
Add comment 50 Plus // Populate current SKU
Add comment 51 Plus string token = await Helpers.GetToken(group.ClientId, group.ServicePrincipalPassword, group.TenantId);
Add comment 52 Plus group.CurrentSKU = GetCurrentSKUAsync(token, group.SubscriptionId, group.ResourceGroup, appName);
Add comment 53 Plus
Add comment 54 Plus return group;
Add comment 55 Plus }
Add comment 56 Plus
Add comment 57 Plus private LoaderioTest GetTestInvocationDetails(string testId, string loaderioKey, bool shouldWarmUp = false)
Add comment 58 Plus {
Add comment 59 Plus JToken testDetails = Helpers.GetTestDetails(testId, loaderioKey);
Add comment 60 Plus JToken testDetail = testDetails.Value<JArray>("urls")[0];
Add comment 61 Plus LoaderioTest testParams = new LoaderioTest()
Add comment 62 Plus {
Add comment 63 Plus Content = testDetail.Value<string>("raw_post_body"),
Add comment 64 Plus RequestType = (RequestType)Enum.Parse(typeof(RequestType), testDetail.Value<string>("request_type"), true),
Add comment 65 Plus FunctionAppUrlForColdstart = testDetail.Value<string>("url"),
Add comment 66 Plus LoaderioTestUrl = $"https://api.loader.io/v2/tests/{testId}/run",
Add comment 67 Plus LoaderioStopUrl = $"https://api.loader.io/v2/tests/{testId}/stop",
Add comment 68 Plus ContentType = testDetail.Value<JObject>("headers").Value<string>("Content-Type"), // ContentType would be null if not present
Add comment 69 Plus LoaderioKey = loaderioKey,
Add comment 70 Plus ShouldWarmUp = shouldWarmUp,
Add comment 71 Plus };
Add comment 72 Plus
Add comment 73 Plus return testParams;
Add comment 74 Plus }
Add comment 75 Plus
Add comment 76 Plus private JObject GetCurrentSKUAsync(string token, string subscriptionId, string resourceGroup, string appName)
Add comment 77 Plus {
Add comment 78 Plus try
Add comment 79 Plus {
Add comment 80 Plus string serverFarmId = Helpers.GetServerFarmId(token, subscriptionId, resourceGroup, appName, _logger);
Add comment 81 Plus
Add comment 82 Plus if (string.IsNullOrEmpty(serverFarmId))
Add comment 83 Plus {
Add comment 84 Plus _logger.LogError($"Server farm id for {appName} is empty");
Add comment 85 Plus return null;
Add comment 86 Plus }
Add comment 87 Plus
Add comment 88 Plus JObject serverFarmDetails = Helpers.GetServerFarmDetails(token, serverFarmId, _logger);
Add comment 89 Plus
Add comment 90 Plus if (serverFarmDetails == null)
Add comment 91 Plus {
Add comment 92 Plus _logger.LogError($"Server farm details for {serverFarmId} is null");
Add comment 93 Plus return null;
Add comment 94 Plus }
Add comment 95 Plus
Add comment 96 Plus return serverFarmDetails.Value<JObject>("sku");
Add comment 97 Plus }
Add comment 98 Plus catch (Exception ex)
Add comment 99 Plus {
Add comment 100 Plus _logger.LogError(ex, $"Exception while trying to Get SKU {appName}");
Add comment 101 Plus }
Add comment 102 Plus
Add comment 103 Plus return null;
Add comment 104 Plus }
Add comment 105 Plus }
Add comment 106 Plus }
Add comment 107 Plus