public StandbyManagerE2ETestBase() { _testRootPath = Path.Combine(Path.GetTempPath(), "StandbyManagerTests"); CleanupTestDirectory(); StandbyManager.ResetChangeToken(); }
public SpecializationE2ETests() { StandbyManager.ResetChangeToken(); var settings = new Dictionary <string, string>() { { EnvironmentSettingNames.AzureWebsitePlaceholderMode, "1" }, { EnvironmentSettingNames.AzureWebsiteContainerReady, null }, }; _environment = new TestEnvironment(settings); _loggerProvider = new TestLoggerProvider(); _pauseBeforeHostBuild = new SemaphoreSlim(1, 1); _pauseAfterStandbyHostBuild = new SemaphoreSlim(1, 1); _buildCount = new SemaphoreSlim(2, 2); }
public async Task InvocationsContainDifferentOperationIds() { // Verify that when a request specializes the host we don't capture the context // of that request. Application Insights uses this context to correlate telemetry // so it had a confusing effect. Previously all TimerTrigger traces would have the // operation id of this request and all host logs would as well. // Start a host in standby mode. StandbyManager.ResetChangeToken(); string standbyPath = Path.Combine(Path.GetTempPath(), "functions", "standby", "wwwroot"); string specializedScriptRoot = @"TestScripts\CSharp"; string scriptRootConfigPath = ConfigurationPath.Combine(ConfigurationSectionNames.WebHost, nameof(ScriptApplicationHostOptions.ScriptPath)); var settings = new Dictionary <string, string>() { { EnvironmentSettingNames.AzureWebsitePlaceholderMode, "1" }, { EnvironmentSettingNames.AzureWebsiteContainerReady, null }, }; var environment = new TestEnvironment(settings); var loggerProvider = new TestLoggerProvider(); var channel = new TestTelemetryChannel(); var builder = Program.CreateWebHostBuilder() .ConfigureLogging(b => { b.AddProvider(loggerProvider); }) .ConfigureAppConfiguration(c => { c.AddInMemoryCollection(new Dictionary <string, string> { { scriptRootConfigPath, specializedScriptRoot } }); }) .ConfigureServices((bc, s) => { s.AddSingleton <IEnvironment>(environment); // Ensure that we don't have a race between the timer and the // request for triggering specialization. s.AddSingleton <IStandbyManager, InfiniteTimerStandbyManager>(); }) .AddScriptHostBuilder(webJobsBuilder => { webJobsBuilder.Services.AddSingleton <ITelemetryChannel>(_ => channel); webJobsBuilder.Services.Configure <FunctionResultAggregatorOptions>(o => { o.IsEnabled = false; }); webJobsBuilder.Services.PostConfigure <ApplicationInsightsLoggerOptions>(o => { o.SamplingSettings = null; }); webJobsBuilder.Services.PostConfigure <ScriptJobHostOptions>(o => { // Only load the function we care about, but not during standby if (o.RootScriptPath != standbyPath) { o.Functions = new[] { "OneSecondTimer", "FunctionExecutionContext" }; } }); }) .ConfigureScriptHostAppConfiguration(c => { c.AddInMemoryCollection(new Dictionary <string, string> { [EnvironmentSettingNames.AppInsightsInstrumentationKey] = "some_key" }); }); using (var testServer = new TestServer(builder)) { var client = testServer.CreateClient(); HttpResponseMessage response = await client.GetAsync("api/warmup"); Assert.True(response.IsSuccessStatusCode, loggerProvider.GetLog()); // Now that standby mode is warmed up, set the specialization properties... environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteContainerReady, "1"); environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsitePlaceholderMode, "0"); // ...and issue a request which will force specialization. response = await client.GetAsync("api/functionexecutioncontext"); Assert.True(response.IsSuccessStatusCode, loggerProvider.GetLog()); // Wait until we have a few logs from the timer trigger. IEnumerable <TraceTelemetry> timerLogs = null; await TestHelpers.Await(() => { timerLogs = channel.Telemetries .OfType <TraceTelemetry>() .Where(p => p.Message == "OneSecondTimer fired!"); return(timerLogs.Count() >= 3); }); var startupRequest = channel.Telemetries .OfType <RequestTelemetry>() .Where(p => p.Name == "FunctionExecutionContext") .Single(); // Make sure that auto-Http tracking worked with this request. Assert.Equal("200", startupRequest.ResponseCode); // The host logs should not be associated with this request. var logsWithRequestId = channel.Telemetries .OfType <TraceTelemetry>() .Select(p => p.Context.Operation.Id) .Where(p => p == startupRequest.Context.Operation.Id); // Just expect the "Executing" and "Executed" logs from the actual request. Assert.Equal(2, logsWithRequestId.Count()); // And each of the timer invocations should have a different operation id, and none // should match the request id. var distinctOpIds = timerLogs.Select(p => p.Context.Operation.Id).Distinct(); Assert.Equal(timerLogs.Count(), distinctOpIds.Count()); Assert.Empty(timerLogs.Where(p => p.Context.Operation.Id == startupRequest.Context.Operation.Id)); } }
public async Task IsPlaceholderMode_ThroughoutInitialization_EvaluatesCorrectly() { StandbyManager.ResetChangeToken(); string standbyPath = Path.Combine(Path.GetTempPath(), "functions", "standby", "wwwroot"); string specializedScriptRoot = @"TestScripts\CSharp"; string scriptRootConfigPath = ConfigurationPath.Combine(ConfigurationSectionNames.WebHost, nameof(ScriptApplicationHostOptions.ScriptPath)); var settings = new Dictionary <string, string>() { { EnvironmentSettingNames.AzureWebsitePlaceholderMode, "1" }, { EnvironmentSettingNames.AzureWebsiteContainerReady, null }, }; var environment = new TestEnvironment(settings); var loggerProvider = new TestLoggerProvider(); var builder = Program.CreateWebHostBuilder() .ConfigureLogging(b => { b.AddProvider(loggerProvider); }) .ConfigureAppConfiguration(c => { c.AddInMemoryCollection(new Dictionary <string, string> { { scriptRootConfigPath, specializedScriptRoot } }); }) .ConfigureServices((bc, s) => { s.AddSingleton <IEnvironment>(environment); // Simulate the environment becoming specialized after these options have been // initialized with standby paths. s.AddOptions <ScriptApplicationHostOptions>() .PostConfigure <IEnvironment>((o, e) => { Specialize(e); }); }) .AddScriptHostBuilder(webJobsBuilder => { webJobsBuilder.Services.PostConfigure <ScriptJobHostOptions>(o => { // Only load the function we care about, but not during standby if (o.RootScriptPath != standbyPath) { o.Functions = new[] { "HttpTrigger-Dynamic" }; } }); }); var server = new TestServer(builder); var client = server.CreateClient(); // Force the specialization middleware to run HttpResponseMessage response = await InvokeFunction(client); response.EnsureSuccessStatusCode(); string log = loggerProvider.GetLog(); Assert.Contains("Creating StandbyMode placeholder function directory", log); Assert.Contains("Starting host specialization", log); // Make sure this was registered. var hostedServices = server.Host.Services.GetServices <IHostedService>(); Assert.Contains(hostedServices, p => p is StandbyInitializationService); }