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();
        }
Exemple #2
0
            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);
        }
Exemple #9
0
        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();
            }
        }
Exemple #14
0
        // 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());
        }
Exemple #15
0
        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."));
        }
Exemple #16
0
        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);
            }
Exemple #19
0
            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);
            }
Exemple #20
0
        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);
        }
Exemple #21
0
        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();
        }
Exemple #23
0
        public override void OnStop()
        {
            Trace.TraceInformation("WorkerRole1 is stopping");

            host.Stop();

            base.OnStop();

            Trace.TraceInformation("WorkerRole1 has stopped");
        }
Exemple #24
0
        public void Stop_WhenUsingTriggeredFunction_TriggersCancellationToken()
        {
            using (JobHost host = new JobHost(_hostConfiguration))
            {
                PrepareHostForTrigger(host, startHost: true);

                host.Stop();

                EvaluateTriggeredCancellation(expectedCancellation: true);
            }
        }
Exemple #25
0
        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();
            }
        }
Exemple #26
0
        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.");
            }
        }
Exemple #27
0
        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.");
            }
        }
Exemple #28
0
        public void StopAsync_WhenStopped_DoesNotThrow()
        {
            // Arrange
            using (JobHost host = new JobHost(CreateConfiguration()))
            {
                host.Start();
                host.Stop();

                // Act & Assert
                host.StopAsync().GetAwaiter().GetResult();
            }
        }
Exemple #29
0
        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;
        }
Exemple #30
0
        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);
            }
        }
Exemple #31
0
        public void Stop_WhenUsingHostCall_DoesNotTriggerCancellationToken()
        {
            using (JobHost host = new JobHost(_hostConfiguration))
            {
                host.Start();

                Task callTask = InvokeNoAutomaticTriggerFunction(host);

                host.Stop();

                EvaluateNoAutomaticTriggerCancellation(callTask, expectedCancellation: false);
            }
        }
            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);
            }
        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 Stop_WhenUsingHostCall_DoesNotTriggerCancellationToken()
        {
            using (JobHost host = new JobHost(_hostConfiguration))
            {
                host.Start();

                Task callTask = InvokeNoAutomaticTriggerFunction(host);

                host.Stop();

                EvaluateNoAutomaticTriggerCancellation(callTask, expectedCancellation: false);
            }
        }
        public void Stop_WhenUsingTriggeredFunction_TriggersCancellationToken()
        {
            using (JobHost host = new JobHost(_hostConfiguration))
            {
                PrepareHostForTrigger(host, startHost: true);

                host.Stop();

                EvaluateTriggeredCancellation(expectedCancellation: true);
            }
        }
        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);
        }
        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 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();
            }
        }