public void Initialize_PerformsExpectedRegistrations() { JobHostConfiguration config = new JobHostConfiguration(); config.AddService<INameResolver>(new RandomNameResolver()); ServiceBusConfiguration serviceBusConfig = new ServiceBusConfiguration(); ServiceBusExtensionConfig serviceBusExtensionConfig = new ServiceBusExtensionConfig(serviceBusConfig); IExtensionRegistry extensions = config.GetService<IExtensionRegistry>(); ITriggerBindingProvider[] triggerBindingProviders = extensions.GetExtensions<ITriggerBindingProvider>().ToArray(); Assert.Equal(0, triggerBindingProviders.Length); IBindingProvider[] bindingProviders = extensions.GetExtensions<IBindingProvider>().ToArray(); Assert.Equal(0, bindingProviders.Length); ExtensionConfigContext context = new ExtensionConfigContext { Config = config, Trace = new TestTraceWriter(TraceLevel.Verbose) }; serviceBusExtensionConfig.Initialize(context); // ensure the ServiceBusTriggerAttributeBindingProvider was registered triggerBindingProviders = extensions.GetExtensions<ITriggerBindingProvider>().ToArray(); Assert.Equal(1, triggerBindingProviders.Length); ServiceBusTriggerAttributeBindingProvider triggerBindingProvider = (ServiceBusTriggerAttributeBindingProvider)triggerBindingProviders[0]; Assert.NotNull(triggerBindingProvider); // ensure the ServiceBusAttributeBindingProvider was registered bindingProviders = extensions.GetExtensions<IBindingProvider>().ToArray(); Assert.Equal(1, bindingProviders.Length); ServiceBusAttributeBindingProvider bindingProvider = (ServiceBusAttributeBindingProvider)bindingProviders[0]; Assert.NotNull(bindingProvider); }
public static JobHost GetJobHost(ILoggerFactory loggerFactory, string taskHub = "CommonTestHub", string eventGridKeySettingName = null, string eventGridKeyValue = null, string eventGridTopicEndpoint = null) { var config = new JobHostConfiguration { HostId = "durable-task-host" }; config.ConfigureDurableFunctionTypeLocator(typeof(TestOrchestrations), typeof(TestActivities)); config.UseDurableTask(new DurableTaskExtension { HubName = taskHub.Replace("_", ""), TraceInputsAndOutputs = true, EventGridKeySettingName = eventGridKeySettingName, EventGridTopicEndpoint = eventGridTopicEndpoint, }); // Mock INameResolver for not setting EnvironmentVariables. if (eventGridKeyValue != null) { config.AddService <INameResolver>(new MockNameResolver(eventGridKeyValue)); } // Performance is *significantly* worse when dashboard logging is enabled, at least // when running in the storage emulator. Disabling to keep tests running quickly. config.DashboardConnectionString = null; // Add test logger config.LoggerFactory = loggerFactory; var host = new JobHost(config); return(host); }
public void JobHost_NoStorage_Succeeds() { using (EnvVarHolder.Set("AzureWebJobsStorage", null)) using (EnvVarHolder.Set("AzureWebJobsDashboard", null)) { JobHostConfiguration config = new JobHostConfiguration() { TypeLocator = new FakeTypeLocator(typeof(BasicTest)) }; Assert.Null(config.InternalStorageConfiguration); // Explicitly disalbe storage. config.HostId = Guid.NewGuid().ToString("n"); config.DashboardConnectionString = null; config.StorageConnectionString = null; var randomValue = Guid.NewGuid().ToString(); StringBuilder sbLoggingCallbacks = new StringBuilder(); var fastLogger = new FastLogger(); config.AddService <IAsyncCollector <FunctionInstanceLogEntry> >(fastLogger); JobHost host = new JobHost(config); // Manually invoked. var method = typeof(BasicTest).GetMethod("Method", BindingFlags.Public | BindingFlags.Static); host.Call(method, new { value = randomValue }); Assert.True(BasicTest.Called); Assert.Equal(2, fastLogger.List.Count); // We should be batching, so flush not called yet. host.Start(); // required to call stop() host.Stop(); // will ensure flush is called. // Verify fast logs Assert.Equal(3, fastLogger.List.Count); var startMsg = fastLogger.List[0]; Assert.Equal("BasicTest.Method", startMsg.FunctionName); Assert.Equal(null, startMsg.EndTime); Assert.NotNull(startMsg.StartTime); var endMsg = fastLogger.List[1]; Assert.Equal(startMsg.FunctionName, endMsg.FunctionName); Assert.Equal(startMsg.StartTime, endMsg.StartTime); Assert.Equal(startMsg.FunctionInstanceId, endMsg.FunctionInstanceId); Assert.NotNull(endMsg.EndTime); // signal completed Assert.True(endMsg.StartTime <= endMsg.EndTime); Assert.Null(endMsg.ErrorDetails); Assert.Null(endMsg.ParentId); Assert.Equal(2, endMsg.Arguments.Count); Assert.True(endMsg.Arguments.ContainsKey("log")); Assert.Equal(randomValue, endMsg.Arguments["value"]); Assert.Equal("val=" + randomValue, endMsg.LogOutput.Trim()); Assert.Same(FastLogger.FlushEntry, fastLogger.List[2]); } }
public async Task Initialize_PerformsExpectedRegistrations() { JobHostConfiguration config = new JobHostConfiguration(); config.AddService <INameResolver>(new RandomNameResolver()); TestLoggerProvider loggerProvider = new TestLoggerProvider(); ILoggerFactory loggerFactory = new LoggerFactory(); loggerFactory.AddProvider(loggerProvider); config.LoggerFactory = loggerFactory; ServiceBusConfiguration serviceBusConfig = new ServiceBusConfiguration(); ServiceBusExtensionConfig serviceBusExtensionConfig = new ServiceBusExtensionConfig(serviceBusConfig); IExtensionRegistry extensions = config.GetService <IExtensionRegistry>(); ITriggerBindingProvider[] triggerBindingProviders = extensions.GetExtensions <ITriggerBindingProvider>().ToArray(); Assert.Empty(triggerBindingProviders); IBindingProvider[] bindingProviders = extensions.GetExtensions <IBindingProvider>().ToArray(); Assert.Empty(bindingProviders); ExtensionConfigContext context = new ExtensionConfigContext { Config = config, }; serviceBusExtensionConfig.Initialize(context); // ensure the ServiceBusTriggerAttributeBindingProvider was registered triggerBindingProviders = extensions.GetExtensions <ITriggerBindingProvider>().ToArray(); Assert.Single(triggerBindingProviders); ServiceBusTriggerAttributeBindingProvider triggerBindingProvider = (ServiceBusTriggerAttributeBindingProvider)triggerBindingProviders[0]; Assert.NotNull(triggerBindingProvider); // ensure the ServiceBusAttributeBindingProvider was registered bindingProviders = extensions.GetExtensions <IBindingProvider>().ToArray(); Assert.Single(bindingProviders); ServiceBusAttributeBindingProvider bindingProvider = (ServiceBusAttributeBindingProvider)bindingProviders[0]; Assert.NotNull(bindingProvider); // ensure the default MessageOptions exception handler is wired up var messageOptions = serviceBusConfig.MessageOptions; var ex = new ServiceBusException(false); var args = new ExceptionReceivedEventArgs(ex, "TestAction", "TestEndpoint", "TestEntityPath", "TestClientId"); Assert.NotNull(serviceBusConfig.ExceptionHandler); // invoke the handler and make sure it logs await serviceBusConfig.MessageOptions.ExceptionReceivedHandler(args); string expectedMessage = "MessageReceiver error (Action=TestAction, ClientId=TestClientId, EntityPath=TestEntityPath, Endpoint=TestEndpoint)"; var logMessage = loggerProvider.GetAllLogMessages().Single(); Assert.Equal(LogLevel.Error, logMessage.Level); Assert.Equal(expectedMessage, logMessage.FormattedMessage); Assert.Same(ex, logMessage.Exception); }
public async Task FunctionLevelErrorHandler_InvokedAsExpected() { ErrorTriggerProgram_FunctionLevelHandler instance = new ErrorTriggerProgram_FunctionLevelHandler(); JobHostConfiguration config = new JobHostConfiguration() { TypeLocator = new ExplicitTypeLocator(instance.GetType()), JobActivator = new ExplicitJobActivator(instance) }; config.UseCore(); config.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); JobHost host = new JobHost(config); await host.StartAsync(); MethodInfo method = instance.GetType().GetMethod("ThrowA"); await CallSafe(host, method); await CallSafe(host, method); Assert.Null(instance.TraceFilter); method = instance.GetType().GetMethod("ThrowB"); await CallSafe(host, method); Assert.Equal("Function 'ErrorTriggerProgram_FunctionLevelHandler.ThrowB' failed.", instance.TraceFilter.Message); Assert.Equal(1, instance.TraceFilter.GetEvents().Count()); }
public AsyncChainEndToEndTests(TestFixture fixture) { _fixture = fixture; _resolver = new RandomNameResolver(); _hostConfig = new JobHostConfiguration() { NameResolver = _resolver, TypeLocator = new FakeTypeLocator(typeof(AsyncChainEndToEndTests)) }; _defaultExceptionHandler = new TestExceptionHandler(); _hostConfig.AddService <IWebJobsExceptionHandler>(_defaultExceptionHandler); _hostConfig.Queues.MaxPollingInterval = TimeSpan.FromSeconds(2); _storageAccount = fixture.StorageAccount; _timeoutJobDelay = TimeSpan.FromMinutes(5); ILoggerFactory loggerFactory = new LoggerFactory(); loggerFactory.AddProvider(_loggerProvider); _hostConfig.LoggerFactory = loggerFactory; _hostConfig.Aggregator.IsEnabled = false; // makes validation easier CloudQueueClient queueClient = _storageAccount.CreateCloudQueueClient(); string queueName = _resolver.ResolveInString(TestQueueName); _testQueue = queueClient.GetQueueReference(queueName); if (!_testQueue.CreateIfNotExistsAsync().Result) { _testQueue.ClearAsync().Wait(); } }
protected override void OnInitializeConfig(JobHostConfiguration config) { base.OnInitializeConfig(config); // Add our WebHost specific services config.AddService <IMetricsLogger>(_metricsLogger); }
private JobHost CreateTestJobHost(int hostId) { TestJobActivator activator = new TestJobActivator(hostId); JobHostConfiguration config = new JobHostConfiguration { HostId = TestHostId, NameResolver = _resolver, TypeLocator = new FakeTypeLocator(typeof(TestJobs)), JobActivator = activator }; config.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); config.Queues.MaxPollingInterval = TimeSpan.FromSeconds(2); config.Singleton.LockAcquisitionTimeout = TimeSpan.FromSeconds(10); config.Singleton.LockAcquisitionPollingInterval = TimeSpan.FromMilliseconds(500); IExtensionRegistry registry = config.GetService <IExtensionRegistry>(); registry.RegisterExtension <ITriggerBindingProvider>(new TestTriggerAttributeBindingProvider()); JobHost host = new JobHost(config); return(host); }
private async Task RunTimerJobTest(Type jobClassType, Func <bool> condition) { TestTraceWriter testTrace = new TestTraceWriter(TraceLevel.Error); ExplicitTypeLocator locator = new ExplicitTypeLocator(jobClassType); JobHostConfiguration config = new JobHostConfiguration { TypeLocator = locator }; config.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); config.UseTimers(); config.Tracing.Tracers.Add(testTrace); JobHost host = new JobHost(config); await host.StartAsync(); await TestHelpers.Await(() => { return(condition()); }); await host.StopAsync(); // ensure there were no errors Assert.Equal(0, testTrace.Events.Count); }
public async Task FunctionLevelErrorHandler_SlidingWindow_InvokedAsExpected() { ErrorTriggerProgram_FunctionLevelHandler_SlidingWindow instance = new ErrorTriggerProgram_FunctionLevelHandler_SlidingWindow(); JobHostConfiguration config = new JobHostConfiguration() { TypeLocator = new ExplicitTypeLocator(instance.GetType()), JobActivator = new ExplicitJobActivator(instance) }; config.UseCore(); config.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); JobHost host = new JobHost(config); await host.StartAsync(); MethodInfo method = instance.GetType().GetMethod("Throw"); await CallSafe(host, method); await CallSafe(host, method); Assert.Null(instance.TraceFilter); await CallSafe(host, method); IEnumerable <TraceEvent> events = instance.TraceFilter.GetEvents(); Assert.Equal(3, events.Count()); Assert.Equal("3 events at level 'Error' or lower have occurred within time window 00:10:00.", instance.TraceFilter.Message); Assert.True(events.All(p => p.Message == "Exception while executing function: ErrorTriggerProgram_FunctionLevelHandler_SlidingWindow.Throw")); }
private async Task RunTimerJobTest(Type jobClassType, Func <bool> condition) { ExplicitTypeLocator locator = new ExplicitTypeLocator(jobClassType); JobHostConfiguration config = new JobHostConfiguration { TypeLocator = locator }; ILoggerFactory loggerFactory = new LoggerFactory(); TestLoggerProvider provider = new TestLoggerProvider(); loggerFactory.AddProvider(provider); config.LoggerFactory = loggerFactory; config.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); config.UseTimers(); JobHost host = new JobHost(config); await host.StartAsync(); await TestHelpers.Await(() => { return(condition()); }); await host.StopAsync(); // TODO: ensure there were no errors }
public async Task ApplicationInsights_SuccessfulFunction() { string testName = nameof(TestApplicationInsightsInformation); LogCategoryFilter filter = new LogCategoryFilter(); filter.DefaultLevel = LogLevel.Information; var loggerFactory = new LoggerFactory() .AddApplicationInsights( new TestTelemetryClientFactory(filter.Filter, _channel)); JobHostConfiguration config = new JobHostConfiguration { LoggerFactory = loggerFactory, TypeLocator = new FakeTypeLocator(GetType()), }; config.Aggregator.IsEnabled = false; config.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); using (JobHost host = new JobHost(config)) { await host.StartAsync(); var methodInfo = GetType().GetMethod(testName, BindingFlags.Public | BindingFlags.Static); await host.CallAsync(methodInfo, new { input = "function input" }); await host.StopAsync(); } Assert.Equal(7, _channel.Telemetries.Count); // Validate the traces. Order by message string as the requests may come in // slightly out-of-order or on different threads TraceTelemetry[] telemetries = _channel.Telemetries .OfType <TraceTelemetry>() .OrderBy(t => t.Message) .ToArray(); ValidateTrace(telemetries[0], "Found the following functions:\r\n", LogCategories.Startup); ValidateTrace(telemetries[1], "Job host started", LogCategories.Startup); ValidateTrace(telemetries[2], "Job host stopped", LogCategories.Startup); ValidateTrace(telemetries[3], "Logger", LogCategories.Function, testName, hasCustomScope: true); ValidateTrace(telemetries[4], "Trace", LogCategories.Function, testName); // We should have 1 custom metric. MetricTelemetry metric = _channel.Telemetries .OfType <MetricTelemetry>() .Single(); ValidateMetric(metric, testName); // Finally, validate the request RequestTelemetry request = _channel.Telemetries .OfType <RequestTelemetry>() .Single(); ValidateRequest(request, testName, true); }
protected override void OnInitializeConfig(JobHostConfiguration config) { base.OnInitializeConfig(config); // Add our WebHost specific services config.AddService <IMetricsLogger>(_metricsLogger); // Register the new "FastLogger" for Dashboard support var dashboardString = AmbientConnectionStringProvider.Instance.GetConnectionString(ConnectionStringNames.Dashboard); if (dashboardString != null) { var fastLogger = new FastLogger(dashboardString); config.AddService <IAsyncCollector <FunctionInstanceLogEntry> >(fastLogger); } config.DashboardConnectionString = null; // disable slow logging }
public static ITestHost CreateJobHost( IOptions <DurableTaskOptions> options, string storageProvider, ILoggerProvider loggerProvider, INameResolver nameResolver, IDurableHttpMessageHandlerFactory durableHttpMessageHandler, ILifeCycleNotificationHelper lifeCycleNotificationHelper, IMessageSerializerSettingsFactory serializerSettingsFactory, IApplicationLifetimeWrapper shutdownNotificationService = null, Action <ITelemetry> onSend = null) { var config = new JobHostConfiguration { HostId = "durable-task-host" }; config.TypeLocator = TestHelpers.GetTypeLocator(); var connectionResolver = new WebJobsConnectionStringProvider(); var loggerFactory = new LoggerFactory(); loggerFactory.AddProvider(loggerProvider); IDurabilityProviderFactory orchestrationServiceFactory = new AzureStorageDurabilityProviderFactory( options, connectionResolver, nameResolver, loggerFactory); var extension = new DurableTaskExtension( options, loggerFactory, nameResolver, orchestrationServiceFactory, shutdownNotificationService ?? new TestHostShutdownNotificationService(), durableHttpMessageHandler, lifeCycleNotificationHelper, serializerSettingsFactory); config.UseDurableTask(extension); // Mock INameResolver for not setting EnvironmentVariables. if (nameResolver != null) { config.AddService(nameResolver); } // Performance is *significantly* worse when dashboard logging is enabled, at least // when running in the storage emulator. Disabling to keep tests running quickly. config.DashboardConnectionString = null; // Add test logger config.LoggerFactory = loggerFactory; var host = new JobHost(config); return(new FunctionsV1HostWrapper(host, options, connectionResolver)); }
public void AddService_ReplacesExistingService() { JobHostConfiguration configuration = new JobHostConfiguration(); IComparable service = "test1"; configuration.AddService <IComparable>(service); IComparable result = configuration.GetService <IComparable>(); Assert.Same(service, result); IComparable service2 = "test2"; configuration.AddService <IComparable>(service2); result = configuration.GetService <IComparable>(); Assert.Same(service2, result); }
public void IndexingExceptions_CanBeHandledByLogger() { JobHostConfiguration config = new JobHostConfiguration(); config.TypeLocator = new FakeTypeLocator(typeof(BindingErrorsProgram)); FunctionErrorLogger errorLogger = new FunctionErrorLogger("TestCategory"); config.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); Mock <ILoggerProvider> mockProvider = new Mock <ILoggerProvider>(MockBehavior.Strict); mockProvider .Setup(m => m.CreateLogger(It.IsAny <string>())) .Returns(errorLogger); ILoggerFactory factory = new LoggerFactory(); factory.AddProvider(mockProvider.Object); config.LoggerFactory = factory; JobHost host = new JobHost(config); host.Start(); // verify the handled binding error FunctionIndexingException fex = errorLogger.Errors.SingleOrDefault() as FunctionIndexingException; Assert.True(fex.Handled); Assert.Equal("BindingErrorsProgram.Invalid", fex.MethodName); // verify that the binding error was logged var messages = errorLogger.GetLogMessages(); Assert.Equal(5, messages.Count); LogMessage logMessage = messages.ElementAt(0); Assert.Equal("Error indexing method 'BindingErrorsProgram.Invalid'", logMessage.FormattedMessage); Assert.Same(fex, logMessage.Exception); Assert.Equal("Invalid container name: invalid$=+1", logMessage.Exception.InnerException.Message); logMessage = messages.ElementAt(1); Assert.Equal("Function 'BindingErrorsProgram.Invalid' failed indexing and will be disabled.", logMessage.FormattedMessage); Assert.Equal(Extensions.Logging.LogLevel.Warning, logMessage.Level); // verify that the valid function was still indexed logMessage = messages.ElementAt(2); Assert.True(logMessage.FormattedMessage.Contains("Found the following functions")); Assert.True(logMessage.FormattedMessage.Contains("BindingErrorsProgram.Valid")); // verify that the job host was started successfully logMessage = messages.ElementAt(4); Assert.Equal("Job host started", logMessage.FormattedMessage); host.Stop(); host.Dispose(); }
public void AddService_ThrowsArgumentNull_WhenServiceTypeIsNull() { JobHostConfiguration configuration = new JobHostConfiguration(); ArgumentNullException exception = Assert.Throws <ArgumentNullException>( () => configuration.AddService(null, "test1") ); Assert.Equal("serviceType", exception.ParamName); }
public void AddService_ThrowsArgumentOutOfRange_WhenInstanceNotInstanceOfType() { JobHostConfiguration configuration = new JobHostConfiguration(); ArgumentOutOfRangeException exception = Assert.Throws <ArgumentOutOfRangeException>( () => configuration.AddService(typeof(IComparable), new object()) ); Assert.Equal("serviceInstance", exception.ParamName); }
private JobHostConfiguration CreateConfig(bool addFactory = true) { IStorageAccountProvider accountProvider = new FakeStorageAccountProvider() { StorageAccount = new FakeStorageAccount() }; ILoggerFactory factory = new LoggerFactory(); factory.AddProvider(_loggerProvider); var config = new JobHostConfiguration(); config.AddService(accountProvider); config.TypeLocator = new FakeTypeLocator(new[] { typeof(ILoggerFunctions) }); config.AddService(factory); config.Aggregator.IsEnabled = false; // disable aggregator return(config); }
public static IConverterManager GetOrCreateConverterManager(this JobHostConfiguration config) { IConverterManager cm = config.GetService <IConverterManager>(); if (cm == null) { cm = new ConverterManager(); config.AddService <IConverterManager>(cm); } return(cm); }
public void AddService_AddsNewService() { JobHostConfiguration configuration = new JobHostConfiguration(); IComparable service = "test1"; configuration.AddService <IComparable>(service); IComparable result = configuration.GetService <IComparable>(); Assert.Same(service, result); }
public HttpTriggerEndToEndTests() { var httpConfig = new HttpExtensionConfiguration(); httpConfig.SetResponse = SetResultHook; _config = new JobHostConfiguration { TypeLocator = new ExplicitTypeLocator(typeof(TestFunctions)) }; _config.UseHttp(httpConfig); _config.UseHttp(); _config.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); _host = new JobHost(_config); }
public void Initialize_PerformsExpectedRegistrations() { JobHostConfiguration config = new JobHostConfiguration(); config.AddService <INameResolver>(new RandomNameResolver()); TestLoggerProvider loggerProvider = new TestLoggerProvider(); ILoggerFactory loggerFactory = new LoggerFactory(); loggerFactory.AddProvider(loggerProvider); config.LoggerFactory = loggerFactory; EventHubConfiguration eventHubConfiguration = new EventHubConfiguration(); IExtensionRegistry extensions = config.GetService <IExtensionRegistry>(); ITriggerBindingProvider[] triggerBindingProviders = extensions.GetExtensions <ITriggerBindingProvider>().ToArray(); Assert.Empty(triggerBindingProviders); IBindingProvider[] bindingProviders = extensions.GetExtensions <IBindingProvider>().ToArray(); Assert.Empty(bindingProviders); ExtensionConfigContext context = new ExtensionConfigContext { Config = config, }; ((IExtensionConfigProvider)eventHubConfiguration).Initialize(context); // ensure the EventHubTriggerAttributeBindingProvider was registered triggerBindingProviders = extensions.GetExtensions <ITriggerBindingProvider>().ToArray(); EventHubTriggerAttributeBindingProvider triggerBindingProvider = (EventHubTriggerAttributeBindingProvider)triggerBindingProviders.Single(); Assert.NotNull(triggerBindingProvider); // ensure the EventProcessorOptions ExceptionReceived event is wired up var eventProcessorOptions = eventHubConfiguration.EventProcessorOptions; var ex = new EventHubsException(false, "Kaboom!"); var ctor = typeof(ExceptionReceivedEventArgs).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).Single(); var args = (ExceptionReceivedEventArgs)ctor.Invoke(new object[] { "TestHostName", "TestPartitionId", ex, "TestAction" }); var handler = (Action <ExceptionReceivedEventArgs>)eventProcessorOptions.GetType().GetField("exceptionHandler", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(eventProcessorOptions); handler.Method.Invoke(handler.Target, new object[] { args }); string expectedMessage = "EventProcessorHost error (Action=TestAction, HostName=TestHostName, PartitionId=TestPartitionId)"; var logMessage = loggerProvider.GetAllLogMessages().Single(); Assert.Equal(LogLevel.Error, logMessage.Level); Assert.Equal(expectedMessage, logMessage.FormattedMessage); Assert.Same(ex, logMessage.Exception); }
public JobHostConfiguration NewConfig <TProgram>(TProgram program, params object[] services) { JobHostConfiguration config = new JobHostConfiguration(); var activator = new FakeActivator(); activator.Add(program); config.TypeLocator = new FakeTypeLocator(typeof(TProgram)); config.JobActivator = activator; config.AddServices(services); config.AddServices(_nameResolver); config.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); return(config); }
public async Task MaxDegreeOfParallelism_Queues(int batchSize, int maxExpectedParallelism) { _receivedMessages = 0; _currentSimultaneouslyRunningFunctions = 0; _maxSimultaneouslyRunningFunctions = 0; _numberOfQueueMessages = batchSize * 3; RandomNameResolver nameResolver = new RandomNameResolver(); JobHostConfiguration hostConfiguration = new JobHostConfiguration() { NameResolver = nameResolver, TypeLocator = new FakeTypeLocator(typeof(ParallelExecutionTests)), }; hostConfiguration.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); hostConfiguration.Queues.BatchSize = batchSize; CloudStorageAccount storageAccount = CloudStorageAccount.Parse(hostConfiguration.StorageConnectionString); _queueClient = storageAccount.CreateCloudQueueClient(); CloudQueue queue = _queueClient.GetQueueReference(nameResolver.ResolveInString(TestQueueName)); await queue.CreateIfNotExistsAsync(); for (int i = 0; i < _numberOfQueueMessages; i++) { int sleepTimeInSeconds = i % 2 == 0 ? 5 : 1; await queue.AddMessageAsync(new CloudQueueMessage(sleepTimeInSeconds.ToString())); } using (_allMessagesProcessed = new ManualResetEvent(initialState: false)) using (JobHost host = new JobHost(hostConfiguration)) { host.Start(); _allMessagesProcessed.WaitOne(TimeSpan.FromSeconds(90)); host.Stop(); } Assert.Equal(_numberOfQueueMessages, _receivedMessages); Assert.Equal(0, _currentSimultaneouslyRunningFunctions); // the actual value will vary sometimes based on the speed of the machine // running the test. int delta = _maxSimultaneouslyRunningFunctions - maxExpectedParallelism; Assert.True(delta == 0 || delta == 1); }
public AsyncCancellationEndToEndTests() { _resolver = new RandomNameResolver(); _hostConfiguration = new JobHostConfiguration() { NameResolver = _resolver, TypeLocator = new FakeTypeLocator(typeof(AsyncCancellationEndToEndTests)) }; _hostConfiguration.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); _storageAccount = CloudStorageAccount.Parse(_hostConfiguration.StorageConnectionString); _invokeInFunction = () => { }; _tokenCancelled = false; _functionStarted = new ManualResetEvent(initialState: false); _functionCompleted = new ManualResetEvent(initialState: false); }
private async Task EndToEndTest(bool uploadBlobBeforeHostStart) { // Reinitialize the name resolver to avoid conflicts _resolver = new RandomNameResolver(); JobHostConfiguration hostConfig = new JobHostConfiguration() { NameResolver = _resolver, TypeLocator = new FakeTypeLocator( this.GetType(), typeof(BlobToCustomObjectBinder)) }; hostConfig.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); if (uploadBlobBeforeHostStart) { // The function will be triggered fast because the blob is already there await UploadTestObject(); } // The jobs host is started JobHost host = new JobHost(hostConfig); _functionChainWaitHandle = new ManualResetEvent(initialState: false); host.Start(); if (!uploadBlobBeforeHostStart) { await WaitForTestFunctionsToStart(); await UploadTestObject(); } bool signaled = _functionChainWaitHandle.WaitOne(15 * 1000); // Stop the host and wait for it to finish host.Stop(); Assert.True(signaled); // Verify await VerifyTableResultsAsync(); }
public async Task GlobalErrorHandler_HandlerFails_NoInfiniteLoop() { ErrorTriggerProgram_GlobalCatchAllHandler instance = new ErrorTriggerProgram_GlobalCatchAllHandler(fail: true); JobHostConfiguration config = new JobHostConfiguration() { TypeLocator = new ExplicitTypeLocator(instance.GetType()), JobActivator = new ExplicitJobActivator(instance) }; config.UseCore(); config.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); JobHost host = new JobHost(config); await host.StartAsync(); TestTraceWriter traceWriter = new TestTraceWriter(); config.Tracing.Tracers.Add(traceWriter); MethodInfo method = instance.GetType().GetMethod("Throw"); await CallSafe(host, method); Assert.Equal(1, instance.Errors.Count); TraceEvent error = instance.Errors.Single(); Assert.Equal("Exception while executing function: ErrorTriggerProgram_GlobalCatchAllHandler.Throw", error.Message); // make sure the error handler failure is still logged var events = traceWriter.Events; Assert.Equal(8, events.Count); Assert.StartsWith("Executing 'ErrorTriggerProgram_GlobalCatchAllHandler.Throw'", events[0].Message); Assert.StartsWith("Executing 'ErrorTriggerProgram_GlobalCatchAllHandler.ErrorHandler'", events[1].Message); Assert.StartsWith("Exception while executing function: ErrorTriggerProgram_GlobalCatchAllHandler.ErrorHandler", events[2].Message); Assert.Equal("Kaboom!", events[3].Exception.InnerException.Message); Assert.StartsWith("Executed 'ErrorTriggerProgram_GlobalCatchAllHandler.ErrorHandler' (Failed, ", events[3].Message); Assert.StartsWith(" Function had errors. See Azure WebJobs SDK dashboard for details.", events[4].Message); Assert.StartsWith("Exception while executing function: ErrorTriggerProgram_GlobalCatchAllHandler.Throw", events[5].Message); Assert.StartsWith("Executed 'ErrorTriggerProgram_GlobalCatchAllHandler.Throw' (Failed, ", events[6].Message); Assert.StartsWith(" Function had errors. See Azure WebJobs SDK dashboard for details.", events[7].Message); }
public void IndexingExceptions_CanBeHandledByTraceWriter() { JobHostConfiguration config = new JobHostConfiguration(); TestTraceWriter traceWriter = new TestTraceWriter(TraceLevel.Verbose); config.Tracing.Tracers.Add(traceWriter); config.TypeLocator = new FakeTypeLocator(typeof(BindingErrorsProgram)); FunctionErrorTraceWriter errorTraceWriter = new FunctionErrorTraceWriter(TraceLevel.Error); config.Tracing.Tracers.Add(errorTraceWriter); config.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); JobHost host = new JobHost(config); host.Start(); // verify the handled binding error FunctionIndexingException fex = errorTraceWriter.Errors.SingleOrDefault() as FunctionIndexingException; Assert.True(fex.Handled); Assert.Equal("BindingErrorsProgram.Invalid", fex.MethodName); // verify that the binding error was logged Assert.Equal(4, traceWriter.Traces.Count); TraceEvent traceEvent = traceWriter.Traces[0]; Assert.Equal("Error indexing method 'BindingErrorsProgram.Invalid'", traceEvent.Message); Assert.Same(fex, traceEvent.Exception); Assert.Equal("Invalid container name: invalid$=+1", traceEvent.Exception.InnerException.Message); // verify that the valid function was still indexed traceEvent = traceWriter.Traces[1]; Assert.True(traceEvent.Message.Contains("Found the following functions")); Assert.True(traceEvent.Message.Contains("BindingErrorsProgram.Valid")); // verify that the job host was started successfully traceEvent = traceWriter.Traces[3]; Assert.Equal("Job host started", traceEvent.Message); host.Stop(); host.Dispose(); }
public async Task GlobalErrorHandler_ManualSubscriberFails_NoInfiniteLoop() { JobHostConfiguration config = new JobHostConfiguration() { TypeLocator = new ExplicitTypeLocator(typeof(ErrorProgram)) }; config.UseCore(); config.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); int notificationCount = 0; var traceMonitor = new TraceMonitor() .Filter(p => { return(true); }) .Subscribe(p => { notificationCount++; throw new Exception("Kaboom"); }); config.Tracing.Tracers.Add(traceMonitor); JobHost host = new JobHost(config); await host.StartAsync(); TestTraceWriter traceWriter = new TestTraceWriter(); config.Tracing.Tracers.Add(traceWriter); MethodInfo method = typeof(ErrorProgram).GetMethod("Throw"); await CallSafe(host, method); Assert.Equal(1, notificationCount); var events = traceWriter.Events; Assert.Equal(4, events.Count); Assert.StartsWith("Executing 'ErrorProgram.Throw'", events[0].Message); Assert.StartsWith("Exception while executing function: ErrorProgram.Throw", events[1].Message); Assert.StartsWith("Executed 'ErrorProgram.Throw' (Failed, ", events[2].Message); Assert.StartsWith(" Function had errors. See Azure WebJobs SDK dashboard for details.", events[3].Message); }
private RedisConfiguration InitializeConfig(string connectionStringSetting) { var config = new RedisConfiguration(); var nameResolver = new TestNameResolver(); nameResolver.Values[RedisConfiguration.AzureWebJobsRedisConnectionStringSetting] = connectionStringSetting; var jobHostConfig = new JobHostConfiguration(); jobHostConfig.AddService <INameResolver>(nameResolver); var context = new ExtensionConfigContext() { Config = jobHostConfig }; config.Initialize(context); return(config); }
public static async Task<JobHostContext> CreateAndLogHostStartedAsync( JobHost host, IStorageAccountProvider storageAccountProvider, IQueueConfiguration queueConfiguration, ITypeLocator typeLocator, IJobActivator activator, INameResolver nameResolver, IConsoleProvider consoleProvider, JobHostConfiguration config, CancellationToken shutdownToken, CancellationToken cancellationToken, IHostIdProvider hostIdProvider = null, FunctionExecutor functionExecutor = null, IFunctionIndexProvider functionIndexProvider = null, IBindingProvider bindingProvider = null, IHostInstanceLoggerProvider hostInstanceLogerProvider = null, IFunctionInstanceLoggerProvider functionInstanceLoggerProvider = null, IFunctionOutputLoggerProvider functionOutputLoggerProvider = null, IBackgroundExceptionDispatcher backgroundExceptionDispatcher = null, SingletonManager singletonManager = null) { if (hostIdProvider == null) { hostIdProvider = new DynamicHostIdProvider(storageAccountProvider, () => functionIndexProvider); } IExtensionTypeLocator extensionTypeLocator = new ExtensionTypeLocator(typeLocator); if (backgroundExceptionDispatcher == null) { backgroundExceptionDispatcher = BackgroundExceptionDispatcher.Instance; } ContextAccessor<IMessageEnqueuedWatcher> messageEnqueuedWatcherAccessor = new ContextAccessor<IMessageEnqueuedWatcher>(); ContextAccessor<IBlobWrittenWatcher> blobWrittenWatcherAccessor = new ContextAccessor<IBlobWrittenWatcher>(); ISharedContextProvider sharedContextProvider = new SharedContextProvider(); // Create a wrapper TraceWriter that delegates to both the user // TraceWriter specified on Config (if present), as well as to Console TraceWriter trace = new ConsoleTraceWriter(config.Tracing, consoleProvider.Out); // Register system services with the service container config.AddService<INameResolver>(nameResolver); ExtensionConfigContext context = new ExtensionConfigContext { Config = config, Trace = trace, Host = host }; InvokeExtensionConfigProviders(context); IExtensionRegistry extensions = config.GetExtensions(); ITriggerBindingProvider triggerBindingProvider = DefaultTriggerBindingProvider.Create(nameResolver, storageAccountProvider, extensionTypeLocator, hostIdProvider, queueConfiguration, backgroundExceptionDispatcher, messageEnqueuedWatcherAccessor, blobWrittenWatcherAccessor, sharedContextProvider, extensions, trace); if (bindingProvider == null) { bindingProvider = DefaultBindingProvider.Create(nameResolver, storageAccountProvider, extensionTypeLocator, messageEnqueuedWatcherAccessor, blobWrittenWatcherAccessor, extensions); } DefaultLoggerProvider loggerProvider = new DefaultLoggerProvider(storageAccountProvider, trace); if (singletonManager == null) { singletonManager = new SingletonManager(storageAccountProvider, backgroundExceptionDispatcher, config.Singleton, trace, config.NameResolver); } using (CancellationTokenSource combinedCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, shutdownToken)) { CancellationToken combinedCancellationToken = combinedCancellationSource.Token; await WriteSiteExtensionManifestAsync(combinedCancellationToken); IStorageAccount dashboardAccount = await storageAccountProvider.GetDashboardAccountAsync(combinedCancellationToken); IHostInstanceLogger hostInstanceLogger = null; if (hostInstanceLogerProvider != null) { hostInstanceLogger = await hostInstanceLogerProvider.GetAsync(combinedCancellationToken); } else { hostInstanceLogger = await((IHostInstanceLoggerProvider)loggerProvider).GetAsync(combinedCancellationToken); } IFunctionInstanceLogger functionInstanceLogger = null; if (functionInstanceLoggerProvider != null) { functionInstanceLogger = await functionInstanceLoggerProvider.GetAsync(combinedCancellationToken); } else { functionInstanceLogger = (IFunctionInstanceLogger)(await((IFunctionInstanceLoggerProvider)loggerProvider).GetAsync(combinedCancellationToken)); } IFunctionOutputLogger functionOutputLogger = null; if (functionOutputLoggerProvider != null) { functionOutputLogger = await functionOutputLoggerProvider.GetAsync(combinedCancellationToken); } else { functionOutputLogger = (IFunctionOutputLogger)(await((IFunctionOutputLoggerProvider)loggerProvider).GetAsync(combinedCancellationToken)); } if (functionExecutor == null) { functionExecutor = new FunctionExecutor(functionInstanceLogger, functionOutputLogger, backgroundExceptionDispatcher, trace); } if (functionIndexProvider == null) { functionIndexProvider = new FunctionIndexProvider(typeLocator, triggerBindingProvider, bindingProvider, activator, functionExecutor, extensions, singletonManager); } IFunctionIndex functions = await functionIndexProvider.GetAsync(combinedCancellationToken); IListenerFactory functionsListenerFactory = new HostListenerFactory(functions.ReadAll(), singletonManager, activator, nameResolver, trace); IFunctionExecutor hostCallExecutor; IListener listener; HostOutputMessage hostOutputMessage; if (dashboardAccount != null) { string hostId = await hostIdProvider.GetHostIdAsync(cancellationToken); string sharedQueueName = HostQueueNames.GetHostQueueName(hostId); IStorageQueueClient dashboardQueueClient = dashboardAccount.CreateQueueClient(); IStorageQueue sharedQueue = dashboardQueueClient.GetQueueReference(sharedQueueName); IListenerFactory sharedQueueListenerFactory = new HostMessageListenerFactory(sharedQueue, queueConfiguration, backgroundExceptionDispatcher, trace, functions, functionInstanceLogger, functionExecutor); Guid hostInstanceId = Guid.NewGuid(); string instanceQueueName = HostQueueNames.GetHostQueueName(hostInstanceId.ToString("N")); IStorageQueue instanceQueue = dashboardQueueClient.GetQueueReference(instanceQueueName); IListenerFactory instanceQueueListenerFactory = new HostMessageListenerFactory(instanceQueue, queueConfiguration, backgroundExceptionDispatcher, trace, functions, functionInstanceLogger, functionExecutor); HeartbeatDescriptor heartbeatDescriptor = new HeartbeatDescriptor { SharedContainerName = HostContainerNames.Hosts, SharedDirectoryName = HostDirectoryNames.Heartbeats + "/" + hostId, InstanceBlobName = hostInstanceId.ToString("N"), ExpirationInSeconds = (int)HeartbeatIntervals.ExpirationInterval.TotalSeconds }; IStorageBlockBlob blob = dashboardAccount.CreateBlobClient() .GetContainerReference(heartbeatDescriptor.SharedContainerName) .GetBlockBlobReference(heartbeatDescriptor.SharedDirectoryName + "/" + heartbeatDescriptor.InstanceBlobName); IRecurrentCommand heartbeatCommand = new UpdateHostHeartbeatCommand(new HeartbeatCommand(blob)); IEnumerable<MethodInfo> indexedMethods = functions.ReadAllMethods(); Assembly hostAssembly = GetHostAssembly(indexedMethods); string displayName = hostAssembly != null ? hostAssembly.GetName().Name : "Unknown"; hostOutputMessage = new DataOnlyHostOutputMessage { HostInstanceId = hostInstanceId, HostDisplayName = displayName, SharedQueueName = sharedQueueName, InstanceQueueName = instanceQueueName, Heartbeat = heartbeatDescriptor, WebJobRunIdentifier = WebJobRunIdentifier.Current }; hostCallExecutor = CreateHostCallExecutor(instanceQueueListenerFactory, heartbeatCommand, backgroundExceptionDispatcher, shutdownToken, functionExecutor); IListenerFactory hostListenerFactory = new CompositeListenerFactory(functionsListenerFactory, sharedQueueListenerFactory, instanceQueueListenerFactory); listener = CreateHostListener(hostListenerFactory, heartbeatCommand, backgroundExceptionDispatcher, shutdownToken); // Publish this to Azure logging account so that a web dashboard can see it. await LogHostStartedAsync(functions, hostOutputMessage, hostInstanceLogger, combinedCancellationToken); } else { hostCallExecutor = new ShutdownFunctionExecutor(shutdownToken, functionExecutor); IListener factoryListener = new ListenerFactoryListener(functionsListenerFactory); IListener shutdownListener = new ShutdownListener(shutdownToken, factoryListener); listener = shutdownListener; hostOutputMessage = new DataOnlyHostOutputMessage(); } functionExecutor.HostOutputMessage = hostOutputMessage; IEnumerable<FunctionDescriptor> descriptors = functions.ReadAllDescriptors(); int descriptorsCount = descriptors.Count(); if (descriptorsCount == 0) { trace.Warning("No functions found. Try making job classes and methods public.", TraceSource.Indexing); } else { StringBuilder functionsTrace = new StringBuilder(); functionsTrace.AppendLine("Found the following functions:"); foreach (FunctionDescriptor descriptor in descriptors) { functionsTrace.AppendLine(descriptor.FullName); } trace.Info(functionsTrace.ToString(), TraceSource.Indexing); } return new JobHostContext(functions, hostCallExecutor, listener, trace); } }
public void AddService_ThrowsArgumentOutOfRange_WhenInstanceNotInstanceOfType() { JobHostConfiguration configuration = new JobHostConfiguration(); ArgumentOutOfRangeException exception = Assert.Throws<ArgumentOutOfRangeException>( () => configuration.AddService(typeof(IComparable), new object()) ); Assert.Equal("serviceInstance", exception.ParamName); }
public void AddService_ThrowsArgumentNull_WhenServiceTypeIsNull() { JobHostConfiguration configuration = new JobHostConfiguration(); ArgumentNullException exception = Assert.Throws<ArgumentNullException>( () => configuration.AddService(null, "test1") ); Assert.Equal("serviceType", exception.ParamName); }
public void AddService_ReplacesExistingService() { JobHostConfiguration configuration = new JobHostConfiguration(); IComparable service = "test1"; configuration.AddService<IComparable>(service); IComparable result = configuration.GetService<IComparable>(); Assert.Same(service, result); IComparable service2 = "test2"; configuration.AddService<IComparable>(service2); result = configuration.GetService<IComparable>(); Assert.Same(service2, result); }
public void AddService_AddsNewService() { JobHostConfiguration configuration = new JobHostConfiguration(); IComparable service = "test1"; configuration.AddService<IComparable>(service); IComparable result = configuration.GetService<IComparable>(); Assert.Same(service, result); }
protected override void OnInitializeConfig(JobHostConfiguration config) { base.OnInitializeConfig(config); // Add our WebHost specific services config.AddService<IMetricsLogger>(_metricsLogger); }