Пример #1
0
        public async Task SequentialOrchestration()
        {
            using (JobHost host = TestHelpers.GetJobHost(this.loggerFactory, nameof(SequentialOrchestration)))
            {
                await host.StartAsync();

                var client = await host.StartFunctionAsync(nameof(TestOrchestrations.Factorial), 10, this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(30), this.output);

                Assert.Equal("Completed", status?.RuntimeStatus);
                Assert.Equal(10, status?.Input);
                Assert.Equal(3628800, status?.Output);

                await host.StopAsync();
            }

            // Assert log entry count
            if (this.useTestLogger)
            {
                var logger      = loggerProvider.CreatedLoggers.Single(l => l.Category == TestHelpers.LogCategory);
                var logMessages = logger.LogMessages.ToList();
                Assert.Equal(153, logMessages.Count);
            }
        }
Пример #2
0
        public async Task TimerExpiration()
        {
            string[] orchestratorFunctionNames =
            {
                nameof(TestOrchestrations.Approval)
            };
            using (JobHost host = TestHelpers.GetJobHost(this.loggerFactory, nameof(TimerExpiration)))
            {
                await host.StartAsync();

                var timeout = TimeSpan.FromSeconds(10);
                var client  = await host.StartFunctionAsync(orchestratorFunctionNames[0], timeout, this.output);

                // Need to wait for the instance to start before sending events to it.
                // TODO: This requirement may not be ideal and should be revisited.
                // BUG: https://github.com/Azure/azure-webjobs-sdk-script-pr/issues/37
                await client.WaitForStartupAsync(TimeSpan.FromSeconds(10), this.output);

                // Don't send any notification - let the internal timeout expire

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(20), this.output);

                Assert.Equal("Completed", status?.RuntimeStatus);
                Assert.Equal("Expired", status?.Output);

                await host.StopAsync();
            }

            if (this.useTestLogger)
            {
                TestHelpers.AssertLogMessageSequence(loggerProvider, "TimerExpiration", orchestratorFunctionNames);
            }
        }
Пример #3
0
        public async Task Orchestration_Activity()
        {
            string[] orchestratorFunctionNames =
            {
                nameof(TestOrchestrations.OrchestratorGreeting),
                nameof(TestOrchestrations.SayHelloWithActivity)
            };

            string activityFunctionName = nameof(TestActivities.Hello);

            using (JobHost host = TestHelpers.GetJobHost(this.loggerFactory, nameof(Orchestration_Activity)))
            {
                await host.StartAsync();

                var client = await host.StartFunctionAsync(orchestratorFunctionNames[0], null, this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(20), this.output);

                Assert.NotNull(status);
                Assert.Equal("Completed", status.RuntimeStatus);
                Assert.Equal(client.InstanceId, status.InstanceId);
                Assert.Equal(orchestratorFunctionNames[0], status?.Name);

                await host.StopAsync();
            }

            if (this.useTestLogger)
            {
                TestHelpers.AssertLogMessageSequence(loggerProvider, "Orchestration_Activity",
                                                     orchestratorFunctionNames, activityFunctionName);
            }
        }
Пример #4
0
        public async Task OrchestrationConcurrency()
        {
            using (JobHost host = TestHelpers.GetJobHost(this.loggerFactory, nameof(OrchestrationConcurrency)))
            {
                await host.StartAsync();

                Func <Task> orchestrationStarter = async delegate()
                {
                    var timeout = TimeSpan.FromSeconds(10);
                    var client  = await host.StartFunctionAsync(nameof(TestOrchestrations.Approval), timeout, this.output);

                    await client.WaitForCompletionAsync(TimeSpan.FromSeconds(60), this.output);

                    // Don't send any notification - let the internal timeout expire
                };

                int iterations = 100;
                var tasks      = new Task[iterations];
                for (int i = 0; i < iterations; i++)
                {
                    tasks[i] = orchestrationStarter();
                }

                // The 100 orchestrations above (which each delay for 10 seconds) should all complete in less than 70 seconds.
                Task parallelOrchestrations = Task.WhenAll(tasks);
                Task timeoutTask            = Task.Delay(TimeSpan.FromSeconds(70));

                Task winner = await Task.WhenAny(parallelOrchestrations, timeoutTask);

                Assert.Equal(parallelOrchestrations, winner);

                await host.StopAsync();
            }
        }
Пример #5
0
        public async Task UnhandledOrchestrationExceptionWithRetry()
        {
            string[] orchestratorFunctionNames =
            {
                nameof(TestOrchestrations.OrchestratorThrowWithRetry)
            };

            using (JobHost host =
                       TestHelpers.GetJobHost(loggerFactory, nameof(UnhandledOrchestrationExceptionWithRetry)))
            {
                await host.StartAsync();

                // Null input should result in ArgumentNullException in the orchestration code.
                var client = await host.StartFunctionAsync(orchestratorFunctionNames[0], null, this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(50), this.output);

                Assert.Equal("Failed", status?.RuntimeStatus);
                Assert.True(status?.Output.ToString().Contains("Value cannot be null"));

                await host.StopAsync();
            }

            if (this.useTestLogger)
            {
                TestHelpers.UnhandledOrchesterationExceptionWithRetry_AssertLogMessageSequence(loggerProvider, "UnhandledOrchestrationExceptionWithRetry",
                                                                                               orchestratorFunctionNames);
            }
        }
Пример #6
0
        public async Task UnhandledActivityExceptionWithRetry()
        {
            string[] orchestratorFunctionNames =
            {
                nameof(TestOrchestrations.ActivityThrowWithRetry)
            };
            string activityFunctionName = nameof(TestActivities.Throw);

            using (JobHost host = TestHelpers.GetJobHost(loggerFactory, nameof(UnhandledActivityExceptionWithRetry)))
            {
                await host.StartAsync();

                string message = "Kah-BOOOOM!!!";
                var    client  = await host.StartFunctionAsync(orchestratorFunctionNames[0], message, this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(40), this.output);

                Assert.Equal("Failed", status?.RuntimeStatus);

                // There aren't any exception details in the output: https://github.com/Azure/azure-webjobs-sdk-script-pr/issues/36
                Assert.True(status?.Output.ToString().Contains("Exception"));

                await host.StopAsync();
            }

            if (this.useTestLogger)
            {
                TestHelpers.AssertLogMessageSequence(loggerProvider, "UnhandledActivityExceptionWithRetry",
                                                     orchestratorFunctionNames, activityFunctionName);
            }
        }
Пример #7
0
        public async Task HelloWorldOrchestration_Activity()
        {
            string[] orchestratorFunctionNames =
            {
                nameof(TestOrchestrations.SayHelloWithActivity)
            };
            string activityFunctionName = nameof(TestActivities.Hello);

            using (JobHost host = TestHelpers.GetJobHost(this.loggerFactory, nameof(HelloWorldOrchestration_Activity)))
            {
                await host.StartAsync();

                var client = await host.StartFunctionAsync(orchestratorFunctionNames[0], "World", this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(30), this.output);

                Assert.Equal("Completed", status?.RuntimeStatus);
                Assert.Equal("World", status?.Input);
                Assert.Equal("Hello, World!", status?.Output);

                await host.StopAsync();
            }

            if (this.useTestLogger)
            {
                TestHelpers.AssertLogMessageSequence(loggerProvider, "HelloWorldOrchestration_Activity",
                                                     orchestratorFunctionNames, activityFunctionName);
            }
        }
Пример #8
0
        public async Task TerminateOrchestration()
        {
            string[] orchestratorFunctionNames =
            {
                nameof(TestOrchestrations.Counter)
            };

            using (JobHost host = TestHelpers.GetJobHost(this.loggerFactory, nameof(TerminateOrchestration)))
            {
                await host.StartAsync();

                // Using the counter orchestration because it will wait indefinitely for input.
                var client = await host.StartFunctionAsync(orchestratorFunctionNames[0], 0, this.output);

                // Need to wait for the instance to start before we can terminate it.
                // TODO: This requirement may not be ideal and should be revisited.
                // BUG: https://github.com/Azure/azure-webjobs-sdk-script-pr/issues/37
                await client.WaitForStartupAsync(TimeSpan.FromSeconds(10), this.output);

                await client.TerminateAsync("sayōnara");

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(10), this.output);

                Assert.Equal("Terminated", status?.RuntimeStatus);
                Assert.Equal("sayōnara", status?.Output);

                await host.StopAsync();
            }

            if (this.useTestLogger)
            {
                TestHelpers.AssertLogMessageSequence(loggerProvider, "TerminateOrchestration",
                                                     orchestratorFunctionNames);
            }
        }
Пример #9
0
        public async Task ActivityTriggerAsPOCO()
        {
            using (JobHost host = TestHelpers.GetJobHost(loggerFactory, nameof(ActivityTriggerAsPOCO)))
            {
                await host.StartAsync();

                // Using StartOrchestrationArgs to start an activity function because it's easier than creating a new type.
                var startArgs = new StartOrchestrationArgs();
                startArgs.FunctionName = nameof(TestActivities.BindToPOCO);

                var input = new { Foo = "Bar" };
                startArgs.Input = input;

                var timeout = Debugger.IsAttached ? TimeSpan.FromMinutes(5) : TimeSpan.FromSeconds(30);
                var client  = await host.StartFunctionAsync(nameof(TestOrchestrations.CallActivity), startArgs, this.output);

                var status = await client.WaitForCompletionAsync(timeout, this.output);

                // The function echos back the 'Foo' input property value
                Assert.Equal("Completed", status?.RuntimeStatus);
                Assert.Equal(input.Foo, status?.Output);

                await host.StopAsync();
            }
        }
        public async Task ActorOrchestration()
        {
            using (JobHost host = GetJobHost())
            {
                await host.StartAsync();

                int initialValue = 0;
                var client       = await host.StartFunctionAsync(nameof(Orchestrations.Counter), initialValue, this.output);

                // Need to wait for the instance to start before sending events to it.
                // TODO: This requirement may not be ideal and should be revisited.
                // BUG: https://github.com/Azure/azure-webjobs-sdk-script-pr/issues/37
                await client.WaitForStartupAsync(TimeSpan.FromSeconds(10), this.output);

                // Perform some operations
                await client.RaiseEventAsync("operation", "incr");

                // TODO: Sleeping to avoid a race condition where multiple ContinueAsNew messages
                //       are processed by the same instance at the same time, resulting in a corrupt
                //       storage failure in DTFx.
                // BUG: https://github.com/Azure/azure-webjobs-sdk-script-pr/issues/38
                await Task.Delay(2000);

                await client.RaiseEventAsync("operation", "incr");

                await Task.Delay(2000);

                await client.RaiseEventAsync("operation", "incr");

                await Task.Delay(2000);

                await client.RaiseEventAsync("operation", "decr");

                await Task.Delay(2000);

                await client.RaiseEventAsync("operation", "incr");

                await Task.Delay(2000);

                // Make sure it's still running and didn't complete early (or fail).
                var status = await client.GetStatusAsync();

                Assert.Equal("Running", status?.RuntimeStatus);

                // The end message will cause the actor to complete itself.
                await client.RaiseEventAsync("operation", "end");

                status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(10), this.output);

                Assert.Equal("Completed", status?.RuntimeStatus);
                Assert.Equal(3, (int)status?.Output);

                // When using ContinueAsNew, the original input is discarded and replaced with the most recent state.
                Assert.NotEqual(initialValue, status?.Input);

                await host.StopAsync();
            }
        }
Пример #11
0
        public async Task Orchestration_OnValidOrchestrator()
        {
            const string greetingName          = "ValidOrchestrator";
            const string validOrchestratorName = "SayHelloWithActivity";

            string[] orchestratorFunctionNames =
            {
                nameof(TestOrchestrations.CallOrchestrator),
                validOrchestratorName
            };
            string activityFunctionName = nameof(TestActivities.Hello);

            var input     = new { Foo = greetingName };
            var inputJson = JsonConvert.SerializeObject(input);

            using (JobHost host = TestHelpers.GetJobHost(this.loggerFactory, nameof(Orchestration_OnValidOrchestrator)))
            {
                await host.StartAsync();

                var startArgs = new StartOrchestrationArgs
                {
                    FunctionName = orchestratorFunctionNames[1],
                    Input        = input
                };

                // Function type call chain: 'CallActivity' (orchestrator) -> 'SayHelloWithActivity' (orchestrator) -> 'Hello' (activity)
                var client = await host.StartFunctionAsync(orchestratorFunctionNames[0], startArgs, this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(30), this.output);

                var statusInput = JsonConvert.DeserializeObject <Dictionary <string, object> >(status?.Input.ToString());

                Assert.NotNull(status);
                Assert.Equal("Completed", status.RuntimeStatus);
                Assert.Equal(client.InstanceId, status.InstanceId);
                Assert.Equal(validOrchestratorName, statusInput["FunctionName"].ToString());
                Assert.Contains(greetingName, statusInput["Input"].ToString());
                Assert.Equal($"Hello, [{inputJson}]!", status.Output.ToString());

                await host.StopAsync();

                if (this.useTestLogger)
                {
                    TestHelpers.AssertLogMessageSequence(loggerProvider, "Orchestration_OnValidOrchestrator",
                                                         orchestratorFunctionNames, activityFunctionName);
                }
            }
        }
Пример #12
0
        public async Task HandledActivityException()
        {
            using (JobHost host = TestHelpers.GetJobHost(this.loggerFactory, nameof(HandledActivityException)))
            {
                await host.StartAsync();

                // Empty string input should result in ArgumentNullException in the orchestration code.
                var client = await host.StartFunctionAsync(nameof(TestOrchestrations.TryCatchLoop), 5, this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(10), this.output);

                Assert.Equal("Completed", status?.RuntimeStatus);
                Assert.Equal(5, status?.Output);

                await host.StopAsync();
            }
        }
        public async Task HelloWorldOrchestration_Activity()
        {
            using (JobHost host = GetJobHost())
            {
                await host.StartAsync();

                var client = await host.StartFunctionAsync(nameof(Orchestrations.SayHelloWithActivity), "World", this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(30), this.output);

                Assert.Equal("Completed", status?.RuntimeStatus);
                Assert.Equal("World", status?.Input);
                Assert.Equal("Hello, World!", status?.Output);

                await host.StopAsync();
            }
        }
        public async Task SequentialOrchestration()
        {
            using (JobHost host = GetJobHost())
            {
                await host.StartAsync();

                var client = await host.StartFunctionAsync(nameof(Orchestrations.Factorial), 10, this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(30), this.output);

                Assert.Equal("Completed", status?.RuntimeStatus);
                Assert.Equal(10, status?.Input);
                Assert.Equal(3628800, status?.Output);

                await host.StopAsync();
            }
        }
Пример #15
0
        public async Task ParallelOrchestration()
        {
            using (JobHost host = TestHelpers.GetJobHost(this.loggerFactory, nameof(ParallelOrchestration)))
            {
                await host.StartAsync();

                var client = await host.StartFunctionAsync(nameof(TestOrchestrations.DiskUsage), Environment.CurrentDirectory, this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(90), this.output);

                Assert.Equal("Completed", status?.RuntimeStatus);
                Assert.Equal(Environment.CurrentDirectory, status?.Input);
                Assert.True((long?)status?.Output > 0L);

                await host.StopAsync();
            }
        }
Пример #16
0
        public async Task ActivityWithRetry_NullRetryOptions()
        {
            using (JobHost host = TestHelpers.GetJobHost(loggerFactory, nameof(ActivityWithRetry_NullRetryOptions)))
            {
                await host.StartAsync();

                string message = "Kah-BOOOOM!!!";
                string orchestratorFunctionName = nameof(TestOrchestrations.ActivityWithRetry_NullRetryOptions);
                var    client = await host.StartFunctionAsync(orchestratorFunctionName, message, this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(40), this.output);

                Assert.Equal("Failed", status?.RuntimeStatus);
                Assert.True(status?.Output.ToString().Contains("Value cannot be null."));
                Assert.True(status?.Output.ToString().Contains("Parameter name: retryOptions"));

                await host.StopAsync();
            }
        }
        public async Task UnhandledOrchestrationException()
        {
            using (JobHost host = GetJobHost())
            {
                await host.StartAsync();

                // Null input should result in ArgumentNullException in the orchestration code.
                var client = await host.StartFunctionAsync(nameof(Orchestrations.Throw), null, this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(10), this.output);

                Assert.Equal("Failed", status?.RuntimeStatus);

                // There aren't any exception details in the output: https://github.com/Azure/azure-webjobs-sdk-script-pr/issues/36
                Assert.True(status?.Output.ToString().Contains("Value cannot be null"));

                await host.StopAsync();
            }
        }
        public async Task UnhandledActivityException()
        {
            using (JobHost host = GetJobHost())
            {
                await host.StartAsync();

                string message = "Kah-BOOOOM!!!";
                var    client  = await host.StartFunctionAsync(nameof(Orchestrations.Throw), message, this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(10), this.output);

                Assert.Equal("Failed", status?.RuntimeStatus);

                // There aren't any exception details in the output: https://github.com/Azure/azure-webjobs-sdk-script-pr/issues/36
                Assert.True(status?.Output.ToString().Contains("Exception"));

                await host.StopAsync();
            }
        }
Пример #19
0
        public async Task ThrowExceptionOnLongTimer()
        {
            using (JobHost host = TestHelpers.GetJobHost(this.loggerFactory, nameof(Orchestration_OnValidOrchestrator)))
            {
                await host.StartAsync();

                // Right now, the limit for timers is 6 days. In the future, we'll extend this and update this test.
                // https://github.com/Azure/azure-functions-durable-extension/issues/14
                DateTime fireAt = DateTime.UtcNow.AddDays(7);
                var      client = await host.StartFunctionAsync(nameof(TestOrchestrations.Timer), fireAt, this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(30), this.output);

                Assert.NotNull(status);
                Assert.Equal("Failed", status.RuntimeStatus);
                Assert.True(status.Output.ToString().Contains("fireAt"));

                await host.StopAsync();
            }
        }
Пример #20
0
        public async Task Orchestration_OnUnregisteredOrchestrator()
        {
            const string unregisteredOrchestrator = "UnregisteredOrchestrator";

            string[] orchestratorFunctionNames =
            {
                nameof(TestOrchestrations.CallOrchestrator),
                unregisteredOrchestrator
            };

            string errorMessage = $"The function '{unregisteredOrchestrator}' doesn't exist, is disabled, or is not an orchestrator function";

            using (JobHost host = TestHelpers.GetJobHost(this.loggerFactory, nameof(Orchestration_OnUnregisteredActivity)))
            {
                await host.StartAsync();

                var startArgs = new StartOrchestrationArgs
                {
                    FunctionName = unregisteredOrchestrator,
                    Input        = new { Foo = "Bar" }
                };

                var client = await host.StartFunctionAsync(orchestratorFunctionNames[0], startArgs, this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(30), this.output);

                Assert.Equal("Failed", status?.RuntimeStatus);

                // There aren't any exception details in the output: https://github.com/Azure/azure-webjobs-sdk-script-pr/issues/36
                Assert.True(status?.Output.ToString().Contains(errorMessage));

                await host.StopAsync();
            }

            if (this.useTestLogger)
            {
                TestHelpers.AssertLogMessageSequence(loggerProvider, "Orchestration_OnUnregisteredOrchestrator",
                                                     orchestratorFunctionNames);
            }
        }
Пример #21
0
        public async Task OrchestrationWithRetry_NullRetryOptions()
        {
            string[] orchestratorFunctionNames =
            {
                nameof(TestOrchestrations.OrchestratorWithRetry_NullRetryOptions)
            };

            using (JobHost host = TestHelpers.GetJobHost(loggerFactory, nameof(OrchestrationWithRetry_NullRetryOptions)))
            {
                await host.StartAsync();

                // Null input should result in ArgumentNullException in the orchestration code.
                var client = await host.StartFunctionAsync(orchestratorFunctionNames[0], null, this.output);

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(50), this.output);

                Assert.Equal("Failed", status?.RuntimeStatus);
                Assert.True(status?.Output.ToString().Contains("Value cannot be null."));
                Assert.True(status?.Output.ToString().Contains("Parameter name: retryOptions"));

                await host.StopAsync();
            }
        }
Пример #22
0
        public async Task ActivityTriggerAsJObject()
        {
            using (JobHost host = TestHelpers.GetJobHost(loggerFactory, nameof(ActivityTriggerAsJObject)))
            {
                await host.StartAsync();

                // Using StartOrchestrationArgs to start an activity function because it's easier than creating a new type.
                var startArgs = new StartOrchestrationArgs();
                startArgs.FunctionName = nameof(TestActivities.BindToJObject);
                startArgs.Input        = new { Foo = "Bar" };

                var timeout = Debugger.IsAttached ? TimeSpan.FromMinutes(5) : TimeSpan.FromSeconds(30);
                var client  = await host.StartFunctionAsync(nameof(TestOrchestrations.CallActivity), startArgs, this.output);

                var status = await client.WaitForCompletionAsync(timeout, this.output);

                // The function checks to see if there is a property called "Foo" which is set to a value
                // called "Bar" and returns true if this is the case. Otherwise returns false.
                Assert.Equal("Completed", status?.RuntimeStatus);
                Assert.Equal(true, status?.Output);

                await host.StopAsync();
            }
        }
        public async Task TimerExpiration()
        {
            using (JobHost host = GetJobHost())
            {
                await host.StartAsync();

                var timeout = TimeSpan.FromSeconds(10);
                var client  = await host.StartFunctionAsync(nameof(Orchestrations.Approval), timeout, this.output);

                // Need to wait for the instance to start before sending events to it.
                // TODO: This requirement may not be ideal and should be revisited.
                // BUG: https://github.com/Azure/azure-webjobs-sdk-script-pr/issues/37
                await client.WaitForStartupAsync(TimeSpan.FromSeconds(10), this.output);

                // Don't send any notification - let the internal timeout expire

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(20), this.output);

                Assert.Equal("Completed", status?.RuntimeStatus);
                Assert.Equal("Expired", status?.Output);

                await host.StopAsync();
            }
        }
        public async Task TerminateOrchestration()
        {
            using (JobHost host = GetJobHost())
            {
                await host.StartAsync();

                // Using the counter orchestration because it will wait indefinitely for input.
                var client = await host.StartFunctionAsync(nameof(Orchestrations.Counter), 0, this.output);

                // Need to wait for the instance to start before we can terminate it.
                // TODO: This requirement may not be ideal and should be revisited.
                // BUG: https://github.com/Azure/azure-webjobs-sdk-script-pr/issues/37
                await client.WaitForStartupAsync(TimeSpan.FromSeconds(10), this.output);

                await client.TerminateAsync("sayōnara");

                var status = await client.WaitForCompletionAsync(TimeSpan.FromSeconds(10), this.output);

                Assert.Equal("Terminated", status?.RuntimeStatus);
                Assert.Equal("sayōnara", status?.Output);

                await host.StopAsync();
            }
        }
Пример #25
0
        public async Task StartOrchestration_OnUnregisteredOrchestrator()
        {
            const string activityFunctionName = "UnregisteredOrchestrator";
            string       errorMessage         = $"The function '{activityFunctionName}' doesn't exist, is disabled, or is not an orchestrator function";

            using (JobHost host = TestHelpers.GetJobHost(this.loggerFactory, nameof(StartOrchestration_OnUnregisteredOrchestrator)))
            {
                await host.StartAsync();

                Exception ex = await Assert.ThrowsAsync <FunctionInvocationException>(async() => await host.StartFunctionAsync("UnregisteredOrchestrator", "Unregistered", this.output));

                Assert.NotNull(ex.InnerException);
                Assert.Contains(errorMessage, ex.InnerException?.ToString());

                await host.StopAsync();
            }
        }