private bool AreExpectedMetricsGenerated(TestMetricsLogger metricsLogger) { return(metricsLogger.EventsBegan.Contains(MetricEventNames.SpecializationSpecializeHost) && metricsLogger.EventsEnded.Contains(MetricEventNames.SpecializationSpecializeHost) && metricsLogger.EventsBegan.Contains(MetricEventNames.SpecializationLanguageWorkerChannelManagerSpecialize) && metricsLogger.EventsEnded.Contains(MetricEventNames.SpecializationLanguageWorkerChannelManagerSpecialize) && metricsLogger.EventsBegan.Contains(MetricEventNames.SpecializationRestartHost) && metricsLogger.EventsEnded.Contains(MetricEventNames.SpecializationRestartHost) && metricsLogger.EventsBegan.Contains(MetricEventNames.SpecializationDelayUntilHostReady) && metricsLogger.EventsEnded.Contains(MetricEventNames.SpecializationDelayUntilHostReady)); }
public void ShouldEnforceSequentialRestart_WithCorrectConfig(string value, bool expectedResult) { var metricsLogger = new TestMetricsLogger(); _host.Setup(h => h.StartAsync(It.IsAny <CancellationToken>())) .Returns(Task.CompletedTask); var hostBuilder = new Mock <IScriptHostBuilder>(); hostBuilder.Setup(b => b.BuildHost(It.IsAny <bool>(), It.IsAny <bool>())) .Returns(_host.Object); IConfiguration config = new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary <string, string> { { "AzureFunctionsJobHost:SequentialRestart", value }, }) .Build(); _hostService = new WebJobsScriptHostService( _monitor, hostBuilder.Object, NullLoggerFactory.Instance, _mockScriptWebHostEnvironment.Object, _mockEnvironment.Object, _hostPerformanceManager, _healthMonitorOptions, metricsLogger, new Mock <IApplicationLifetime>().Object, config, new TestScriptEventManager()); Assert.Equal(expectedResult, _hostService.ShouldEnforceSequentialRestart()); }
protected async Task <IWebHostBuilder> CreateWebHostBuilderAsync(string testDirName, IEnvironment environment) { var httpConfig = new HttpConfiguration(); var uniqueTestRootPath = Path.Combine(_testRootPath, testDirName, Guid.NewGuid().ToString()); var scriptRootPath = Path.Combine(uniqueTestRootPath, "wwwroot"); FileUtility.EnsureDirectoryExists(scriptRootPath); string proxyConfigPath = Path.Combine(scriptRootPath, "proxies.json"); File.WriteAllText(proxyConfigPath, "{}"); await TestHelpers.Await(() => File.Exists(proxyConfigPath)); _loggerProvider = new TestLoggerProvider(); _metricsLogger = new TestMetricsLogger(); if (environment.IsAppService()) { // if the test is mocking App Service environment, we need // to also set the HOME and WEBSITE_SITE_NAME variables environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteHomePath, uniqueTestRootPath); environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteName, "test-host-name"); } var webHostBuilder = Program.CreateWebHostBuilder() .ConfigureAppConfiguration(c => { // This source reads from AzureWebJobsScriptRoot, which does not work // with the custom paths that these tests are using. var source = c.Sources.OfType <WebScriptHostConfigurationSource>().SingleOrDefault(); if (source != null) { c.Sources.Remove(source); } c.AddTestSettings(); }) .ConfigureLogging(c => { c.AddProvider(_loggerProvider); c.AddFilter((cat, lev) => true); }) .ConfigureServices(c => { c.ConfigureAll <ScriptApplicationHostOptions>(o => { o.IsSelfHost = true; o.LogPath = Path.Combine(uniqueTestRootPath, "logs"); o.SecretsPath = Path.Combine(uniqueTestRootPath, "secrets"); o.ScriptPath = _expectedScriptPath = scriptRootPath; }); c.AddSingleton <IEnvironment>(_ => environment); c.AddSingleton <IMetricsLogger>(_ => _metricsLogger); }) .ConfigureScriptHostLogging(b => { b.AddProvider(_loggerProvider); }); return(webHostBuilder); }
public void LogInvocationMetrics_EmitsExpectedEvents() { var metrics = new TestMetricsLogger(); Collection <BindingMetadata> bindings = new Collection <BindingMetadata> { new BindingMetadata { Type = "httpTrigger" }, new BindingMetadata { Type = "blob", Direction = BindingDirection.In }, new BindingMetadata { Type = "blob", Direction = BindingDirection.Out }, new BindingMetadata { Type = "table", Direction = BindingDirection.In }, new BindingMetadata { Type = "table", Direction = BindingDirection.In } }; FunctionInvokerBase.LogInvocationMetrics(metrics, bindings); Assert.Equal(6, metrics.LoggedEvents.Count); Assert.Equal("function.invoke", metrics.LoggedEvents[0]); Assert.Equal("function.binding.httpTrigger", metrics.LoggedEvents[1]); Assert.Equal("function.binding.blob.In", metrics.LoggedEvents[2]); Assert.Equal("function.binding.blob.Out", metrics.LoggedEvents[3]); Assert.Equal("function.binding.table.In", metrics.LoggedEvents[4]); Assert.Equal("function.binding.table.In", metrics.LoggedEvents[5]); }
public async Task GetExtensionsStartupTypes_NonLegacyBundles_UsesBundlesForNonPrecompiledFunctions(bool hasPrecompiledFunctions) { using (var directory = GetTempDirectory()) { TestMetricsLogger testMetricsLogger = new TestMetricsLogger(); var testLogger = GetTestLogger(); string bundlePath = hasPrecompiledFunctions ? "FakePath" : directory.Path; var binPath = Path.Combine(directory.Path, "bin"); var mockExtensionBundleManager = new Mock <IExtensionBundleManager>(); mockExtensionBundleManager.Setup(e => e.IsExtensionBundleConfigured()).Returns(true); mockExtensionBundleManager.Setup(e => e.GetExtensionBundleBinPathAsync()).Returns(Task.FromResult(binPath)); mockExtensionBundleManager.Setup(e => e.IsLegacyExtensionBundle()).Returns(false); var mockFunctionMetadataManager = GetTestFunctionMetadataManager(hasPrecompiledFunction: hasPrecompiledFunctions); var discoverer = new ScriptStartupTypeLocator(directory.Path, testLogger, mockExtensionBundleManager.Object, mockFunctionMetadataManager, testMetricsLogger); // Act var types = await discoverer.GetExtensionsStartupTypesAsync(); //Assert AreExpectedMetricsGenerated(testMetricsLogger); Assert.Single(types); Assert.Equal(typeof(AzureStorageWebJobsStartup).FullName, types.Single().FullName); } }
public FunctionInvokerBaseTests() { _metricsLogger = new TestMetricsLogger(); _traceWriter = new TestTraceWriter(TraceLevel.Verbose); var config = new ScriptHostConfiguration(); config.HostConfig.AddService <IMetricsLogger>(_metricsLogger); var funcDescriptor = new FunctionDescriptor(); var funcDescriptors = new Collection <FunctionDescriptor>(); funcDescriptors.Add(funcDescriptor); var eventManager = new Mock <IScriptEventManager>(); var hostMock = new Mock <ScriptHost>(MockBehavior.Strict, new object[] { new NullScriptHostEnvironment(), eventManager.Object, config, null, null }); hostMock.SetupGet(h => h.FunctionTraceWriterFactory).Returns(new FunctionTraceWriterFactory(config)); hostMock.SetupGet(h => h.Functions).Returns(funcDescriptors); hostMock.Object.TraceWriter = _traceWriter; var metadata = new FunctionMetadata { Name = "TestFunction" }; _invoker = new MockInvoker(hostMock.Object, _metricsLogger, metadata); funcDescriptor.Metadata = metadata; funcDescriptor.Invoker = _invoker; funcDescriptor.Name = metadata.Name; }
public async Task GetExtensionsStartupTypes_ExtensionBundleReturnsNullPath_ReturnsNull() { var mockExtensionBundleManager = new Mock <IExtensionBundleManager>(); mockExtensionBundleManager.Setup(e => e.IsExtensionBundleConfigured()).Returns(true); mockExtensionBundleManager.Setup(e => e.GetExtensionBundlePath()).ReturnsAsync(string.Empty); using (var directory = new TempDirectory()) { TestLoggerProvider testLoggerProvider = new TestLoggerProvider(); LoggerFactory factory = new LoggerFactory(); TestMetricsLogger testMetricsLogger = new TestMetricsLogger(); factory.AddProvider(testLoggerProvider); var testLogger = factory.CreateLogger <ScriptStartupTypeLocator>(); var mockFunctionMetadataManager = GetTestFunctionMetadataManager(ImmutableArray <FunctionMetadata> .Empty); var discoverer = new ScriptStartupTypeLocator(string.Empty, testLogger, mockExtensionBundleManager.Object, mockFunctionMetadataManager, testMetricsLogger); // Act var types = await discoverer.GetExtensionsStartupTypesAsync(); var traces = testLoggerProvider.GetAllLogMessages(); // Assert AreExpectedMetricsGenerated(testMetricsLogger); Assert.NotNull(types); Assert.Equal(types.Count(), 0); Assert.True(traces.Any(m => string.Equals(m.FormattedMessage, $"Unable to find or download extension bundle"))); } }
public async Task GetExtensionsStartupTypes_RejectsBundleBelowMinimumVersion() { using (var directory = GetTempDirectory()) { TestMetricsLogger testMetricsLogger = new TestMetricsLogger(); TestLoggerProvider testLoggerProvider = new TestLoggerProvider(); LoggerFactory factory = new LoggerFactory(); factory.AddProvider(testLoggerProvider); var testLogger = factory.CreateLogger <ScriptStartupTypeLocator>(); var binPath = Path.Combine(directory.Path, "bin"); var mockExtensionBundleManager = new Mock <IExtensionBundleManager>(); mockExtensionBundleManager.Setup(e => e.IsExtensionBundleConfigured()).Returns(true); mockExtensionBundleManager.Setup(e => e.GetExtensionBundleBinPathAsync()).Returns(Task.FromResult(binPath)); mockExtensionBundleManager.Setup(e => e.IsLegacyExtensionBundle()).Returns(false); mockExtensionBundleManager.Setup(e => e.GetExtensionBundleDetails()).Returns(Task.FromResult(GetV2BundleDetails("2.1.0"))); var mockFunctionMetadataManager = GetTestFunctionMetadataManager(); var languageWorkerOptions = new OptionsWrapper <LanguageWorkerOptions>(new LanguageWorkerOptions()); var discoverer = new ScriptStartupTypeLocator(directory.Path, testLogger, mockExtensionBundleManager.Object, mockFunctionMetadataManager, testMetricsLogger, languageWorkerOptions); // Act var exception = await Assert.ThrowsAsync <HostInitializationException>(async() => await discoverer.GetExtensionsStartupTypesAsync()); var traces = testLoggerProvider.GetAllLogMessages(); // Assert Assert.True(traces.Any(m => string.Equals(m.FormattedMessage, $"Referenced bundle Microsoft.Azure.Functions.ExtensionBundle of version 2.1.0 does not meet the required minimum version of 2.6.1. Update your extension bundle reference in host.json to reference 2.6.1 or later."))); } }
public void LogInvocationMetrics_EmitsExpectedEvents() { var metrics = new TestMetricsLogger(); var metadata = new FunctionMetadata { Name = "TestFunction" }; metadata.Bindings.Add(new BindingMetadata { Type = "httpTrigger" }); metadata.Bindings.Add(new BindingMetadata { Type = "blob", Direction = BindingDirection.In }); metadata.Bindings.Add(new BindingMetadata { Type = "blob", Direction = BindingDirection.Out }); metadata.Bindings.Add(new BindingMetadata { Type = "table", Direction = BindingDirection.In }); metadata.Bindings.Add(new BindingMetadata { Type = "table", Direction = BindingDirection.In }); var invokeLatencyEvent = FunctionInvokerBase.LogInvocationMetrics(metrics, metadata); Assert.Equal($"{MetricEventNames.FunctionInvokeLatency}_testfunction", (string)invokeLatencyEvent); Assert.Equal(5, metrics.LoggedEvents.Count); Assert.Equal("function.binding.httptrigger", metrics.LoggedEvents[0]); Assert.Equal("function.binding.blob.in", metrics.LoggedEvents[1]); Assert.Equal("function.binding.blob.out", metrics.LoggedEvents[2]); Assert.Equal("function.binding.table.in", metrics.LoggedEvents[3]); Assert.Equal("function.binding.table.in", metrics.LoggedEvents[4]); }
public async Task GetExtensionsStartupTypes_LegacyBundles_UsesExtensionBundleBinaries(bool hasPrecompiledFunctions) { using (var directory = GetTempDirectory()) { var binPath = Path.Combine(directory.Path, "bin"); TestMetricsLogger testMetricsLogger = new TestMetricsLogger(); var testLogger = GetTestLogger(); var mockExtensionBundleManager = new Mock <IExtensionBundleManager>(); mockExtensionBundleManager.Setup(e => e.IsExtensionBundleConfigured()).Returns(true); mockExtensionBundleManager.Setup(e => e.GetExtensionBundleBinPathAsync()).Returns(Task.FromResult(binPath)); mockExtensionBundleManager.Setup(e => e.IsLegacyExtensionBundle()).Returns(true); mockExtensionBundleManager.Setup(e => e.GetExtensionBundleDetails()).Returns(Task.FromResult(GetV2BundleDetails())); var mockFunctionMetadataManager = GetTestFunctionMetadataManager(hasPrecompiledFunction: hasPrecompiledFunctions); var languageWorkerOptions = new OptionsWrapper <LanguageWorkerOptions>(new LanguageWorkerOptions()); var discoverer = new ScriptStartupTypeLocator(directory.Path, testLogger, mockExtensionBundleManager.Object, mockFunctionMetadataManager, testMetricsLogger, languageWorkerOptions); // Act var types = await discoverer.GetExtensionsStartupTypesAsync(); //Assert AreExpectedMetricsGenerated(testMetricsLogger); Assert.Single(types); Assert.Equal(typeof(AzureStorageWebJobsStartup).FullName, types.Single().FullName); } }
public async Task HostInitialization_OnInitializationException_MaintainsErrorInformation() { // When an exception is thrown, we'll create a new host. Make sure // we don't return the same one (with disposed services) the second time. var metricsLogger = new TestMetricsLogger(); var hostA = CreateMockHost(); hostA.Setup(h => h.StartAsync(It.IsAny <CancellationToken>())) .Throws(new HostInitializationException("boom")); var hostB = CreateMockHost(); hostB.Setup(h => h.StartAsync(It.IsAny <CancellationToken>())) .Returns(Task.CompletedTask); var hostBuilder = new Mock <IScriptHostBuilder>(); hostBuilder.SetupSequence(b => b.BuildHost(It.IsAny <bool>(), It.IsAny <bool>())) .Returns(hostA.Object) .Returns(hostB.Object); _hostService = new WebJobsScriptHostService( _monitor, hostBuilder.Object, NullLoggerFactory.Instance, _mockScriptWebHostEnvironment.Object, _mockEnvironment.Object, _hostPerformanceManager, _healthMonitorOptions, metricsLogger, new Mock <IApplicationLifetime>().Object); await _hostService.StartAsync(CancellationToken.None); Assert.True(AreRequiredMetricsGenerated(metricsLogger)); Assert.Equal(ScriptHostState.Error, _hostService.State); Assert.IsType <HostInitializationException>(_hostService.LastError); }
public async Task StartAsync_Succeeds() { var hostBuilder = new Mock <IScriptHostBuilder>(); hostBuilder.Setup(b => b.BuildHost(It.IsAny <bool>(), It.IsAny <bool>())).Returns(_host.Object); _webHostLoggerProvider = new TestLoggerProvider(); _loggerFactory = new LoggerFactory(); _loggerFactory.AddProvider(_webHostLoggerProvider); var mockEventManager = new Mock <IScriptEventManager>(MockBehavior.Strict); mockEventManager.Setup(p => p.Publish(It.IsAny <HostStartEvent>())); var metricsLogger = new TestMetricsLogger(); _hostService = new WebJobsScriptHostService( _monitor, hostBuilder.Object, _loggerFactory, _mockScriptWebHostEnvironment.Object, _mockEnvironment.Object, _hostPerformanceManager, _healthMonitorOptions, metricsLogger, new Mock <IApplicationLifetime>().Object, _mockConfig, mockEventManager.Object); await _hostService.StartAsync(CancellationToken.None); // add general post startup validations here mockEventManager.Verify(_ => _.Publish(It.IsAny <HostStartEvent>()), Times.Once()); }
public async Task GetExtensionsStartupTypes_BundlesConfiguredBindingsConfigured_PerformsSelectiveLoading() { var storageExtensionReference = new ExtensionReference { Name = "Storage", TypeName = typeof(AzureStorageWebJobsStartup).AssemblyQualifiedName }; storageExtensionReference.Bindings.Add("blob"); var sendGridExtensionReference = new ExtensionReference { Name = "SendGrid", TypeName = typeof(AzureStorageWebJobsStartup).AssemblyQualifiedName }; sendGridExtensionReference.Bindings.Add("sendGrid"); var references = new[] { storageExtensionReference, sendGridExtensionReference }; TestMetricsLogger testMetricsLogger = new TestMetricsLogger(); var extensions = new JObject { { "extensions", JArray.FromObject(references) } }; using (var directory = new TempDirectory()) { var binPath = Path.Combine(directory.Path, "bin"); Directory.CreateDirectory(binPath); void CopyToBin(string path) { File.Copy(path, Path.Combine(binPath, Path.GetFileName(path))); } CopyToBin(typeof(AzureStorageWebJobsStartup).Assembly.Location); File.WriteAllText(Path.Combine(binPath, "extensions.json"), extensions.ToString()); TestLoggerProvider testLoggerProvider = new TestLoggerProvider(); LoggerFactory factory = new LoggerFactory(); factory.AddProvider(testLoggerProvider); var testLogger = factory.CreateLogger <ScriptStartupTypeLocator>(); var mockFunctionMetadataManager = GetTestFunctionMetadataManager(); var mockExtensionBundleManager = new Mock <IExtensionBundleManager>(); mockExtensionBundleManager.Setup(e => e.IsExtensionBundleConfigured()).Returns(true); mockExtensionBundleManager.Setup(e => e.GetExtensionBundleBinPathAsync()).Returns(Task.FromResult(binPath)); mockExtensionBundleManager.Setup(e => e.GetExtensionBundleDetails()).Returns(Task.FromResult(GetV2BundleDetails())); var languageWorkerOptions = new OptionsWrapper <LanguageWorkerOptions>(new LanguageWorkerOptions()); var discoverer = new ScriptStartupTypeLocator(directory.Path, testLogger, mockExtensionBundleManager.Object, mockFunctionMetadataManager, testMetricsLogger, languageWorkerOptions); // Act var types = await discoverer.GetExtensionsStartupTypesAsync(); //Assert AreExpectedMetricsGenerated(testMetricsLogger); Assert.Single(types); Assert.Equal(typeof(AzureStorageWebJobsStartup).FullName, types.Single().FullName); } }
public FunctionMetadataProviderTests() { _testMetricsLogger = new TestMetricsLogger(); _scriptApplicationHostOptions = new ScriptApplicationHostOptions(); _languageWorkerOptions = new LanguageWorkerOptions { WorkerConfigs = TestHelpers.GetTestWorkerConfigs() }; }
public async Task DisposesScriptHost() { var metricsLogger = new TestMetricsLogger(); var services = new ServiceCollection() .AddLogging(l => { l.Services.AddSingleton <ILoggerProvider, TestLoggerProvider>(); l.AddFilter(_ => true); }) .BuildServiceProvider(); var host = new Mock <IHost>(); host.Setup(h => h.Services) .Returns(services); host.Setup(h => h.Dispose()) .Callback(() => { services.Dispose(); }); var hostBuilder = new Mock <IScriptHostBuilder>(); hostBuilder.Setup(b => b.BuildHost(It.IsAny <bool>(), It.IsAny <bool>())) .Returns(host.Object); _webHostLoggerProvider = new TestLoggerProvider(); _loggerFactory = new LoggerFactory(); _loggerFactory.AddProvider(_webHostLoggerProvider); _hostService = new WebJobsScriptHostService( _monitor, hostBuilder.Object, _loggerFactory, _mockScriptWebHostEnvironment.Object, _mockEnvironment.Object, _hostPerformanceManager, _healthMonitorOptions, metricsLogger, new Mock <IApplicationLifetime>().Object, _mockConfig, new TestScriptEventManager()); var hostLogger = host.Object.GetTestLoggerProvider(); await _hostService.StartAsync(CancellationToken.None); await _hostService.RestartHostAsync(CancellationToken.None); Assert.True(AreRequiredMetricsGenerated(metricsLogger)); host.Verify(m => m.StopAsync(It.IsAny <CancellationToken>()), Times.Exactly(1)); host.Verify(m => m.Dispose(), Times.Exactly(1)); var allLogMessages = _webHostLoggerProvider.GetAllLogMessages(); Assert.Contains(allLogMessages, m => m.FormattedMessage != null && m.FormattedMessage.Contains("ScriptHost disposed")); }
public async Task Specialize_StandbyManagerInitialize_EmitsExpectedMetric() { TestMetricsLogger metricsLogger = new TestMetricsLogger(); _testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteHostName, "placeholder.azurewebsites.net"); var hostNameProvider = new HostNameProvider(_testEnvironment); var manager = new StandbyManager(_mockHostManager.Object, _mockLanguageWorkerChannelManager.Object, _mockConfiguration.Object, _mockWebHostEnvironment.Object, _testEnvironment, _mockOptionsMonitor.Object, NullLogger <StandbyManager> .Instance, hostNameProvider, _mockApplicationLifetime.Object, metricsLogger); await manager.InitializeAsync().ContinueWith(t => { }); // Ignore errors. // Ensure metric is generated Assert.True(metricsLogger.EventsBegan.Contains(MetricEventNames.SpecializationStandbyManagerInitialize) && metricsLogger.EventsEnded.Contains(MetricEventNames.SpecializationStandbyManagerInitialize)); }
public async Task Specialize_ResetsConfiguration() { TestMetricsLogger metricsLogger = new TestMetricsLogger(); var hostNameProvider = new HostNameProvider(_testEnvironment); var manager = new StandbyManager(_mockHostManager.Object, _mockLanguageWorkerChannelManager.Object, _mockConfiguration.Object, _mockWebHostEnvironment.Object, _testEnvironment, _mockOptionsMonitor.Object, NullLogger <StandbyManager> .Instance, hostNameProvider, _mockApplicationLifetime.Object, metricsLogger); await manager.SpecializeHostAsync(); // Ensure metrics are generated Assert.True(AreExpectedMetricsGenerated(metricsLogger)); _mockConfiguration.Verify(c => c.Reload()); }
public async Task GetExtensionsStartupTypes_BundlesNotConfiguredBindingsNotConfigured_LoadsAllExtensions() { var references = new[] { new ExtensionReference { Name = "Storage", TypeName = typeof(AzureStorageWebJobsStartup).AssemblyQualifiedName } }; var extensions = new JObject { { "extensions", JArray.FromObject(references) } }; var mockExtensionBundleManager = new Mock <IExtensionBundleManager>(); TestMetricsLogger testMetricsLogger = new TestMetricsLogger(); mockExtensionBundleManager.Setup(e => e.IsExtensionBundleConfigured()).Returns(false); using (var directory = new TempDirectory()) { var binPath = Path.Combine(directory.Path, "bin"); Directory.CreateDirectory(binPath); void CopyToBin(string path) { File.Copy(path, Path.Combine(binPath, Path.GetFileName(path))); } CopyToBin(typeof(AzureStorageWebJobsStartup).Assembly.Location); File.WriteAllText(Path.Combine(binPath, "extensions.json"), extensions.ToString()); TestLoggerProvider testLoggerProvider = new TestLoggerProvider(); LoggerFactory factory = new LoggerFactory(); factory.AddProvider(testLoggerProvider); var testLogger = factory.CreateLogger <ScriptStartupTypeLocator>(); // mock Function metadata var mockFunctionMetadataManager = GetTestFunctionMetadataManager(ImmutableArray <FunctionMetadata> .Empty); var discoverer = new ScriptStartupTypeLocator(directory.Path, testLogger, mockExtensionBundleManager.Object, mockFunctionMetadataManager, testMetricsLogger); // Act var types = await discoverer.GetExtensionsStartupTypesAsync(); // Assert AreExpectedMetricsGenerated(testMetricsLogger); Assert.Single(types); Assert.Equal(typeof(AzureStorageWebJobsStartup).FullName, types.Single().FullName); } }
public async Task DisposedHost_ServicesNotExposed() { SemaphoreSlim blockingSemaphore = new SemaphoreSlim(0, 1); SemaphoreSlim disposedSemaphore = new SemaphoreSlim(0, 1); var metricsLogger = new TestMetricsLogger(); // Have the first host throw upon starting. Then pause while building the second // host. When accessing Services then, they should be null, rather than disposed. var hostA = CreateMockHost(disposedSemaphore); hostA .Setup(h => h.StartAsync(It.IsAny <CancellationToken>())) .Returns(() => { throw new InvalidOperationException("Something happened at startup!"); }); var hostB = CreateMockHost(); hostB .Setup(h => h.StartAsync(It.IsAny <CancellationToken>())) .Returns(async() => { await blockingSemaphore.WaitAsync(); }); var hostBuilder = new Mock <IScriptHostBuilder>(); hostBuilder.SetupSequence(b => b.BuildHost(It.IsAny <bool>(), It.IsAny <bool>())) .Returns(hostA.Object) .Returns(hostB.Object); _hostService = new WebJobsScriptHostService( _monitor, hostBuilder.Object, NullLoggerFactory.Instance, _mockScriptWebHostEnvironment.Object, _mockEnvironment.Object, _hostPerformanceManager, _healthMonitorOptions, metricsLogger, new Mock <IApplicationLifetime>().Object, _mockConfig, new TestScriptEventManager()); Task startTask = _hostService.StartAsync(CancellationToken.None); await disposedSemaphore.WaitAsync(); Assert.Null(_hostService.Services); blockingSemaphore.Release(); await startTask; Assert.True(AreRequiredMetricsGenerated(metricsLogger)); }
public async Task HostRestart_BeforeStart_WaitsForStartToContinue() { _host = CreateMockHost(); var metricsLogger = new TestMetricsLogger(); var hostBuilder = new Mock <IScriptHostBuilder>(); hostBuilder.SetupSequence(b => b.BuildHost(It.IsAny <bool>(), It.IsAny <bool>())) .Returns(_host.Object) .Returns(_host.Object); _webHostLoggerProvider = new TestLoggerProvider(); _loggerFactory = new LoggerFactory(); _loggerFactory.AddProvider(_webHostLoggerProvider); _hostService = new WebJobsScriptHostService( _monitor, hostBuilder.Object, _loggerFactory, _mockScriptWebHostEnvironment.Object, _mockEnvironment.Object, _hostPerformanceManager, _healthMonitorOptions, metricsLogger, new Mock <IApplicationLifetime>().Object, _mockConfig, new TestScriptEventManager()); // Simulate a call to specialize coming from the PlaceholderSpecializationMiddleware. This // can happen before we ever start the service, which could create invalid state. Task restartTask = _hostService.RestartHostAsync(CancellationToken.None); await _hostService.StartAsync(CancellationToken.None); await restartTask; // Ensure metrics are added Assert.True(AreRequiredMetricsGenerated(metricsLogger)); Assert.True(metricsLogger.EventsBegan.Contains(MetricEventNames.ScriptHostManagerRestartService)); Assert.True(metricsLogger.EventsEnded.Contains(MetricEventNames.ScriptHostManagerRestartService)); Assert.True(metricsLogger.EventsBegan.Contains(MetricEventNames.ScriptHostManagerBuildScriptHost)); Assert.True(metricsLogger.EventsBegan.Contains(MetricEventNames.ScriptHostManagerBuildScriptHost)); Assert.True(metricsLogger.EventsBegan.Contains(MetricEventNames.ScriptHostManagerStartScriptHost)); Assert.True(metricsLogger.EventsBegan.Contains(MetricEventNames.ScriptHostManagerStartScriptHost)); var messages = _webHostLoggerProvider.GetAllLogMessages(); // The CancellationToken is canceled quick enough that we never build the initial host, so the // only one we start is the restarted/specialized one. Assert.NotNull(messages.Single(p => p.EventId.Id == 513)); // "Building" message Assert.NotNull(messages.Single(p => p.EventId.Id == 514)); // "StartupWasCanceled" message Assert.NotNull(messages.Single(p => p.EventId.Id == 520)); // "RestartBeforeStart" message _host.Verify(p => p.StartAsync(It.IsAny <CancellationToken>()), Times.Once); }
public async Task GetExtensionsStartupTypes_RejectsExtensionsBelowMinimumVersion() { var mockExtensionBundleManager = new Mock <IExtensionBundleManager>(); TestMetricsLogger testMetricsLogger = new TestMetricsLogger(); mockExtensionBundleManager.Setup(e => e.IsExtensionBundleConfigured()).Returns(false); using (var directory = new TempDirectory()) { var binPath = Path.Combine(directory.Path, "bin"); Directory.CreateDirectory(binPath); void CopyToBin(string path) { File.Copy(path, Path.Combine(binPath, Path.GetFileName(path))); } // create a bin folder that has out of date extensions var extensionBinPath = Path.Combine(Environment.CurrentDirectory, @"TestScripts\OutOfDateExtension\bin"); foreach (var f in Directory.GetFiles(extensionBinPath)) { CopyToBin(f); } TestLoggerProvider testLoggerProvider = new TestLoggerProvider(); LoggerFactory factory = new LoggerFactory(); factory.AddProvider(testLoggerProvider); var testLogger = factory.CreateLogger <ScriptStartupTypeLocator>(); var mockFunctionMetadataManager = GetTestFunctionMetadataManager(ImmutableArray <FunctionMetadata> .Empty); var languageWorkerOptions = new OptionsWrapper <LanguageWorkerOptions>(new LanguageWorkerOptions()); var discoverer = new ScriptStartupTypeLocator(directory.Path, testLogger, mockExtensionBundleManager.Object, mockFunctionMetadataManager, testMetricsLogger, languageWorkerOptions); // Act var exception = await Assert.ThrowsAsync <HostInitializationException>(async() => await discoverer.GetExtensionsStartupTypesAsync()); var traces = testLoggerProvider.GetAllLogMessages(); // Assert var storageTrace = traces.FirstOrDefault(m => m.FormattedMessage.StartsWith("ExtensionStartupType AzureStorageWebJobsStartup")); Assert.NotNull(storageTrace); Assert.Equal("ExtensionStartupType AzureStorageWebJobsStartup from assembly 'Microsoft.Azure.WebJobs.Extensions.Storage, Version=3.0.10.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' does not meet the required minimum version of 4.0.4.0. Update your NuGet package reference for Microsoft.Azure.WebJobs.Extensions.Storage to 4.0.4 or later.", storageTrace.FormattedMessage); } }
public FunctionInvokerBaseTests() { _metricsLogger = new TestMetricsLogger(); _traceWriter = new TestTraceWriter(TraceLevel.Verbose); var config = new ScriptHostConfiguration(); config.HostConfig.AddService <IMetricsLogger>(_metricsLogger); var hostMock = new Mock <ScriptHost>(MockBehavior.Strict, new object[] { new NullScriptHostEnvironment(), config, null }); hostMock.Object.TraceWriter = _traceWriter; var metadata = new FunctionMetadata { Name = "TestFunction" }; _invoker = new MockInvoker(hostMock.Object, metadata); }
public FunctionInvokerBaseTests() { _metricsLogger = new TestMetricsLogger(); _testLoggerProvider = new TestLoggerProvider(); var scriptHostConfiguration = new ScriptHostConfiguration { HostConfig = new JobHostConfiguration(), FileLoggingMode = FileLoggingMode.Always, FileWatchingEnabled = true }; ILoggerFactory loggerFactory = new LoggerFactory(); loggerFactory.AddProvider(_testLoggerProvider); scriptHostConfiguration.HostConfig.LoggerFactory = loggerFactory; scriptHostConfiguration.HostConfig.AddService <IMetricsLogger>(_metricsLogger); var eventManager = new ScriptEventManager(); var host = new Mock <ScriptHost>(new NullScriptHostEnvironment(), eventManager, scriptHostConfiguration, null, null, null); host.CallBase = true; host.SetupGet(h => h.IsPrimary).Returns(true); var funcDescriptor = new FunctionDescriptor(); var funcDescriptors = new Collection <FunctionDescriptor>(); funcDescriptors.Add(funcDescriptor); host.SetupGet(h => h.Functions).Returns(funcDescriptors); var metadata = new FunctionMetadata { Name = "TestFunction" }; _invoker = new MockInvoker(host.Object, _metricsLogger, metadata); funcDescriptor.Metadata = metadata; funcDescriptor.Invoker = _invoker; funcDescriptor.Name = metadata.Name; }
public FunctionInvokerBaseTests() { _metricsLogger = new TestMetricsLogger(); _testLoggerProvider = new TestLoggerProvider(); ILoggerFactory loggerFactory = new LoggerFactory(); loggerFactory.AddProvider(_testLoggerProvider); var eventManager = new ScriptEventManager(); var metadata = new FunctionMetadata { Name = "TestFunction", ScriptFile = "index.js", Language = "node" }; JObject binding = JObject.FromObject(new { type = "manualTrigger", name = "manual", direction = "in" }); metadata.Bindings.Add(BindingMetadata.Create(binding)); var metadataManager = new MockMetadataManager(new[] { metadata }); _host = new HostBuilder() .ConfigureDefaultTestWebScriptHost() .ConfigureServices(s => { s.AddSingleton <IFunctionMetadataManager>(metadataManager); }) .Build(); _scriptHost = _host.GetScriptHost(); _scriptHost.InitializeAsync().Wait(); _invoker = new MockInvoker(_scriptHost, _metricsLogger, metadataManager, metadata, loggerFactory); }
public async Task Specialize_ReloadsEnvironmentVariables() { TestMetricsLogger metricsLogger = new TestMetricsLogger(); _testEnvironment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, RpcWorkerConstants.JavaLanguageWorkerName); _mockLanguageWorkerChannelManager.Setup(m => m.SpecializeAsync()).Returns(async() => { _testEnvironment.SetEnvironmentVariable(_testSettingName, _testSettingValue); await Task.Yield(); }); _testEnvironment.SetEnvironmentVariable(RpcWorkerConstants.FunctionWorkerRuntimeSettingName, RpcWorkerConstants.JavaLanguageWorkerName); var hostNameProvider = new HostNameProvider(_testEnvironment); var manager = new StandbyManager(_mockHostManager.Object, _mockLanguageWorkerChannelManager.Object, _mockConfiguration.Object, _mockWebHostEnvironment.Object, _testEnvironment, _mockOptionsMonitor.Object, NullLogger <StandbyManager> .Instance, hostNameProvider, _mockApplicationLifetime.Object, metricsLogger); await manager.SpecializeHostAsync(); // Ensure metrics are generated Assert.True(AreExpectedMetricsGenerated(metricsLogger)); Assert.Equal(_testSettingValue, _testEnvironment.GetEnvironmentVariable(_testSettingName)); }
public async Task Specialize_ResetsHostNameProvider() { TestMetricsLogger metricsLogger = new TestMetricsLogger(); _testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteHostName, "placeholder.azurewebsites.net"); var hostNameProvider = new HostNameProvider(_testEnvironment); var manager = new StandbyManager(_mockHostManager.Object, _mockLanguageWorkerChannelManager.Object, _mockConfiguration.Object, _mockWebHostEnvironment.Object, _testEnvironment, _mockOptionsMonitor.Object, NullLogger <StandbyManager> .Instance, hostNameProvider, _mockApplicationLifetime.Object, metricsLogger); Assert.Equal("placeholder.azurewebsites.net", hostNameProvider.Value); await manager.SpecializeHostAsync(); // Ensure metrics are generated Assert.True(AreExpectedMetricsGenerated(metricsLogger)); _testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteHostName, "testapp.azurewebsites.net"); Assert.Equal("testapp.azurewebsites.net", hostNameProvider.Value); _mockConfiguration.Verify(c => c.Reload()); }
public async Task HostRestart_Specialization_Succeeds() { var metricsLogger = new TestMetricsLogger(); _host.Setup(h => h.StartAsync(It.IsAny <CancellationToken>())) .Returns(Task.CompletedTask); var hostBuilder = new Mock <IScriptHostBuilder>(); hostBuilder.Setup(b => b.BuildHost(It.IsAny <bool>(), It.IsAny <bool>())) .Returns(_host.Object); _webHostLoggerProvider = new TestLoggerProvider(); _loggerFactory = new LoggerFactory(); _loggerFactory.AddProvider(_webHostLoggerProvider); _hostService = new WebJobsScriptHostService( _monitor, hostBuilder.Object, _loggerFactory, _mockScriptWebHostEnvironment.Object, _mockEnvironment.Object, _hostPerformanceManager, _healthMonitorOptions, metricsLogger, new Mock <IApplicationLifetime>().Object, _mockConfig, new TestScriptEventManager()); await _hostService.StartAsync(CancellationToken.None); Assert.True(AreRequiredMetricsGenerated(metricsLogger)); Thread restartHostThread = new Thread(new ThreadStart(RestartHost)); Thread specializeHostThread = new Thread(new ThreadStart(SpecializeHost)); restartHostThread.Start(); specializeHostThread.Start(); restartHostThread.Join(); specializeHostThread.Join(); var logMessages = _webHostLoggerProvider.GetAllLogMessages().Where(m => m.FormattedMessage.Contains("Restarting host.")); Assert.Equal(2, logMessages.Count()); }
private bool AreRequiredMetricsEmitted(TestMetricsLogger metricsLogger) { bool hasBegun = false; bool hasEnded = false; foreach (string begin in metricsLogger.EventsBegan) { if (begin.Contains(MetricEventNames.ReadFunctionMetadata.Substring(0, MetricEventNames.ReadFunctionMetadata.IndexOf('{')))) { hasBegun = true; break; } } foreach (string end in metricsLogger.EventsEnded) { if (end.Contains(MetricEventNames.ReadFunctionMetadata.Substring(0, MetricEventNames.ReadFunctionMetadata.IndexOf('{')))) { hasEnded = true; break; } } return(hasBegun && hasEnded && (metricsLogger.EventsBegan.Contains(MetricEventNames.ReadFunctionsMetadata) && metricsLogger.EventsEnded.Contains(MetricEventNames.ReadFunctionsMetadata))); }
private bool AreExpectedMetricsGenerated(TestMetricsLogger metricsLogger) { return(metricsLogger.EventsBegan.Contains(MetricEventNames.ParseExtensions) && metricsLogger.EventsEnded.Contains(MetricEventNames.ParseExtensions)); }
public async Task GetExtensionsStartupTypes_FiltersBuiltinExtensionsAsync() { var references = new[] { new ExtensionReference { Name = "Http", TypeName = typeof(HttpWebJobsStartup).AssemblyQualifiedName }, new ExtensionReference { Name = "Timers", TypeName = typeof(ExtensionsWebJobsStartup).AssemblyQualifiedName }, new ExtensionReference { Name = "Storage", TypeName = typeof(AzureStorageWebJobsStartup).AssemblyQualifiedName }, }; var extensions = new JObject { { "extensions", JArray.FromObject(references) } }; var mockExtensionBundleManager = new Mock <IExtensionBundleManager>(); TestMetricsLogger testMetricsLogger = new TestMetricsLogger(); mockExtensionBundleManager.Setup(e => e.IsExtensionBundleConfigured()).Returns(false); using (var directory = new TempDirectory()) { var binPath = Path.Combine(directory.Path, "bin"); Directory.CreateDirectory(binPath); void CopyToBin(string path) { File.Copy(path, Path.Combine(binPath, Path.GetFileName(path))); } CopyToBin(typeof(HttpWebJobsStartup).Assembly.Location); CopyToBin(typeof(ExtensionsWebJobsStartup).Assembly.Location); CopyToBin(typeof(AzureStorageWebJobsStartup).Assembly.Location); File.WriteAllText(Path.Combine(binPath, "extensions.json"), extensions.ToString()); TestLoggerProvider testLoggerProvider = new TestLoggerProvider(); LoggerFactory factory = new LoggerFactory(); factory.AddProvider(testLoggerProvider); var testLogger = factory.CreateLogger <ScriptStartupTypeLocator>(); var mockFunctionMetadataManager = GetTestFunctionMetadataManager(ImmutableArray <FunctionMetadata> .Empty); var discoverer = new ScriptStartupTypeLocator(directory.Path, testLogger, mockExtensionBundleManager.Object, mockFunctionMetadataManager, testMetricsLogger); // Act var types = await discoverer.GetExtensionsStartupTypesAsync(); var traces = testLoggerProvider.GetAllLogMessages(); // Assert AreExpectedMetricsGenerated(testMetricsLogger); Assert.Single(types); Assert.Equal(typeof(AzureStorageWebJobsStartup).FullName, types.Single().FullName); Assert.True(traces.Any(m => string.Equals(m.FormattedMessage, $"The extension startup type '{references[0].TypeName}' belongs to a builtin extension"))); Assert.True(traces.Any(m => string.Equals(m.FormattedMessage, $"The extension startup type '{references[1].TypeName}' belongs to a builtin extension"))); } }