public async void ExistingFilesAreBatchProcessedOnStartup() { JobHost host = CreateTestJobHost(); // create a bunch of preexisting files List <string> filesToProcess = new List <string>(); int preexistingFileCount = 10; for (int i = 0; i < preexistingFileCount; i++) { string testFilePath = WriteTestFile(); filesToProcess.Add(Path.GetFileName(testFilePath)); } // write a non .dat file - don't expect it to be processed WriteTestFile("txt"); host.Start(); await TestHelpers.Await(() => { return(FilesTestJobs.Processed.Count == preexistingFileCount); }); Assert.True(FilesTestJobs.Processed.OrderBy(p => p).SequenceEqual(filesToProcess.OrderBy(p => p))); host.Stop(); }
public void WaitsForTaskToComplete() { var host = new JobHost(); var workTask = new Task(() => host.DoWork(new Task(() => { // Was getting inconsistent results with Thread.Sleep(100) for (int i = 0; i < 100; i++) { Thread.Sleep(1); } }))); var beforeStop = DateTime.UtcNow; workTask.Start(); while (workTask.Status != TaskStatus.Running) { Thread.Sleep(1); } host.Stop(false); var afterStop = DateTime.UtcNow; // If Stop didn't wait, we'd expect after to be less than 100 ms larger than beforeStop Assert.True((afterStop - beforeStop).TotalMilliseconds >= 100); }
public async void JobIsTriggeredForNewFiles() { JobHost host = CreateTestJobHost(); host.Start(); Assert.Equal(0, ApiHubTestJobs.Processed.Count); // now write a file to trigger the job var fileItem = await WriteTestFile(); await TestHelpers.Await(() => { return(_rootFolder.FileExists(fileItem.Path)); }); await TestHelpers.Await(() => { return(ApiHubTestJobs.Processed.Count != 0); }); Assert.Equal(1, ApiHubTestJobs.Processed.Count); Assert.Equal(Path.GetFileName(fileItem.Path), ApiHubTestJobs.Processed.Single()); host.Stop(); await fileItem.DeleteAsync(); }
public void DisabledAggregator_NoAggregator() { // Add the loggerfactory but disable the aggregator var config = CreateConfig(); config.Aggregator.IsEnabled = false; // Ensure the aggregator is never configured by registering an // AggregatorFactory that with a strict, unconfigured mock. var mockFactory = new Mock <IFunctionResultAggregatorFactory>(MockBehavior.Strict); config.AddService <IFunctionResultAggregatorFactory>(mockFactory.Object); using (JobHost host = new JobHost(config)) { // also start and stop the host to ensure nothing throws due to the // null aggregator host.Start(); var method = typeof(ILoggerFunctions).GetMethod(nameof(ILoggerFunctions.TraceWriterWithILoggerFactory)); host.Call(method); host.Stop(); } }
static void Main(string[] args) { JobHostConfiguration config = new JobHostConfiguration(); //config.Tracing.Trace = new ConsoleTraceWriter(TraceLevel.Verbose); config.UseRedis(); JobHost host = new JobHost(config); host.Start(); // Give subscriber chance to startup Task.Delay(5000).Wait(); host.Call(typeof(Functions).GetMethod("SendSimplePubSubMessage")); host.Call(typeof(Functions).GetMethod("SendPubSubMessage")); host.Call(typeof(Functions).GetMethod("SendPubSubMessageIdChannel")); host.Call(typeof(Functions).GetMethod("AddSimpleCacheMessage")); host.Call(typeof(Functions).GetMethod("AddCacheMessage")); host.Call(typeof(Functions).GetMethod("AddCacheMessage")); Console.CancelKeyPress += (sender, e) => { host.Stop(); }; while (true) { Thread.Sleep(500); } }
public async Task SingletonFunction_HostScope_InvocationsAreSerialized() { JobHost host = CreateTestJobHost(1); host.Start(); MethodInfo methodA = typeof(TestJobs).GetMethod("SingletonJobA_HostScope"); List <Task> tasks = new List <Task>(); for (int i = 0; i < 5; i++) { tasks.Add(host.CallAsync(methodA, new { })); } MethodInfo methodB = typeof(TestJobs).GetMethod("SingletonJobB_HostScope"); for (int i = 0; i < 5; i++) { tasks.Add(host.CallAsync(methodB, new { })); } await Task.WhenAll(tasks); Assert.False(TestJobs.FailureDetected); Assert.Equal(10, TestJobs.JobInvocations[1]); await VerifyLeaseState(methodA, SingletonScope.Host, "TestValue", LeaseState.Available, LeaseStatus.Unlocked); await VerifyLeaseState(methodB, SingletonScope.Host, "TestValue", LeaseState.Available, LeaseStatus.Unlocked); host.Stop(); host.Dispose(); }
public async Task SingletonFunction_Exception_LeaseReleasedImmediately() { JobHost host = CreateTestJobHost(1); host.Start(); WorkItem workItem = new WorkItem { ID = 1, Region = "Central", Zone = 3, Category = -1, Description = "Test Work Item" }; Exception exception = null; MethodInfo method = typeof(TestJobs).GetMethod("SingletonJob"); try { await host.CallAsync(method, new { workItem = workItem }); } catch (Exception ex) { exception = ex; } Assert.Equal("Exception while executing function: TestJobs.SingletonJob", exception.Message); await VerifyLeaseState(method, SingletonScope.Function, "TestValue", LeaseState.Available, LeaseStatus.Unlocked); host.Stop(); host.Dispose(); }
private void ServiceBusEndToEndInternal() { // Reinitialize the name resolver to avoid naming conflicts _nameResolver = new RandomNameResolver(); JobHostConfiguration config = new JobHostConfiguration() { NameResolver = _nameResolver, TypeLocator = new FakeTypeLocator(this.GetType()) }; _namespaceManager = NamespaceManager.CreateFromConnectionString(config.ServiceBusConnectionString); CreateStartMessage(config.ServiceBusConnectionString); JobHost host = new JobHost(config); _topicSubscriptionCalled1 = new ManualResetEvent(initialState: false); _topicSubscriptionCalled2 = new ManualResetEvent(initialState: false); host.Start(); bool signaled = WaitHandle.WaitAll( new WaitHandle[] { _topicSubscriptionCalled1, _topicSubscriptionCalled2 }, 2 * 60 * 1000); // Wait for the host to terminate host.Stop(); Assert.True(signaled); Assert.Equal("E2E-SBQueue2SBQueue-SBQueue2SBTopic-topic-1", _resultMessage1); Assert.Equal("E2E-SBQueue2SBQueue-SBQueue2SBTopic-topic-2", _resultMessage2); }
private void RunTest(string testName, IMobileServiceClientFactory factory, TraceWriter testTrace, object argument = null) { Type testType = typeof(MobileTableEndToEndFunctions); ExplicitTypeLocator locator = new ExplicitTypeLocator(testType); JobHostConfiguration config = new JobHostConfiguration { TypeLocator = locator, }; config.Tracing.Tracers.Add(testTrace); var arguments = new Dictionary <string, object>(); arguments.Add("triggerData", argument); var mobileAppsConfig = new MobileAppsConfiguration { MobileAppUri = new Uri("https://someuri"), ApiKey = "api_key", ClientFactory = factory }; var resolver = new TestNameResolver(); config.NameResolver = resolver; config.UseMobileApps(mobileAppsConfig); JobHost host = new JobHost(config); host.Start(); host.Call(testType.GetMethod(testName), arguments); host.Stop(); }
public async Task SingletonNonTriggeredFunction_MultipleConcurrentInvocations_InvocationsAreSerialized() { JobHost host = CreateTestJobHost(1); host.Start(); // make a bunch of parallel invocations int numInvocations = 20; List <Task> invokeTasks = new List <Task>(); MethodInfo method = typeof(TestJobs).GetMethod("SingletonJob"); for (int i = 0; i < numInvocations; i++) { int zone = _rand.Next(3) + 1; WorkItem workItem = new WorkItem { ID = i + 1, Region = "Central", Zone = zone, Category = 3, Description = "Test Work Item " + i }; invokeTasks.Add(host.CallAsync(method, new { workItem = workItem })); } await Task.WhenAll(invokeTasks.ToArray()); Assert.False(TestJobs.FailureDetected); Assert.Equal(numInvocations, TestJobs.JobInvocations[1]); await VerifyLeaseState(method, SingletonScope.Function, "TestValue", LeaseState.Available, LeaseStatus.Unlocked); host.Stop(); host.Dispose(); }
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.UseTimers(); config.Tracing.Tracers.Add(testTrace); JobHost host = new JobHost(config); host.Start(); await TestHelpers.Await(() => { return(condition()); }); host.Stop(); // ensure there were no errors Assert.Equal(0, testTrace.Events.Count); }
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 FunctionTraceLevelOverride_ProducesExpectedOutput() { TestTraceWriter trace = new TestTraceWriter(TraceLevel.Verbose); _hostConfig.Tracing.Tracers.Add(trace); JobHost host = new JobHost(_hostConfig); try { using (_functionCompletedEvent = new ManualResetEvent(initialState: false)) { await host.StartAsync(); CloudQueueMessage message = new CloudQueueMessage("test message"); await _testQueue.AddMessageAsync(message); await TestHelpers.Await(() => _functionCompletedEvent.WaitOne(200), 30000); // wait for logs to flush await Task.Delay(3000); // expect no function output TraceEvent[] traces = trace.Traces.ToArray(); Assert.Equal(4, traces.Length); Assert.False(traces.Any(p => p.Message.Contains("test message"))); } } finally { host.Stop(); } }
// Helper to send items to the listener, and return what they collected private object[] Run <TFunction>(params FakeQueueData[] items) where TFunction : FunctionsBase, new() { var activator = new FakeActivator(); var func1 = new TFunction(); activator.Add(func1); JobHostConfiguration config = new JobHostConfiguration() { TypeLocator = new FakeTypeLocator(typeof(TFunction)), JobActivator = activator }; FakeQueueClient client = new FakeQueueClient(); IExtensionRegistry extensions = config.GetService <IExtensionRegistry>(); extensions.RegisterExtension <IExtensionConfigProvider>(client); JobHost host = new JobHost(config); foreach (var item in items) { client.AddAsync(item).Wait(); } host.Start(); TestHelpers.WaitOne(func1._stopEvent); host.Stop(); return(func1._collected.ToArray()); }
private async Task RunTimeoutTest(IWebJobsExceptionHandler exceptionHandler, Type expectedExceptionType, string functionName) { TestTraceWriter trace = new TestTraceWriter(TraceLevel.Verbose); _hostConfig.Tracing.Tracers.Add(trace); _hostConfig.AddService <IWebJobsExceptionHandler>(exceptionHandler); JobHost host = new JobHost(_hostConfig); try { await host.StartAsync(); MethodInfo methodInfo = GetType().GetMethod(functionName); Exception ex = await Assert.ThrowsAnyAsync <Exception>(async() => { await host.CallAsync(methodInfo); }); Assert.IsType(expectedExceptionType, ex); } finally { host.Stop(); } // We expect 3 error messages total TraceEvent[] traceErrors = trace.Traces.Where(p => p.Level == TraceLevel.Error).ToArray(); Assert.Equal(3, traceErrors.Length); Assert.True(traceErrors[0].Message.StartsWith(string.Format("Timeout value of 00:00:01 exceeded by function 'AsyncChainEndToEndTests.{0}'", functionName))); Assert.True(traceErrors[1].Message.StartsWith(string.Format("Executed 'AsyncChainEndToEndTests.{0}' (Failed, Id=", functionName))); Assert.True(traceErrors[2].Message.Trim().StartsWith("Function had errors. See Azure WebJobs SDK dashboard for details.")); }
static void Main() { CreateDemoData(); JobHostConfiguration configuration = new JobHostConfiguration(); configuration.Queues.MaxPollingInterval = TimeSpan.FromSeconds(30); configuration.Queues.MaxDequeueCount = 10; configuration.Queues.BatchSize = 1; JobHost host = new JobHost(configuration); host.Start(); // Stop the host if Ctrl + C/Ctrl + Break is pressed Console.CancelKeyPress += (sender, args) => { host.Stop(); }; while (true) { Thread.Sleep(500); } }
public async void JobIsTriggeredForNewFiles() { JobHost host = CreateTestJobHost(); host.Start(); Assert.Equal(0, FilesTestJobs.Processed.Count); // now write a file to trigger the job string testFilePath = WriteTestFile(); await Task.Delay(2000); Assert.Equal(1, FilesTestJobs.Processed.Count); Assert.Equal(Path.GetFileName(testFilePath), FilesTestJobs.Processed.Single()); Assert.True(File.Exists(testFilePath)); // write a non .dat file - don't expect it to trigger the job string ignoreFilePath = WriteTestFile("txt"); await Task.Delay(2000); Assert.Equal(1, FilesTestJobs.Processed.Count); Assert.True(File.Exists(ignoreFilePath)); host.Stop(); }
public void EnsuresNoWorkIsDone() { var host = new JobHost(); var task = new Task(() => { throw new InvalidOperationException("Hey, this is supposed to be shut down!"); }); host.Stop(true); host.DoWork(task); }
public void Aggregator_Runs_WhenEnabled_AndFlushes_OnStop() { int addCalls = 0; int flushCalls = 0; var config = CreateConfig(); var mockAggregator = new Mock <IAsyncCollector <FunctionInstanceLogEntry> >(MockBehavior.Strict); mockAggregator .Setup(a => a.AddAsync(It.IsAny <FunctionInstanceLogEntry>(), It.IsAny <CancellationToken>())) .Callback <FunctionInstanceLogEntry, CancellationToken>((l, t) => { if (l.IsCompleted) { addCalls++; // The default aggregator will ingore the 'Function started' calls. } }) .Returns(Task.CompletedTask); mockAggregator .Setup(a => a.FlushAsync(It.IsAny <CancellationToken>())) .Callback <CancellationToken>(t => flushCalls++) .Returns(Task.CompletedTask); var mockFactory = new Mock <IFunctionResultAggregatorFactory>(MockBehavior.Strict); mockFactory .Setup(f => f.Create(5, TimeSpan.FromSeconds(1), It.IsAny <ILoggerFactory>())) .Returns(mockAggregator.Object); config.AddService <IFunctionResultAggregatorFactory>(mockFactory.Object); const int N = 5; config.Aggregator.IsEnabled = true; config.Aggregator.BatchSize = N; config.Aggregator.FlushTimeout = TimeSpan.FromSeconds(1); using (JobHost host = new JobHost(config)) { host.Start(); var method = typeof(ILoggerFunctions).GetMethod(nameof(ILoggerFunctions.TraceWriterWithILoggerFactory)); for (int i = 0; i < N; i++) { host.Call(method); } host.Stop(); } Assert.Equal(N, addCalls); // Flush is called on host stop Assert.Equal(1, flushCalls); }
public void BlobGetsProcessedOnlyOnce_SingleHost() { TextWriter hold = Console.Out; StringWriter consoleOutput = new StringWriter(); Console.SetOut(consoleOutput); CloudBlockBlob blob = _testContainer.GetBlockBlobReference(BlobName); blob.UploadText("0"); int timeToProcess; // Process the blob first using (_blobProcessedEvent = new ManualResetEvent(initialState: false)) using (JobHost host = new JobHost(_hostConfiguration)) { DateTime startTime = DateTime.Now; host.Start(); Assert.True(_blobProcessedEvent.WaitOne(TimeSpan.FromSeconds(60))); timeToProcess = (int)(DateTime.Now - startTime).TotalMilliseconds; host.Stop(); Console.SetOut(hold); string[] consoleOutputLines = consoleOutput.ToString().Trim().Split(new string[] { Environment.NewLine }, StringSplitOptions.None); string[] expectedOutputLines = new string[] { "Found the following functions:", "Microsoft.Azure.WebJobs.Host.EndToEndTests.BlobTriggerTests.SingleBlobTrigger", "Job host started", string.Format("Executing: 'BlobTriggerTests.SingleBlobTrigger' - Reason: 'New blob detected: {0}/{1}'", blob.Container.Name, blob.Name), "Executed: 'BlobTriggerTests.SingleBlobTrigger' (Succeeded)", "Job host stopped", }; Assert.True(consoleOutputLines.SequenceEqual(expectedOutputLines)); } // Then start again and make sure the blob doesn't get reprocessed // wait twice the amount of time required to process first before // deciding that it doesn't get reprocessed using (_blobProcessedEvent = new ManualResetEvent(initialState: false)) using (JobHost host = new JobHost(_hostConfiguration)) { host.Start(); bool blobReprocessed = _blobProcessedEvent.WaitOne(2 * timeToProcess); host.Stop(); Assert.False(blobReprocessed); } }
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 override void OnStop() { Trace.TraceInformation("WorkerRole1 is stopping"); host.Stop(); base.OnStop(); Trace.TraceInformation("WorkerRole1 has stopped"); }
public void Stop_WhenUsingTriggeredFunction_TriggersCancellationToken() { using (JobHost host = new JobHost(_hostConfiguration)) { PrepareHostForTrigger(host, startHost: true); host.Stop(); EvaluateTriggeredCancellation(expectedCancellation: true); } }
public void StopAsync_WhenStopped_DoesNotThrow() { // Arrange using (JobHost host = new JobHost(new OptionsWrapper <JobHostOptions>(new JobHostOptions()), new Mock <IJobHostContextFactory>().Object)) { host.Start(); host.Stop(); // Act & Assert host.StopAsync().GetAwaiter().GetResult(); } }
public void StartAsync_WhenStopped_Throws() { // Arrange using (JobHost host = new JobHost(new OptionsWrapper <JobHostOptions>(new JobHostOptions()), new Mock <IJobHostContextFactory>().Object)) { host.Start(); host.Stop(); // Act & Assert ExceptionAssert.ThrowsInvalidOperation(() => host.StartAsync(), "Start has already been called."); } }
public void StartAsync_WhenStopped_Throws() { // Arrange using (JobHost host = new JobHost(CreateConfiguration())) { host.Start(); host.Stop(); // Act & Assert ExceptionAssert.ThrowsInvalidOperation(() => host.StartAsync(), "Start has already been called."); } }
public void StopAsync_WhenStopped_DoesNotThrow() { // Arrange using (JobHost host = new JobHost(CreateConfiguration())) { host.Start(); host.Stop(); // Act & Assert host.StopAsync().GetAwaiter().GetResult(); } }
public void Dispose() { Thread.Sleep(TimeSpan.FromSeconds(1)); // let the functions finish // this should not be needed, but for some reason some connections stay open / references keep exist after JobHost instance is stopped and disposed var mqttExtensionConfigProvider = _jobHost.Services.GetService(typeof(IMqttConnectionFactory)) as MqttConnectionFactory; mqttExtensionConfigProvider.DisconnectAll().Wait(); _jobHost.Stop(); _jobHost.Dispose(); _jobHost = null; }
public void Stop_WhenUsingTriggeredFunction_TriggersCancellationToken() { // Note: Calling IHost.StopAsync() does not stop registered IHostedServices. The host must // be disposed in order to stop those. using (_host) { JobHost jobHost = _host.GetJobHost(); PrepareHostForTrigger(jobHost, startHost: true); jobHost.Stop(); EvaluateTriggeredCancellation(expectedCancellation: true); } }
public void Stop_WhenUsingHostCall_DoesNotTriggerCancellationToken() { using (JobHost host = new JobHost(_hostConfiguration)) { host.Start(); Task callTask = InvokeNoAutomaticTriggerFunction(host); host.Stop(); EvaluateNoAutomaticTriggerCancellation(callTask, expectedCancellation: false); } }
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.UseTimers(); config.Tracing.Tracers.Add(testTrace); JobHost host = new JobHost(config); host.Start(); await TestHelpers.Await(() => { return condition(); }); host.Stop(); // ensure there were no errors Assert.Equal(0, testTrace.Events.Count); }
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); 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(5, 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[4]; Assert.Equal("Job host started", traceEvent.Message); host.Stop(); host.Dispose(); }
private void ServiceBusEndToEndInternal(Type jobContainerType, bool verifyLogs = true) { StringWriter consoleOutput = null; if (verifyLogs) { consoleOutput = new StringWriter(); Console.SetOut(consoleOutput); } JobHostConfiguration config = new JobHostConfiguration() { NameResolver = _nameResolver, TypeLocator = new FakeTypeLocator(jobContainerType) }; config.UseServiceBus(_serviceBusConfig); string startQueueName = ResolveName(StartQueueName); string secondQueueName = startQueueName.Replace("start", "1"); string queuePrefix = startQueueName.Replace("-queue-start", ""); string firstTopicName = string.Format("{0}-topic/Subscriptions/{0}-queue-topic-1", queuePrefix); string secondTopicName = string.Format("{0}-topic/Subscriptions/{0}-queue-topic-2", queuePrefix); CreateStartMessage(_serviceBusConfig.ConnectionString, startQueueName); _host = new JobHost(config); _topicSubscriptionCalled1 = new ManualResetEvent(initialState: false); _topicSubscriptionCalled2 = new ManualResetEvent(initialState: false); _host.Start(); int timeout = 1 * 60 * 1000; _topicSubscriptionCalled1.WaitOne(timeout); _topicSubscriptionCalled2.WaitOne(timeout); // Wait for the host to terminate _host.Stop(); Assert.Equal("E2E-SBQueue2SBQueue-SBQueue2SBTopic-topic-1", _resultMessage1); Assert.Equal("E2E-SBQueue2SBQueue-SBQueue2SBTopic-topic-2", _resultMessage2); if (verifyLogs) { string[] consoleOutputLines = consoleOutput.ToString().Trim().Split(new string[] { Environment.NewLine }, StringSplitOptions.None); string[] expectedOutputLines = new string[] { "Found the following functions:", string.Format("{0}.SBQueue2SBQueue", jobContainerType.FullName), string.Format("{0}.SBQueue2SBTopic", jobContainerType.FullName), string.Format("{0}.SBTopicListener1", jobContainerType.FullName), string.Format("{0}.SBTopicListener2", jobContainerType.FullName), "Job host started", string.Format("Executing: '{0}.SBQueue2SBQueue' - Reason: 'New ServiceBus message detected on '{1}'.'", jobContainerType.Name, startQueueName), string.Format("Executing: '{0}.SBQueue2SBTopic' - Reason: 'New ServiceBus message detected on '{1}'.'", jobContainerType.Name, secondQueueName), string.Format("Executing: '{0}.SBTopicListener1' - Reason: 'New ServiceBus message detected on '{1}'.'", jobContainerType.Name, firstTopicName), string.Format("Executing: '{0}.SBTopicListener2' - Reason: 'New ServiceBus message detected on '{1}'.'", jobContainerType.Name, secondTopicName), "Job host stopped" }; Assert.True(expectedOutputLines.OrderBy(p => p).SequenceEqual(consoleOutputLines.OrderBy(p => p))); } }
public void 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.Queues.BatchSize = batchSize; CloudStorageAccount storageAccount = CloudStorageAccount.Parse(hostConfiguration.StorageConnectionString); _queueClient = storageAccount.CreateCloudQueueClient(); CloudQueue queue = _queueClient.GetQueueReference(nameResolver.ResolveInString(TestQueueName)); queue.CreateIfNotExists(); for (int i = 0; i < _numberOfQueueMessages; i++) { int sleepTimeInSeconds = i % 2 == 0 ? 5 : 1; queue.AddMessage(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 void BlobGetsProcessedOnlyOnce_MultipleHosts() { _testContainer .GetBlockBlobReference(BlobName) .UploadText("10"); using (_blobProcessedEvent = new ManualResetEvent(initialState: false)) using (JobHost host1 = new JobHost(_hostConfiguration)) using (JobHost host2 = new JobHost(_hostConfiguration)) { host1.Start(); host2.Start(); Assert.True(_blobProcessedEvent.WaitOne(TimeSpan.FromSeconds(60))); host1.Stop(); host2.Stop(); } Assert.Equal(1, _timesProcessed); }