public TestFunctionHost(string scriptPath, string logPath, Action <IWebJobsBuilder> configureJobHost = null, Action <IConfigurationBuilder> configureAppConfiguration = null, Action <IServiceCollection> configureServices = null) { _appRoot = scriptPath; _hostOptions = new ScriptApplicationHostOptions { IsSelfHost = true, ScriptPath = _appRoot, LogPath = logPath, SecretsPath = Environment.CurrentDirectory, // not used HasParentScope = true }; var optionsMonitor = TestHelpers.CreateOptionsMonitor(_hostOptions); var builder = new WebHostBuilder() .ConfigureLogging(b => { b.AddProvider(_loggerProvider); }) .ConfigureServices(services => { services.Replace(new ServiceDescriptor(typeof(ISecretManagerProvider), new TestSecretManagerProvider(new TestSecretManager()))); services.Replace(ServiceDescriptor.Singleton <IServiceProviderFactory <IServiceCollection> >(new WebHostServiceProviderFactory())); services.Replace(new ServiceDescriptor(typeof(IOptions <ScriptApplicationHostOptions>), new OptionsWrapper <ScriptApplicationHostOptions>(_hostOptions))); services.Replace(new ServiceDescriptor(typeof(IOptionsMonitor <ScriptApplicationHostOptions>), optionsMonitor)); services.AddSingleton <IConfigureBuilder <IConfigurationBuilder> >(_ => new DelegatedConfigureBuilder <IConfigurationBuilder>(c => { c.AddTestSettings(); configureAppConfiguration?.Invoke(c); })); configureServices?.Invoke(services); }) .AddScriptHostBuilder(webJobsBuilder => { var loggingBuilder = new LoggingBuilder(webJobsBuilder.Services); loggingBuilder.AddProvider(_loggerProvider); loggingBuilder.AddFilter <TestLoggerProvider>(_ => true); webJobsBuilder.AddAzureStorage(); configureJobHost?.Invoke(webJobsBuilder); }) .UseStartup <Startup>(); _testServer = new TestServer(builder); HttpClient = new HttpClient(new UpdateContentLengthHandler(_testServer.CreateHandler())); HttpClient.BaseAddress = new Uri("https://localhost/"); var manager = _testServer.Host.Services.GetService <IScriptHostManager>(); _hostService = manager as WebJobsScriptHostService; StartAsync().GetAwaiter().GetResult(); }
public void ReadFunctionMetadata_With_Retry_Succeeds() { string functionsPath = Path.Combine(Environment.CurrentDirectory, @"..\..\..\..\..\sample\noderetry"); _scriptApplicationHostOptions.ScriptPath = functionsPath; var optionsMonitor = TestHelpers.CreateOptionsMonitor(_scriptApplicationHostOptions); var metadataProvider = new FunctionMetadataProvider(optionsMonitor, NullLogger <FunctionMetadataProvider> .Instance, _testMetricsLogger); var workerConfigs = TestHelpers.GetTestWorkerConfigs(); var functionMetadatas = metadataProvider.GetFunctionMetadata(workerConfigs, false); Assert.Equal(2, functionMetadatas.Length); var functionMetadataWithRetry = functionMetadatas.Where(f => f.Name.Contains("HttpTrigger-RetryFunctionJson", StringComparison.OrdinalIgnoreCase)); Assert.Single(functionMetadataWithRetry); var retry = functionMetadataWithRetry.FirstOrDefault().Retry; Assert.NotNull(retry); Assert.Equal(RetryStrategy.FixedDelay, retry.Strategy); Assert.Equal(4, retry.MaxRetryCount); Assert.Equal(TimeSpan.Parse("00:00:03"), retry.DelayInterval); var functionMetadata = functionMetadatas.Where(f => !f.Name.Contains("HttpTrigger-RetryFunctionJson", StringComparison.OrdinalIgnoreCase)); Assert.Single(functionMetadataWithRetry); Assert.Null(functionMetadata.FirstOrDefault().Retry); }
public void ReadFunctionMetadata_For_WorkerIndexingFormatApp_Fails() { string functionsPath = Path.Combine(Environment.CurrentDirectory, @"..", "..", "..", "..", "..", "sample", "PythonWorkerIndexing"); _scriptApplicationHostOptions.ScriptPath = functionsPath; var optionsMonitor = TestHelpers.CreateOptionsMonitor(_scriptApplicationHostOptions); var metadataProvider = new HostFunctionMetadataProvider(optionsMonitor, NullLogger <HostFunctionMetadataProvider> .Instance, _testMetricsLogger); var workerConfigs = TestHelpers.GetTestWorkerConfigs(); Assert.Equal(0, metadataProvider.GetFunctionMetadataAsync(workerConfigs, SystemEnvironment.Instance, false).Result.Length); }
public void ReadFunctionMetadata_Succeeds() { string functionsPath = Path.Combine(Environment.CurrentDirectory, @"..\..\..\..\..\sample\node"); _scriptApplicationHostOptions.ScriptPath = functionsPath; var optionsMonitor = TestHelpers.CreateOptionsMonitor(_scriptApplicationHostOptions); var metadataProvider = new FunctionMetadataProvider(optionsMonitor, new OptionsWrapper <LanguageWorkerOptions>(_languageWorkerOptions), NullLogger <FunctionMetadataProvider> .Instance, _testMetricsLogger); Assert.Equal(17, metadataProvider.GetFunctionMetadata(false).Length); Assert.True(AreRequiredMetricsEmitted(_testMetricsLogger)); }
public void ReadFunctionMetadata_Succeeds() { string functionsPath = Path.Combine(Environment.CurrentDirectory, @"..", "..", "..", "..", "..", "sample", "node"); _scriptApplicationHostOptions.ScriptPath = functionsPath; var optionsMonitor = TestHelpers.CreateOptionsMonitor(_scriptApplicationHostOptions); var metadataProvider = new HostFunctionMetadataProvider(optionsMonitor, NullLogger <HostFunctionMetadataProvider> .Instance, _testMetricsLogger); var workerConfigs = TestHelpers.GetTestWorkerConfigs(); Assert.Equal(18, metadataProvider.GetFunctionMetadataAsync(workerConfigs, SystemEnvironment.Instance, false).Result.Length); Assert.True(AreRequiredMetricsEmitted(_testMetricsLogger)); }
public TestFixture() { // copy test files to temp directory, since accessing the metadata APIs will result // in file creations (for test data files) var scriptSource = Path.Combine(Environment.CurrentDirectory, "..", "..", "..", "TestScripts", "WarmupFunction"); _testHome = Path.Combine(Path.GetTempPath(), @"WarmupFunction"); var scriptRoot = Path.Combine(_testHome, "site", "wwwroot"); FileUtility.CopyDirectory(scriptSource, scriptRoot); HostOptions = new ScriptApplicationHostOptions { IsSelfHost = true, ScriptPath = scriptRoot, LogPath = Path.Combine(_testHome, "LogFiles", "Application", "Functions"), SecretsPath = Path.Combine(_testHome, "data", "Functions", "Secrets"), TestDataPath = Path.Combine(_testHome, "data", "Functions", "SampleData") }; FileUtility.EnsureDirectoryExists(HostOptions.TestDataPath); var optionsMonitor = TestHelpers.CreateOptionsMonitor(HostOptions); var workerOptions = new LanguageWorkerOptions { WorkerConfigs = TestHelpers.GetTestWorkerConfigs() }; var provider = new HostFunctionMetadataProvider(optionsMonitor, NullLogger <HostFunctionMetadataProvider> .Instance, new TestMetricsLogger()); var builder = AspNetCore.WebHost.CreateDefaultBuilder() .UseStartup <Startup>() .ConfigureServices(services => { services.Replace(new ServiceDescriptor(typeof(IOptions <ScriptApplicationHostOptions>), new OptionsWrapper <ScriptApplicationHostOptions>(HostOptions))); services.Replace(new ServiceDescriptor(typeof(ISecretManagerProvider), new TestSecretManagerProvider(new TestSecretManager()))); services.Replace(new ServiceDescriptor(typeof(IOptionsMonitor <ScriptApplicationHostOptions>), optionsMonitor)); services.Replace(new ServiceDescriptor(typeof(IFunctionMetadataProvider), provider)); services.SkipDependencyValidation(); }); // TODO: https://github.com/Azure/azure-functions-host/issues/4876 _testServer = new TestServer(builder); HostOptions.RootServiceProvider = _testServer.Host.Services; var scriptConfig = _testServer.Host.Services.GetService <IOptions <ScriptJobHostOptions> >().Value; HttpClient = _testServer.CreateClient(); HttpClient.BaseAddress = new Uri("https://localhost/"); TestHelpers.WaitForWebHost(HttpClient); }
public void ValidateFunctionName_ThrowsOnInvalidName(string functionName) { string functionsPath = "c:\testdir"; _scriptApplicationHostOptions.ScriptPath = functionsPath; var optionsMonitor = TestHelpers.CreateOptionsMonitor(_scriptApplicationHostOptions); var metadataProvider = new FunctionMetadataProvider(optionsMonitor, NullLogger <FunctionMetadataProvider> .Instance, _testMetricsLogger); var ex = Assert.Throws <InvalidOperationException>(() => { metadataProvider.ValidateName(functionName); }); Assert.Equal(string.Format("'{0}' is not a valid function name.", functionName), ex.Message); }
public void ValidateFunctionName_DoesNotThrowOnValidName(string functionName) { string functionsPath = "c:\testdir"; _scriptApplicationHostOptions.ScriptPath = functionsPath; var optionsMonitor = TestHelpers.CreateOptionsMonitor(_scriptApplicationHostOptions); var metadataProvider = new FunctionMetadataProvider(optionsMonitor, NullLogger <FunctionMetadataProvider> .Instance, _testMetricsLogger); try { metadataProvider.ValidateName(functionName); } catch (InvalidOperationException) { Assert.True(false, $"Valid function name {functionName} failed validation."); } }
public void ReadFunctionMetadata_Succeeds() { string functionsPath = Path.Combine(Environment.CurrentDirectory, @"..\..\..\..\..\sample\node"); var scriptApplicationHostOptions = new ScriptApplicationHostOptions() { ScriptPath = functionsPath }; var optionsMonitor = TestHelpers.CreateOptionsMonitor(scriptApplicationHostOptions); var workerOptions = new LanguageWorkerOptions { WorkerConfigs = TestHelpers.GetTestWorkerConfigs() }; var metadataProvider = new FunctionMetadataProvider(optionsMonitor, new OptionsWrapper <LanguageWorkerOptions>(workerOptions), NullLogger <FunctionMetadataProvider> .Instance); Assert.Equal(17, metadataProvider.GetFunctionMetadata(false).Length); }
public TestFixture() { // copy test files to temp directory, since accessing the metadata APIs will result // in file creations (for test data files) var scriptSource = Path.Combine(Environment.CurrentDirectory, @"..\..\..\TestScripts\Proxies"); _testHome = Path.Combine(Path.GetTempPath(), @"ProxyTests"); var scriptRoot = Path.Combine(_testHome, @"site\wwwroot"); FileUtility.CopyDirectory(scriptSource, scriptRoot); HostOptions = new ScriptApplicationHostOptions { IsSelfHost = true, ScriptPath = scriptRoot, LogPath = Path.Combine(_testHome, @"LogFiles\Application\Functions"), SecretsPath = Path.Combine(_testHome, @"data\Functions\Secrets"), TestDataPath = Path.Combine(_testHome, @"data\Functions\SampleData") }; FileUtility.EnsureDirectoryExists(HostOptions.TestDataPath); var optionsMonitor = TestHelpers.CreateOptionsMonitor(HostOptions); var builder = AspNetCore.WebHost.CreateDefaultBuilder() .UseStartup <Startup>() .ConfigureServices(services => { services.Replace(new ServiceDescriptor(typeof(IOptions <ScriptApplicationHostOptions>), new OptionsWrapper <ScriptApplicationHostOptions>(HostOptions))); services.Replace(new ServiceDescriptor(typeof(ISecretManagerProvider), new TestSecretManagerProvider(new TestSecretManager()))); services.Replace(new ServiceDescriptor(typeof(IOptionsMonitor <ScriptApplicationHostOptions>), optionsMonitor)); }); _testServer = new TestServer(builder); var scriptConfig = _testServer.Host.Services.GetService <IOptions <ScriptJobHostOptions> >().Value; HttpClient = _testServer.CreateClient(); HttpClient.BaseAddress = new Uri("https://localhost/"); TestHelpers.WaitForWebHost(HttpClient); }
public TestFunctionHost(string scriptPath, string logPath, Action <IServiceCollection> configureWebHostServices = null, Action <IWebJobsBuilder> configureScriptHostWebJobsBuilder = null, Action <IConfigurationBuilder> configureScriptHostAppConfiguration = null, Action <ILoggingBuilder> configureScriptHostLogging = null, Action <IServiceCollection> configureScriptHostServices = null) { _appRoot = scriptPath; _hostOptions = new ScriptApplicationHostOptions { IsSelfHost = true, ScriptPath = _appRoot, LogPath = logPath, SecretsPath = Environment.CurrentDirectory, // not used HasParentScope = true }; var optionsMonitor = TestHelpers.CreateOptionsMonitor(_hostOptions); var serviceProvider = new TestServiceProvider(_hostOptions, optionsMonitor); _hostOptions.RootServiceProvider = serviceProvider; var builder = new WebHostBuilder() .ConfigureLogging(b => { b.AddProvider(_webHostLoggerProvider); }) .ConfigureServices(services => { services.Replace(new ServiceDescriptor(typeof(ISecretManagerProvider), new TestSecretManagerProvider(new TestSecretManager()))); services.Replace(ServiceDescriptor.Singleton <IServiceProviderFactory <IServiceCollection> >(new WebHostServiceProviderFactory())); services.Replace(new ServiceDescriptor(typeof(IOptions <ScriptApplicationHostOptions>), new OptionsWrapper <ScriptApplicationHostOptions>(_hostOptions))); services.Replace(new ServiceDescriptor(typeof(IOptionsMonitor <ScriptApplicationHostOptions>), optionsMonitor)); services.Replace(new ServiceDescriptor(typeof(IExtensionBundleManager), new TestExtensionBundleManager())); // Allows us to configure services as the last step, thereby overriding anything services.AddSingleton(new PostConfigureServices(configureWebHostServices)); }) .ConfigureScriptHostWebJobsBuilder(scriptHostWebJobsBuilder => { scriptHostWebJobsBuilder.AddAzureStorage(); configureScriptHostWebJobsBuilder?.Invoke(scriptHostWebJobsBuilder); }) .ConfigureScriptHostAppConfiguration(scriptHostConfigurationBuilder => { scriptHostConfigurationBuilder.AddTestSettings(); configureScriptHostAppConfiguration?.Invoke(scriptHostConfigurationBuilder); }) .ConfigureScriptHostLogging(scriptHostLoggingBuilder => { scriptHostLoggingBuilder.AddProvider(_scriptHostLoggerProvider); scriptHostLoggingBuilder.AddFilter <TestLoggerProvider>(_ => true); configureScriptHostLogging?.Invoke(scriptHostLoggingBuilder); }) .ConfigureScriptHostServices(scriptHostServices => { configureScriptHostServices?.Invoke(scriptHostServices); }) .UseStartup <TestStartup>(); _testServer = new TestServer(builder); HttpClient = new HttpClient(new UpdateContentLengthHandler(_testServer.CreateHandler())) { BaseAddress = new Uri("https://localhost/") }; var manager = _testServer.Host.Services.GetService <IScriptHostManager>(); _hostService = manager as WebJobsScriptHostService; StartAsync().GetAwaiter().GetResult(); }
public TestFunctionHost(string scriptPath, string logPath, Action <IServiceCollection> configureWebHostServices = null, Action <IWebJobsBuilder> configureScriptHostWebJobsBuilder = null, Action <IConfigurationBuilder> configureScriptHostAppConfiguration = null, Action <ILoggingBuilder> configureScriptHostLogging = null, Action <IServiceCollection> configureScriptHostServices = null) { _appRoot = scriptPath; _hostOptions = new ScriptApplicationHostOptions { IsSelfHost = true, ScriptPath = _appRoot, LogPath = logPath, SecretsPath = Environment.CurrentDirectory, // not used HasParentScope = true }; var builder = new WebHostBuilder() .ConfigureLogging(b => { b.AddProvider(_webHostLoggerProvider); }) .ConfigureServices(services => { services.Replace(new ServiceDescriptor(typeof(ISecretManagerProvider), new TestSecretManagerProvider(new TestSecretManager()))); services.Replace(ServiceDescriptor.Singleton <IServiceProviderFactory <IServiceCollection> >(new WebHostServiceProviderFactory())); services.Replace(new ServiceDescriptor(typeof(IOptions <ScriptApplicationHostOptions>), sp => { _hostOptions.RootServiceProvider = sp; return(new OptionsWrapper <ScriptApplicationHostOptions>(_hostOptions)); }, ServiceLifetime.Singleton)); services.Replace(new ServiceDescriptor(typeof(IOptionsMonitor <ScriptApplicationHostOptions>), sp => { _hostOptions.RootServiceProvider = sp; return(TestHelpers.CreateOptionsMonitor(_hostOptions)); }, ServiceLifetime.Singleton)); services.Replace(new ServiceDescriptor(typeof(IExtensionBundleManager), new TestExtensionBundleManager())); services.Replace(new ServiceDescriptor(typeof(IFunctionMetadataManager), sp => { var montior = sp.GetService <IOptionsMonitor <ScriptApplicationHostOptions> >(); var scriptManager = sp.GetService <IScriptHostManager>(); var loggerFactory = sp.GetService <ILoggerFactory>(); return(GetMetadataManager(montior, scriptManager, loggerFactory)); }, ServiceLifetime.Singleton)); // Allows us to configure services as the last step, thereby overriding anything services.AddSingleton(new PostConfigureServices(configureWebHostServices)); }) .ConfigureScriptHostWebJobsBuilder(scriptHostWebJobsBuilder => { scriptHostWebJobsBuilder.AddAzureStorage(); configureScriptHostWebJobsBuilder?.Invoke(scriptHostWebJobsBuilder); }) .ConfigureScriptHostAppConfiguration(scriptHostConfigurationBuilder => { scriptHostConfigurationBuilder.AddTestSettings(); configureScriptHostAppConfiguration?.Invoke(scriptHostConfigurationBuilder); }) .ConfigureScriptHostLogging(scriptHostLoggingBuilder => { scriptHostLoggingBuilder.AddProvider(_scriptHostLoggerProvider); scriptHostLoggingBuilder.AddFilter <TestLoggerProvider>(_ => true); configureScriptHostLogging?.Invoke(scriptHostLoggingBuilder); }) .ConfigureScriptHostServices(scriptHostServices => { configureScriptHostServices?.Invoke(scriptHostServices); }) .UseStartup <TestStartup>(); _testServer = new TestServer(builder) { BaseAddress = new Uri("https://localhost/") }; HttpClient = _testServer.CreateClient(); var manager = _testServer.Host.Services.GetService <IScriptHostManager>(); _hostService = manager as WebJobsScriptHostService; // Wire up StopApplication calls as they behave in hosted scenarios var lifetime = WebHostServices.GetService <IApplicationLifetime>(); lifetime.ApplicationStopping.Register(async() => await _testServer.Host.StopAsync()); StartAsync().GetAwaiter().GetResult(); }
public TestFunctionHost(string scriptPath, string logPath, Action <IServiceCollection> configureWebHostServices = null, Action <IWebJobsBuilder> configureScriptHostWebJobsBuilder = null, Action <IConfigurationBuilder> configureScriptHostAppConfiguration = null, Action <ILoggingBuilder> configureScriptHostLogging = null, Action <IServiceCollection> configureScriptHostServices = null) { _appRoot = scriptPath; _hostOptions = new ScriptApplicationHostOptions { IsSelfHost = true, ScriptPath = _appRoot, LogPath = logPath, SecretsPath = Environment.CurrentDirectory, // not used HasParentScope = true }; var builder = new WebHostBuilder() .ConfigureLogging(b => { b.AddProvider(_webHostLoggerProvider); }) .ConfigureServices(services => { services.Replace(new ServiceDescriptor(typeof(ISecretManagerProvider), new TestSecretManagerProvider(new TestSecretManager()))); services.Replace(ServiceDescriptor.Singleton <IServiceProviderFactory <IServiceCollection> >(new WebHostServiceProviderFactory())); services.Replace(new ServiceDescriptor(typeof(IOptions <ScriptApplicationHostOptions>), sp => { _hostOptions.RootServiceProvider = sp; return(new OptionsWrapper <ScriptApplicationHostOptions>(_hostOptions)); }, ServiceLifetime.Singleton)); services.Replace(new ServiceDescriptor(typeof(IOptionsMonitor <ScriptApplicationHostOptions>), sp => { _hostOptions.RootServiceProvider = sp; return(TestHelpers.CreateOptionsMonitor(_hostOptions)); }, ServiceLifetime.Singleton)); services.Replace(new ServiceDescriptor(typeof(IExtensionBundleManager), new TestExtensionBundleManager())); services.Replace(new ServiceDescriptor(typeof(IFunctionMetadataManager), sp => { var montior = sp.GetService <IOptionsMonitor <ScriptApplicationHostOptions> >(); var scriptManager = sp.GetService <IScriptHostManager>(); var loggerFactory = sp.GetService <ILoggerFactory>(); var environment = sp.GetService <IEnvironment>(); return(GetMetadataManager(montior, scriptManager, loggerFactory, environment)); }, ServiceLifetime.Singleton)); services.SkipDependencyValidation(); // Allows us to configure services as the last step, thereby overriding anything services.AddSingleton(new PostConfigureServices(configureWebHostServices)); }) .ConfigureScriptHostWebJobsBuilder(scriptHostWebJobsBuilder => { /// REVIEW THIS scriptHostWebJobsBuilder.AddAzureStorage(); configureScriptHostWebJobsBuilder?.Invoke(scriptHostWebJobsBuilder); }) .ConfigureScriptHostAppConfiguration(scriptHostConfigurationBuilder => { scriptHostConfigurationBuilder.AddTestSettings(); configureScriptHostAppConfiguration?.Invoke(scriptHostConfigurationBuilder); }) .ConfigureScriptHostLogging(scriptHostLoggingBuilder => { scriptHostLoggingBuilder.AddProvider(_scriptHostLoggerProvider); scriptHostLoggingBuilder.AddFilter <TestLoggerProvider>(_ => true); configureScriptHostLogging?.Invoke(scriptHostLoggingBuilder); }) .ConfigureScriptHostServices(scriptHostServices => { configureScriptHostServices?.Invoke(scriptHostServices); }) .ConfigureAppConfiguration((builderContext, config) => { // replace the default environment source with our own IConfigurationSource envVarsSource = config.Sources.OfType <EnvironmentVariablesConfigurationSource>().FirstOrDefault(); if (envVarsSource != null) { config.Sources.Remove(envVarsSource); } config.Add(new ScriptEnvironmentVariablesConfigurationSource()); config.AddTestSettings(); }) .UseStartup <TestStartup>(); _testServer = new TestServer(builder) { BaseAddress = new Uri("https://localhost/") }; HttpClient = _testServer.CreateClient(); HttpClient.Timeout = TimeSpan.FromMinutes(5); var manager = _testServer.Host.Services.GetService <IScriptHostManager>(); _hostService = manager as WebJobsScriptHostService; // Wire up StopApplication calls as they behave in hosted scenarios var lifetime = WebHostServices.GetService <IApplicationLifetime>(); lifetime.ApplicationStopping.Register(async() => await _testServer.Host.StopAsync()); StartAsync().GetAwaiter().GetResult(); _stillRunningTimer = new Timer(StillRunningCallback, _testServer, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30)); // store off a bit of the creation stack for easier debugging if this host doesn't shut down. var stack = new StackTrace(true).ToString().Split(Environment.NewLine).Take(5); _createdStack = string.Join($"{Environment.NewLine} ", stack); // cache startup logs since tests clear logs from time to time StartupLogs = GetScriptHostLogMessages(); }