public static void Run(string connectionString)
        {
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);

            CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
            CreateTestQueues(queueClient);

            try
            {
                CloudQueue firstQueue = queueClient.GetQueueReference(_nameResolver.ResolveInString(FunctionChainingPerfTest.FirstQueueName));
                firstQueue.AddMessage(new CloudQueueMessage("Test"));

                _startBlock = MeasurementBlock.BeginNew(0, HostStartMetric);

                JobHostConfiguration hostConfig = new JobHostConfiguration(connectionString);
                hostConfig.NameResolver = _nameResolver;
                hostConfig.TypeLocator = new FakeTypeLocator(typeof(FunctionChainingPerfTest));

                JobHost host = new JobHost(hostConfig);
                _tokenSource = new CancellationTokenSource();
                Task stopTask = null;
                _tokenSource.Token.Register(() => stopTask = host.StopAsync());
                host.RunAndBlock();
                stopTask.GetAwaiter().GetResult();
            }
            finally
            {
                DeleteTestQueues(queueClient);
            }
        }
        public async Task Generate_EndToEnd()
        {
            // construct our TimerTrigger attribute ([TimerTrigger("00:00:02", RunOnStartup = true)])
            Collection<ParameterDescriptor> parameters = new Collection<ParameterDescriptor>();
            ParameterDescriptor parameter = new ParameterDescriptor("timerInfo", typeof(TimerInfo));
            ConstructorInfo ctorInfo = typeof(TimerTriggerAttribute).GetConstructor(new Type[] { typeof(string) });
            PropertyInfo runOnStartupProperty = typeof(TimerTriggerAttribute).GetProperty("RunOnStartup");
            CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(
                ctorInfo,
                new object[] { "00:00:02" },
                new PropertyInfo[] { runOnStartupProperty },
                new object[] { true });
            parameter.CustomAttributes.Add(attributeBuilder);
            parameters.Add(parameter);

            // create the FunctionDefinition
            FunctionMetadata metadata = new FunctionMetadata();
            TestInvoker invoker = new TestInvoker();
            FunctionDescriptor function = new FunctionDescriptor("TimerFunction", invoker, metadata, parameters);
            Collection<FunctionDescriptor> functions = new Collection<FunctionDescriptor>();
            functions.Add(function);

            // Get the Type Attributes (in this case, a TimeoutAttribute)
            ScriptHostConfiguration scriptConfig = new ScriptHostConfiguration();
            scriptConfig.FunctionTimeout = TimeSpan.FromMinutes(5);
            Collection<CustomAttributeBuilder> typeAttributes = ScriptHost.CreateTypeAttributes(scriptConfig);

            // generate the Type
            Type functionType = FunctionGenerator.Generate("TestScriptHost", "TestFunctions", typeAttributes, functions);

            // verify the generated function
            MethodInfo method = functionType.GetMethod("TimerFunction");
            TimeoutAttribute timeoutAttribute = (TimeoutAttribute)functionType.GetCustomAttributes().Single();
            Assert.Equal(TimeSpan.FromMinutes(5), timeoutAttribute.Timeout);
            Assert.True(timeoutAttribute.ThrowOnTimeout);
            Assert.True(timeoutAttribute.TimeoutWhileDebugging);
            ParameterInfo triggerParameter = method.GetParameters()[0];
            TimerTriggerAttribute triggerAttribute = triggerParameter.GetCustomAttribute<TimerTriggerAttribute>();
            Assert.NotNull(triggerAttribute);

            // start the JobHost which will start running the timer function
            JobHostConfiguration config = new JobHostConfiguration()
            {
                TypeLocator = new TypeLocator(functionType)
            };
            config.UseTimers();
            JobHost host = new JobHost(config);

            await host.StartAsync();
            await Task.Delay(3000);
            await host.StopAsync();

            // verify our custom invoker was called
            Assert.True(invoker.InvokeCount >= 2);
        }
Exemplo n.º 3
0
        public async Task Orchestration_OnUnregisteredActivity()
        {
            string[] orchestratorFunctionNames =
            {
                nameof(TestOrchestrations.CallActivity)
            };
            const string activityFunctionName = "UnregisteredActivity";
            string       errorMessage         = $"The function '{activityFunctionName}' doesn't exist, is disabled, or is not an activity function";

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

                var startArgs = new StartOrchestrationArgs
                {
                    FunctionName = activityFunctionName,
                    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_OnUnregisteredActivity",
                                                     orchestratorFunctionNames);
            }
        }
Exemplo n.º 4
0
        public async Task SingletonListener_MultipleHosts_OnlyOneHostRunsListener()
        {
            // create and start multiple hosts concurrently
            int            numHosts = 3;
            List <JobHost> hosts    = new List <JobHost>();

            Task[] tasks = new Task[numHosts];
            for (int i = 0; i < numHosts; i++)
            {
                JobHost host = CreateTestJobHost(i);
                hosts.Add(host);
                tasks[i] = host.StartAsync();
            }
            await Task.WhenAll(tasks);

            // verify that only 2 listeners were started (one for each of the singleton functions)
            Assert.Equal(3, TestTriggerAttributeBindingProvider.TestTriggerBinding.TestTriggerListener.StartCount);

            MethodInfo singletonListenerMethod = typeof(TestJobs).GetMethod("TriggerJob_SingletonListener");

            VerifyLeaseState(singletonListenerMethod, "Listener", LeaseState.Leased, LeaseStatus.Locked);

            MethodInfo singletonListenerAndFunctionMethod = typeof(TestJobs).GetMethod("SingletonTriggerJob_SingletonListener");

            VerifyLeaseState(singletonListenerAndFunctionMethod, "Listener", LeaseState.Leased, LeaseStatus.Locked);

            // stop all the hosts
            foreach (JobHost host in hosts)
            {
                await host.StopAsync();

                host.Dispose();
            }

            VerifyLeaseState(singletonListenerMethod, "Listener", LeaseState.Available, LeaseStatus.Unlocked);
            VerifyLeaseState(singletonListenerAndFunctionMethod, "Listener", LeaseState.Available, LeaseStatus.Unlocked);
        }
Exemplo n.º 5
0
        public async Task ServiceBusEndToEnd_CreatesEntities()
        {
            JobHost host      = null;
            var     startName = ResolveName(StartQueueName);
            var     topicName = ResolveName(TopicName);
            var     queueName = ResolveName(QueueNamePrefix);

            try
            {
                host = CreateHost(typeof(ServiceBusTestJobs_EntityCreation));
                await host.StartAsync();

                CreateStartMessage(_serviceBusConfig.ConnectionString, startName);
                CreateStartMessage(_serviceBusConfig.ConnectionString, startName + '1');
                CreateStartMessage(_serviceBusConfig.ConnectionString, startName + '2');

                await TestHelpers.Await(() =>
                {
                    return(_namespaceManager.TopicExists(topicName) &&
                           _namespaceManager.QueueExists(queueName + '1') &&
                           _namespaceManager.QueueExists(queueName + '2'));
                }, 30000);

                Assert.Throws <MessagingException>(() => _namespaceManager.QueueExists(topicName));
                Assert.Throws <MessagingException>(() => _namespaceManager.TopicExists(queueName + '1'));
                Assert.Throws <MessagingException>(() => _namespaceManager.TopicExists(queueName + '2'));
            }
            finally
            {
                host?.StopAsync();
                host?.Dispose();
                Cleanup();
                CleanupQueue(startName + '1');
                CleanupQueue(startName + '2');
                CleanupQueue(queueName + '2');
            }
        }
        public async Task EventCollectorOnly()
        {
            using (_functionCompletedEvent = new ManualResetEvent(initialState: false))
            {
                // aggregator is disabled by default in these tests

                // add a FunctionEventCollector
                var eventCollector = new TestFunctionEventCollector();

                _hostBuilder.ConfigureServices(services =>
                {
                    services.AddSingleton <IAsyncCollector <FunctionInstanceLogEntry> >(eventCollector);
                });

                IHost   host    = _hostBuilder.Build();
                JobHost jobHost = host.GetJobHost();

                await jobHost.StartAsync();

                await jobHost.CallAsync(typeof(AsyncChainEndToEndTests).GetMethod("WriteStartDataMessageToQueue"));

                var loggerProvider = host.GetTestLoggerProvider();
                await WaitForFunctionCompleteAsync(loggerProvider);

                // ensure all logs have had a chance to flush
                await Task.Delay(3000);

                await jobHost.StopAsync();

                // Make sure the aggregator was logged to
                var logger = host.GetTestLoggerProvider().CreatedLoggers.Where(l => l.Category == LogCategories.Aggregator).SingleOrDefault();
                Assert.Null(logger);

                // Make sure the eventCollector was logged
                eventCollector.AssertFunctionCount(4, loggerProvider.GetLogString());
            }
        }
        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();
            }
        }
        public async Task RaiseEventToSubOrchestration()
        {
            string taskHub = nameof(RaiseEventToSubOrchestration);

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

                var orchestrator = nameof(TestOrchestrations.CallOrchestrator);
                var timeout      = Debugger.IsAttached ? TimeSpan.FromMinutes(5) : TimeSpan.FromSeconds(30);

                var input = new StartOrchestrationArgs
                {
                    FunctionName = nameof(TestOrchestrations.Approval),
                    InstanceId   = "SubOrchestration-" + Guid.NewGuid().ToString("N"),
                    Input        = TimeSpan.FromMinutes(5)
                };

                var client = await host.StartOrchestratorAsync(orchestrator, input, this.output);

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

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

                // Wait long enough for the sub-orchestration to be started and waiting for input.
                await Task.Delay(TimeSpan.FromSeconds(2));

                await client.InnerClient.RaiseEventAsync(input.InstanceId, "approval", true);

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

                Assert.Equal("Approved", status?.Output);

                await host.StopAsync();
            }
        }
Exemplo n.º 10
0
        public async Task ActivityTriggerAsPOCO()
        {
            using (JobHost host = TestHelpers.GetJobHost(this.loggerProvider, nameof(this.ActivityTriggerAsPOCO), false))
            {
                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 client = await host.StartOrchestratorAsync(nameof(TestOrchestrations.CallActivity), startArgs, this.output);

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

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

                await host.StopAsync();
            }
        }
        private async Task AsyncChainEndToEndInternal()
        {
            JobHost host = new JobHost(_hostConfig);

            Assert.Null(_hostConfig.HostId);

            await host.StartAsync();

            Assert.NotEmpty(_hostConfig.HostId);

            await host.CallAsync(typeof(AsyncChainEndToEndTests).GetMethod("WriteStartDataMessageToQueue"));

            await TestHelpers.Await(() => _functionCompletedEvent.WaitOne(200), 30000);

            // ensure all logs have had a chance to flush
            await Task.Delay(3000);

            // Stop async waits for the function to complete
            await host.StopAsync();

            await host.CallAsync(typeof(AsyncChainEndToEndTests).GetMethod("ReadResultBlob"));

            Assert.Equal("async works", _finalBlobContent);
        }
Exemplo n.º 12
0
        public async Task AggregatorAndEventCollector()
        {
            using (_functionCompletedEvent = new ManualResetEvent(initialState: false))
            {
                _hostConfig.Tracing.ConsoleLevel = TraceLevel.Off;

                // enable the aggregator
                _hostConfig.Aggregator.IsEnabled = true;
                _hostConfig.Aggregator.BatchSize = 1;

                // add a FunctionEventCollector
                var eventCollector = new TestFunctionEventCollector();
                _hostConfig.AddService <IAsyncCollector <FunctionInstanceLogEntry> >(eventCollector);

                JobHost host = new JobHost(_hostConfig);

                await host.StartAsync();

                await host.CallAsync(typeof(AsyncChainEndToEndTests).GetMethod("WriteStartDataMessageToQueue"));

                _functionCompletedEvent.WaitOne();

                // ensure all logs have had a chance to flush
                await Task.Delay(3000);

                await host.StopAsync();

                // Make sure the aggregator was logged to
                var logger = _loggerProvider.CreatedLoggers.Where(l => l.Category == LogCategories.Aggregator).Single();
                Assert.Equal(4, logger.LogMessages.Count);

                // Make sure the eventCollector was logged to
                // The aggregator ignores 'start' evetns, so this will be double
                Assert.Equal(8, eventCollector.LogCount);
            }
        }
Exemplo n.º 13
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 QuickPulse_Works_EvenIfFiltered(LogLevel defaultLevel, int expectedTelemetryItems)
        {
            LogCategoryFilter filter = new LogCategoryFilter();

            filter.DefaultLevel = defaultLevel;

            var loggerFactory = new LoggerFactory()
                                .AddApplicationInsights(
                new TestTelemetryClientFactory(filter.Filter, _channel));

            JobHostConfiguration config = new JobHostConfiguration
            {
                LoggerFactory = loggerFactory,
                TypeLocator   = new FakeTypeLocator(GetType()),
            };

            config.Aggregator.IsEnabled = false;

            var listener = new ApplicationInsightsTestListener();
            int requests = 5;

            try
            {
                listener.StartListening();

                using (JobHost host = new JobHost(config))
                {
                    await host.StartAsync();

                    var methodInfo = GetType().GetMethod(nameof(TestApplicationInsightsWarning), BindingFlags.Public | BindingFlags.Static);

                    for (int i = 0; i < requests; i++)
                    {
                        await host.CallAsync(methodInfo);
                    }

                    await host.StopAsync();
                }
            }
            finally
            {
                listener.StopListening();
            }

            // wait for everything to flush
            await Task.Delay(2000);

            // Sum up all req/sec calls that we've received.
            var reqPerSec = listener
                            .QuickPulseItems.Select(p => p.Metrics.Where(q => q.Name == @"\ApplicationInsights\Requests/Sec").Single());
            double sum = reqPerSec.Sum(p => p.Value);

            // All requests will go to QuickPulse.
            // The calculated RPS may off, so give some wiggle room. The important thing is that it's generating
            // RequestTelemetry and not being filtered.
            double max = requests + 3;
            double min = requests - 2;

            Assert.True(sum > min && sum < max, $"Expected sum to be greater than {min} and less than {max}. DefaultLevel: {defaultLevel}. Actual: {sum}");

            // These will be filtered based on the default filter.
            var infos = _channel.Telemetries.OfType <TraceTelemetry>().Where(t => t.SeverityLevel == SeverityLevel.Information);
            var warns = _channel.Telemetries.OfType <TraceTelemetry>().Where(t => t.SeverityLevel == SeverityLevel.Warning);
            var errs  = _channel.Telemetries.OfType <TraceTelemetry>().Where(t => t.SeverityLevel == SeverityLevel.Error);

            Assert.Equal(expectedTelemetryItems, _channel.Telemetries.Count());
        }
Exemplo n.º 15
0
        public async Task Generate_EndToEnd()
        {
            // construct our TimerTrigger attribute ([TimerTrigger("00:00:02", RunOnStartup = true)])
            Collection <ParameterDescriptor> parameters = new Collection <ParameterDescriptor>();
            ParameterDescriptor    parameter            = new ParameterDescriptor("timerInfo", typeof(TimerInfo));
            ConstructorInfo        ctorInfo             = typeof(TimerTriggerAttribute).GetConstructor(new Type[] { typeof(string) });
            PropertyInfo           runOnStartupProperty = typeof(TimerTriggerAttribute).GetProperty("RunOnStartup");
            CustomAttributeBuilder attributeBuilder     = new CustomAttributeBuilder(
                ctorInfo,
                new object[] { "00:00:02" },
                new PropertyInfo[] { runOnStartupProperty },
                new object[] { true });

            parameter.CustomAttributes.Add(attributeBuilder);
            parameters.Add(parameter);

            // create the FunctionDefinition
            FunctionMetadata   metadata = new FunctionMetadata();
            TestInvoker        invoker  = new TestInvoker();
            FunctionDescriptor function = new FunctionDescriptor("TimerFunction", invoker, metadata, parameters);
            Collection <FunctionDescriptor> functions = new Collection <FunctionDescriptor>();

            functions.Add(function);

            // Get the Type Attributes (in this case, a TimeoutAttribute)
            ScriptHostConfiguration scriptConfig = new ScriptHostConfiguration();

            scriptConfig.FunctionTimeout = TimeSpan.FromMinutes(5);
            Collection <CustomAttributeBuilder> typeAttributes = ScriptHost.CreateTypeAttributes(scriptConfig);

            // generate the Type
            Type functionType = FunctionGenerator.Generate("TestScriptHost", "TestFunctions", typeAttributes, functions);

            // verify the generated function
            MethodInfo       method           = functionType.GetMethod("TimerFunction");
            TimeoutAttribute timeoutAttribute = (TimeoutAttribute)functionType.GetCustomAttributes().Single();

            Assert.Equal(TimeSpan.FromMinutes(5), timeoutAttribute.Timeout);
            Assert.True(timeoutAttribute.ThrowOnTimeout);
            Assert.True(timeoutAttribute.TimeoutWhileDebugging);
            ParameterInfo         triggerParameter = method.GetParameters()[0];
            TimerTriggerAttribute triggerAttribute = triggerParameter.GetCustomAttribute <TimerTriggerAttribute>();

            Assert.NotNull(triggerAttribute);

            // start the JobHost which will start running the timer function
            JobHostConfiguration config = new JobHostConfiguration()
            {
                TypeLocator = new TypeLocator(functionType)
            };

            config.UseTimers();
            JobHost host = new JobHost(config);

            await host.StartAsync();

            await Task.Delay(3000);

            await host.StopAsync();

            // verify our custom invoker was called
            Assert.True(invoker.InvokeCount >= 2);
        }
Exemplo n.º 16
0
        public void StopAsync_WhenAlreadyStopping_ReturnsSameTask()
        {
            // Arrange
            using (JobHost host = new JobHost(CreateConfiguration()))
            {
                host.Start();

                // Replace (and cleanup) the existing listener to hook StopAsync.
                IListener oldRunner = host.Listener;
                oldRunner.StopAsync(CancellationToken.None).GetAwaiter().GetResult();

                TaskCompletionSource<object> stopTaskSource = new TaskCompletionSource<object>();
                Mock<IListener> listenerMock = new Mock<IListener>(MockBehavior.Strict);
                listenerMock.Setup(r => r.StopAsync(It.IsAny<CancellationToken>())).Returns(stopTaskSource.Task);
                listenerMock.Setup(r => r.Dispose());
                host.Listener = listenerMock.Object;
                Task alreadyStopping = host.StopAsync();

                // Act
                Task stoppingAgain = host.StopAsync();

                // Assert
                Assert.Same(alreadyStopping, stoppingAgain);

                // Cleanup
                stopTaskSource.SetResult(null);
                alreadyStopping.GetAwaiter().GetResult();
                stoppingAgain.GetAwaiter().GetResult();
            }
        }
Exemplo n.º 17
0
        public void StopAsync_WhenStarting_Throws()
        {
            // Arrange
            TaskCompletionSource<IStorageAccount> getAccountTaskSource = new TaskCompletionSource<IStorageAccount>();
            TestJobHostConfiguration configuration = CreateConfiguration(new LambdaStorageAccountProvider(
                    (i1, i2) => getAccountTaskSource.Task));

            using (JobHost host = new JobHost(configuration))
            {
                Task starting = host.StartAsync();
                Assert.False(starting.IsCompleted); // Guard

                // Act & Assert
                ExceptionAssert.ThrowsInvalidOperation(() => host.StopAsync(), "The host has not yet started.");

                // Cleanup
                getAccountTaskSource.SetResult(null);
                starting.GetAwaiter().GetResult();
            }
        }
Exemplo n.º 18
0
 public void StopAsync_WhenNotStarted_Throws()
 {
     // Arrange
     using (JobHost host = new JobHost(CreateConfiguration()))
     {
         // Act & Assert
         ExceptionAssert.ThrowsInvalidOperation(() => host.StopAsync(), "The host has not yet started.");
     }
 }
Exemplo n.º 19
0
        public void StopAsync_WhenStopped_DoesNotThrow()
        {
            // Arrange
            using (JobHost host = new JobHost(CreateConfiguration()))
            {
                host.Start();
                host.Stop();

                // Act & Assert
                host.StopAsync().GetAwaiter().GetResult();
            }
        }
Exemplo n.º 20
0
        public void StartAsync_WhenStopping_Throws()
        {
            // Arrange
            using (JobHost host = new JobHost(CreateConfiguration()))
            {
                host.Start();

                // Replace (and cleanup) the exsiting runner to hook StopAsync.
                IListener oldListener = host.Listener;
                oldListener.StopAsync(CancellationToken.None).GetAwaiter().GetResult();

                TaskCompletionSource<object> stopTaskSource = new TaskCompletionSource<object>();
                Mock<IListener> listenerMock = new Mock<IListener>(MockBehavior.Strict);
                listenerMock.Setup(r => r.StopAsync(It.IsAny<CancellationToken>())).Returns(stopTaskSource.Task);
                listenerMock.Setup(r => r.Dispose());
                host.Listener = listenerMock.Object;

                Task stopping = host.StopAsync();

                // Act & Assert
                ExceptionAssert.ThrowsInvalidOperation(() => host.StartAsync(), "Start has already been called.");

                // Cleanup
                stopTaskSource.SetResult(null);
                stopping.GetAwaiter().GetResult();
            }
        }
        public async Task OrchestrationStartAndCompleted(bool extendedSessionsEnabled)
        {
            var functionName            = nameof(TestOrchestrations.SayHelloInline);
            var eventGridKeyValue       = "testEventGridKey";
            var eventGridKeySettingName = "eventGridKeySettingName";
            var eventGridEndpoint       = "http://dymmy.com/";

            using (JobHost host = TestHelpers.GetJobHost(
                       this.loggerFactory,
                       nameof(this.OrchestrationStartAndCompleted),
                       extendedSessionsEnabled,
                       eventGridKeySettingName,
                       eventGridKeyValue,
                       eventGridEndpoint))
            {
                await host.StartAsync();

                string createdInstanceId = Guid.NewGuid().ToString("N");

                Func <HttpRequestMessage, HttpResponseMessage> responseGenerator =
                    (HttpRequestMessage req) => req.CreateResponse(HttpStatusCode.OK, "{\"message\":\"OK!\"}");

                int           callCount = 0;
                List <Action> eventGridRequestValidators = this.ConfigureEventGridMockHandler(
                    host,
                    functionName,
                    createdInstanceId,
                    eventGridKeyValue,
                    eventGridEndpoint,
                    responseGenerator,
                    handler: (JObject eventPayload) =>
                {
                    dynamic o = eventPayload;
                    if (callCount == 0)
                    {
                        Assert.Equal("durable/orchestrator/Running", (string)o.subject);
                        Assert.Equal("orchestratorEvent", (string)o.eventType);
                        Assert.Equal("Running", (string)o.data.runtimeStatus);
                    }
                    else if (callCount == 1)
                    {
                        Assert.Equal("durable/orchestrator/Completed", (string)o.subject);
                        Assert.Equal("orchestratorEvent", (string)o.eventType);
                        Assert.Equal("Completed", (string)o.data.runtimeStatus);
                    }
                    else
                    {
                        Assert.True(false, "The calls to Event Grid should be exactly 2 but we are registering more.");
                    }

                    callCount++;
                });

                var client = await host.StartOrchestratorAsync(
                    functionName,
                    "World",
                    this.output,
                    createdInstanceId);

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

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

                // There should be one validator for each Event Grid request.
                // Each validator is a delegate with several Assert statements.
                Assert.NotEmpty(eventGridRequestValidators);
                foreach (Action validator in eventGridRequestValidators)
                {
                    validator.Invoke();
                }

                Assert.Equal(2, callCount);

                await host.StopAsync();
            }
        }
Exemplo n.º 22
0
        public async Task ApplicationInsights_FailedFunction()
        {
            string            testName = nameof(TestApplicationInsightsFailure);
            LogCategoryFilter filter   = new LogCategoryFilter();

            filter.DefaultLevel = LogLevel.Information;

            var loggerFactory = new LoggerFactory()
                                .AddApplicationInsights(
                new TestTelemetryClientFactory(filter.Filter, _channel));

            JobHostConfiguration config = new JobHostConfiguration
            {
                LoggerFactory = loggerFactory,
                TypeLocator   = new FakeTypeLocator(GetType()),
            };

            config.Aggregator.IsEnabled = false;
            config.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler());

            using (JobHost host = new JobHost(config))
            {
                await host.StartAsync();

                var methodInfo = GetType().GetMethod(testName, BindingFlags.Public | BindingFlags.Static);
                await Assert.ThrowsAsync <FunctionInvocationException>(() => host.CallAsync(methodInfo, new { input = "function input" }));

                await host.StopAsync();
            }

            Assert.Equal(8, _channel.Telemetries.Count);

            // Validate the traces. Order by message string as the requests may come in
            // slightly out-of-order or on different threads
            TraceTelemetry[] telemetries = _channel.Telemetries
                                           .OfType <TraceTelemetry>()
                                           .OrderBy(t => t.Message)
                                           .ToArray();

            ValidateTrace(telemetries[0], "Found the following functions:\r\n", LogCategories.Startup);
            ValidateTrace(telemetries[1], "Job host started", LogCategories.Startup);
            ValidateTrace(telemetries[2], "Job host stopped", LogCategories.Startup);
            ValidateTrace(telemetries[3], "Logger", LogCategories.Function, testName, hasCustomScope: true);
            ValidateTrace(telemetries[4], "Trace", LogCategories.Function, testName);

            // Validate the exception
            ExceptionTelemetry[] exceptions = _channel.Telemetries
                                              .OfType <ExceptionTelemetry>()
                                              .OrderBy(t => t.Timestamp)
                                              .ToArray();
            Assert.Equal(2, exceptions.Length);
            ValidateException(exceptions[0], LogCategories.Function, testName);
            ValidateException(exceptions[1], LogCategories.Results, testName);

            // Finally, validate the request
            RequestTelemetry request = _channel.Telemetries
                                       .OfType <RequestTelemetry>()
                                       .Single();

            ValidateRequest(request, testName, false);
        }
Exemplo n.º 23
0
 /// <summary>
 /// <see cref="IJobHost.StopAsync"/>
 /// </summary>
 /// <returns></returns>
 public async Task StopAsync()
 {
     await _jobHost.StopAsync();
 }
        public async Task ApplicationInsights_SuccessfulFunction()
        {
            string            testName = nameof(TestApplicationInsightsInformation);
            LogCategoryFilter filter   = new LogCategoryFilter();

            filter.DefaultLevel = LogLevel.Information;

            var loggerFactory = new LoggerFactory()
                                .AddApplicationInsights(
                new TestTelemetryClientFactory(filter.Filter, _channel));

            JobHostConfiguration config = new JobHostConfiguration
            {
                LoggerFactory = loggerFactory,
                TypeLocator   = new FakeTypeLocator(GetType()),
            };

            config.Aggregator.IsEnabled = false;
            config.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler());

            using (JobHost host = new JobHost(config))
            {
                await host.StartAsync();

                var methodInfo = GetType().GetMethod(testName, BindingFlags.Public | BindingFlags.Static);
                await host.CallAsync(methodInfo, new { input = "function input" });

                await host.StopAsync();
            }

            Assert.Equal(9, _channel.Telemetries.Count);

            // Validate the traces. Order by message string as the requests may come in
            // slightly out-of-order or on different threads
            TraceTelemetry[] telemetries = _channel.Telemetries
                                           .OfType <TraceTelemetry>()
                                           .OrderBy(t => t.Message)
                                           .ToArray();

            string expectedFunctionCategory     = LogCategories.CreateFunctionCategory(testName);
            string expectedFunctionUserCategory = LogCategories.CreateFunctionUserCategory(testName);

            ValidateTrace(telemetries[0], "Executed ", expectedFunctionCategory, testName);
            ValidateTrace(telemetries[1], "Executing ", expectedFunctionCategory, testName);
            ValidateTrace(telemetries[2], "Found the following functions:\r\n", LogCategories.Startup);
            ValidateTrace(telemetries[3], "Job host started", LogCategories.Startup);
            ValidateTrace(telemetries[4], "Job host stopped", LogCategories.Startup);
            ValidateTrace(telemetries[5], "Logger", expectedFunctionUserCategory, testName, hasCustomScope: true);
            ValidateTrace(telemetries[6], "Trace", expectedFunctionUserCategory, testName);

            // We should have 1 custom metric.
            MetricTelemetry metric = _channel.Telemetries
                                     .OfType <MetricTelemetry>()
                                     .Single();

            ValidateMetric(metric, testName);

            // Finally, validate the request
            RequestTelemetry request = _channel.Telemetries
                                       .OfType <RequestTelemetry>()
                                       .Single();

            ValidateRequest(request, testName, true);
        }
        private async Task ServiceBusEndToEndInternal(Type jobContainerType, JobHost host = null, bool verifyLogs = true)
        {
            StringWriter consoleOutput = null;
            TextWriter   hold          = null;

            if (verifyLogs)
            {
                consoleOutput = new StringWriter();
                hold          = Console.Out;
                Console.SetOut(consoleOutput);
            }

            if (host == null)
            {
                host = CreateHost(jobContainerType);
            }

            await WriteQueueMessage(_serviceBusConfig.ConnectionString, FirstQueueName, "E2E");

            _topicSubscriptionCalled1 = new ManualResetEvent(initialState: false);
            _topicSubscriptionCalled2 = new ManualResetEvent(initialState: false);

            await host.StartAsync();

            _topicSubscriptionCalled1.WaitOne(SBTimeout);
            _topicSubscriptionCalled2.WaitOne(SBTimeout);

            // ensure all logs have had a chance to flush
            await Task.Delay(3000);

            // Wait for the host to terminate
            await host.StopAsync();

            host.Dispose();

            Assert.Equal("E2E-SBQueue2SBQueue-SBQueue2SBTopic-topic-1", _resultMessage1);
            Assert.Equal("E2E-SBQueue2SBQueue-SBQueue2SBTopic-topic-2", _resultMessage2);

            if (verifyLogs)
            {
                Console.SetOut(hold);

                string[] consoleOutputLines  = consoleOutput.ToString().Trim().Split(new string[] { Environment.NewLine }, StringSplitOptions.None).OrderBy(p => p).ToArray();
                string[] expectedOutputLines = new string[]
                {
                    "Found the following functions:",
                    string.Format("{0}.SBQueue2SBQueue", jobContainerType.FullName),
                    string.Format("{0}.MultipleAccounts", 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}'.', Id=", jobContainerType.Name, FirstQueueName),
                    string.Format("Executed '{0}.SBQueue2SBQueue' (Succeeded, Id=", jobContainerType.Name),
                    string.Format("Executing '{0}.SBQueue2SBTopic' (Reason='New ServiceBus message detected on '{1}'.', Id=", jobContainerType.Name, SecondQueueName),
                    string.Format("Executed '{0}.SBQueue2SBTopic' (Succeeded, Id=", jobContainerType.Name),
                    string.Format("Executing '{0}.SBTopicListener1' (Reason='New ServiceBus message detected on '{1}'.', Id=", jobContainerType.Name, EntityNameHelper.FormatSubscriptionPath(TopicName, TopicSubscriptionName1)),
                    string.Format("Executed '{0}.SBTopicListener1' (Succeeded, Id=", jobContainerType.Name),
                    string.Format("Executing '{0}.SBTopicListener2' (Reason='New ServiceBus message detected on '{1}'.', Id=", jobContainerType.Name, EntityNameHelper.FormatSubscriptionPath(TopicName, TopicSubscriptionName2)),
                    string.Format("Executed '{0}.SBTopicListener2' (Succeeded, Id=", jobContainerType.Name),
                    "Job host stopped"
                }.OrderBy(p => p).ToArray();

                bool hasError = consoleOutputLines.Any(p => p.Contains("Function had errors"));
                if (!hasError)
                {
                    for (int i = 0; i < expectedOutputLines.Length; i++)
                    {
                        Assert.StartsWith(expectedOutputLines[i], consoleOutputLines[i]);
                    }
                }
            }
        }
        public async Task OrchestrationStartAndCompleted()
        {
            string[] orchestratorFunctionNames =
            {
                nameof(TestOrchestrations.SayHelloInline),
            };

            var eventGridKeyValue       = "testEventGridKey";
            var eventGridKeySettingName = "eventGridKeySettingName";
            var eventGridEndpoint       = "http://dymmy.com/";
            var callCount = 0;

            using (JobHost host = TestHelpers.GetJobHost(this.loggerFactory, nameof(this.OrchestrationStartAndCompleted), eventGridKeySettingName, eventGridKeyValue, eventGridEndpoint))
            {
                await host.StartAsync();

                var extensionRegistry  = (IExtensionRegistry)host.Services.GetService(typeof(IExtensionRegistry));
                var extensionProviders = extensionRegistry.GetExtensions(typeof(IExtensionConfigProvider))
                                         .Where(x => x is DurableTaskExtension)
                                         .ToList();
                if (extensionProviders.Any())
                {
                    var extension = (DurableTaskExtension)extensionProviders.First();
                    var mock      = new Mock <HttpMessageHandler>();
                    mock.Protected()
                    .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
                    .Returns((HttpRequestMessage request, CancellationToken cancellationToken) =>
                    {
                        Assert.True(request.Headers.Any(x => x.Key == "aeg-sas-key"));
                        var values = request.Headers.GetValues("aeg-sas-key").ToList();
                        Assert.Single(values);
                        Assert.Equal(eventGridKeyValue, values[0]);
                        Assert.Equal(eventGridEndpoint, request.RequestUri.ToString());
                        var json        = request.Content.ReadAsStringAsync().GetAwaiter().GetResult();
                        dynamic content = JsonConvert.DeserializeObject(json);
                        foreach (dynamic o in content)
                        {
                            Assert.Equal("1.0", o.dataVersion.ToString());
                            Assert.Equal(nameof(this.OrchestrationStartAndCompleted), o.data.HubName.ToString());
                            Assert.Equal(orchestratorFunctionNames[0], o.data.FunctionName.ToString());

                            if (callCount == 0)
                            {
                                Assert.Equal("durable/orchestrator/Running", o.subject.ToString());
                                Assert.Equal("orchestratorEvent", o.eventType.ToString());
                                Assert.Equal("0", o.data.EventType.ToString());
                            }
                            else if (callCount == 1)
                            {
                                Assert.Equal("durable/orchestrator/Completed", o.subject.ToString());
                                Assert.Equal("orchestratorEvent", o.eventType.ToString());
                                Assert.Equal("1", o.data.EventType.ToString());
                            }
                            else
                            {
                                Assert.True(false, "The calls to Event Grid should be exactly 2 but we are registering more.");
                            }
                        }

                        callCount++;
                        var message     = new HttpResponseMessage(HttpStatusCode.OK);
                        message.Content = new StringContent("{\"message\":\"OK!\"}");
                        return(Task.FromResult(message));
                    });

                    extension.LifeCycleNotificationHelper.SetHttpMessageHandler(mock.Object);
                }

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

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

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

                await host.StopAsync();
            }
        }
        public async Task OrchestrationTerminate()
        {
            string[] orchestratorFunctionNames =
            {
                nameof(TestOrchestrations.Counter),
            };
            var eventGridKeyValue       = "testEventGridKey";
            var eventGridKeySettingName = "eventGridKeySettingName";
            var eventGridEndpoint       = "http://dymmy.com/";
            var callCount = 0;

            using (JobHost host = TestHelpers.GetJobHost(this.loggerFactory, nameof(this.OrchestrationTerminate), eventGridKeySettingName, eventGridKeyValue, eventGridEndpoint))
            {
                await host.StartAsync();

                var extensionRegistry  = (IExtensionRegistry)host.Services.GetService(typeof(IExtensionRegistry));
                var extensionProviders = extensionRegistry.GetExtensions(typeof(IExtensionConfigProvider))
                                         .Where(x => x is DurableTaskExtension)
                                         .ToList();

                if (extensionProviders.Any())
                {
                    var extension = (DurableTaskExtension)extensionProviders.First();
                    var mock      = new Mock <HttpMessageHandler>();
                    mock.Protected()
                    .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
                    .Returns((HttpRequestMessage request, CancellationToken cancellationToken) =>
                    {
                        Assert.True(request.Headers.Any(x => x.Key == "aeg-sas-key"));
                        var values = request.Headers.GetValues("aeg-sas-key").ToList();
                        Assert.Single(values);
                        Assert.Equal(eventGridKeyValue, values[0]);
                        Assert.Equal(eventGridEndpoint, request.RequestUri.ToString());
                        var json        = request.Content.ReadAsStringAsync().GetAwaiter().GetResult();
                        dynamic content = JsonConvert.DeserializeObject(json);
                        foreach (dynamic o in content)
                        {
                            Assert.Equal("1.0", o.dataVersion.ToString());
                            Assert.Equal(nameof(this.OrchestrationTerminate), o.data.HubName.ToString());
                            Assert.Equal(orchestratorFunctionNames[0], o.data.FunctionName.ToString());

                            if (callCount == 0)
                            {
                                Assert.Equal("durable/orchestrator/Running", o.subject.ToString());
                                Assert.Equal("orchestratorEvent", o.eventType.ToString());
                                Assert.Equal("0", o.data.EventType.ToString());
                            }
                            else if (callCount == 1)
                            {
                                Assert.Equal("durable/orchestrator/Terminated", o.subject.ToString());
                                Assert.Equal("orchestratorEvent", o.eventType.ToString());
                                Assert.Equal("5", o.data.EventType.ToString());
                            }
                            else
                            {
                                Assert.True(false, "The calls to Event Grid should be exactly 2 but we are registering more.");
                            }
                        }

                        callCount++;
                        var message     = new HttpResponseMessage(HttpStatusCode.OK);
                        message.Content = new StringContent("{\"message\":\"OK!\"}");
                        return(Task.FromResult(message));
                    });

                    extension.LifeCycleNotificationHelper.SetHttpMessageHandler(mock.Object);
                }

                // Using the counter orchestration because it will wait indefinitely for input.
                var client = await host.StartOrchestratorAsync(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-functions-durable-extension/issues/101
                await client.WaitForStartupAsync(TimeSpan.FromSeconds(30), this.output);

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

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

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

                await host.StopAsync();
            }
        }
Exemplo n.º 28
0
        public async Task ActorOrchestration()
        {
            using (JobHost host = TestHelpers.GetJobHost(this.loggerFactory, nameof(ActorOrchestration)))
            {
                await host.StartAsync();

                int initialValue = 0;
                var client       = await host.StartFunctionAsync(nameof(TestOrchestrations.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();
            }

            if (this.useTestLogger)
            {
                var logger      = loggerProvider.CreatedLoggers.Single(l => l.Category == TestHelpers.LogCategory);
                var logMessages = logger.LogMessages.ToList();
                Assert.Equal(49, logMessages.Count);
            }
        }
        public async Task OrchestrationTerminate(bool extendedSessionsEnabled)
        {
            // Using the counter orchestration because it will wait indefinitely for input.
            var functionName            = nameof(TestOrchestrations.Counter);
            var eventGridKeyValue       = "testEventGridKey";
            var eventGridKeySettingName = "eventGridKeySettingName";
            var eventGridEndpoint       = "http://dymmy.com/";

            using (JobHost host = TestHelpers.GetJobHost(
                       this.loggerFactory,
                       nameof(this.OrchestrationTerminate),
                       extendedSessionsEnabled,
                       eventGridKeySettingName,
                       eventGridKeyValue,
                       eventGridEndpoint))
            {
                await host.StartAsync();

                string createdInstanceId = Guid.NewGuid().ToString("N");

                Func <HttpRequestMessage, HttpResponseMessage> responseGenerator =
                    (HttpRequestMessage req) => req.CreateResponse(HttpStatusCode.OK, "{\"message\":\"OK!\"}");

                int           callCount = 0;
                List <Action> eventGridRequestValidators = this.ConfigureEventGridMockHandler(
                    host,
                    functionName,
                    createdInstanceId,
                    eventGridKeyValue,
                    eventGridEndpoint,
                    responseGenerator,
                    handler: (JObject eventPayload) =>
                {
                    dynamic o = eventPayload;
                    if (callCount == 0)
                    {
                        Assert.Equal("durable/orchestrator/Running", (string)o.subject);
                        Assert.Equal("orchestratorEvent", (string)o.eventType);
                        Assert.Equal("Running", (string)o.data.runtimeStatus);
                    }
                    else if (callCount == 1)
                    {
                        Assert.Equal("durable/orchestrator/Terminated", (string)o.subject);
                        Assert.Equal("orchestratorEvent", (string)o.eventType);
                        Assert.Equal("Terminated", (string)o.data.runtimeStatus);
                    }
                    else
                    {
                        Assert.True(false, "The calls to Event Grid should be exactly 2 but we are registering more.");
                    }

                    callCount++;
                });

                var client = await host.StartOrchestratorAsync(
                    functionName,
                    0,
                    this.output,
                    createdInstanceId);

                await client.WaitForStartupAsync(TimeSpan.FromSeconds(30), this.output);

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

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

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

                // There should be one validator for each Event Grid request.
                // Each validator is a delegate with several Assert statements.
                Assert.NotEmpty(eventGridRequestValidators);
                foreach (Action validator in eventGridRequestValidators)
                {
                    validator.Invoke();
                }

                // TODO: There should be two calls, but the termination notification is not being fired.
                //       https://github.com/Azure/azure-functions-durable-extension/issues/286
                Assert.Equal(1, callCount);
                await host.StopAsync();
            }
        }
Exemplo n.º 30
0
        private async Task ServiceBusEndToEndInternal(Type jobContainerType, JobHost host = null, bool verifyLogs = true)
        {
            if (host == null)
            {
                host = CreateHost(jobContainerType);
            }

            await WriteQueueMessage(_serviceBusConfig.ConnectionString, FirstQueueName, "E2E");

            _topicSubscriptionCalled1 = new ManualResetEvent(initialState: false);
            _topicSubscriptionCalled2 = new ManualResetEvent(initialState: false);

            await host.StartAsync();

            _topicSubscriptionCalled1.WaitOne(SBTimeout);
            _topicSubscriptionCalled2.WaitOne(SBTimeout);

            // ensure all logs have had a chance to flush
            await Task.Delay(3000);

            // Wait for the host to terminate
            await host.StopAsync();

            host.Dispose();

            Assert.Equal("E2E-SBQueue2SBQueue-SBQueue2SBTopic-topic-1", _resultMessage1);
            Assert.Equal("E2E-SBQueue2SBQueue-SBQueue2SBTopic-topic-2", _resultMessage2);

            if (verifyLogs)
            {
                IEnumerable <LogMessage> consoleOutput = _loggerProvider.GetAllLogMessages();

                Assert.DoesNotContain(consoleOutput, p => p.Level == LogLevel.Error);

                string[] consoleOutputLines = consoleOutput
                                              .Where(p => p.FormattedMessage != null)
                                              .SelectMany(p => p.FormattedMessage.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries))
                                              .OrderBy(p => p)
                                              .ToArray();

                string[] expectedOutputLines = new string[]
                {
                    "Found the following functions:",
                    $"{jobContainerType.FullName}.SBQueue2SBQueue",
                    $"{jobContainerType.FullName}.MultipleAccounts",
                    $"{jobContainerType.FullName}.SBQueue2SBTopic",
                    $"{jobContainerType.FullName}.SBTopicListener1",
                    $"{jobContainerType.FullName}.SBTopicListener2",
                    $"{jobContainerType.FullName}.ServiceBusBinderTest",
                    "Job host started",
                    $"Executing '{jobContainerType.Name}.SBQueue2SBQueue' (Reason='New ServiceBus message detected on '{FirstQueueName}'.', Id=",
                    $"Executed '{jobContainerType.Name}.SBQueue2SBQueue' (Succeeded, Id=",
                    $"Executing '{jobContainerType.Name}.SBQueue2SBTopic' (Reason='New ServiceBus message detected on '{SecondQueueName}'.', Id=",
                    $"Executed '{jobContainerType.Name}.SBQueue2SBTopic' (Succeeded, Id=",
                    $"Executing '{jobContainerType.Name}.SBTopicListener1' (Reason='New ServiceBus message detected on '{EntityNameHelper.FormatSubscriptionPath(TopicName, TopicSubscriptionName1)}'.', Id=",
                    $"Executed '{jobContainerType.Name}.SBTopicListener1' (Succeeded, Id=",
                    $"Executing '{jobContainerType.Name}.SBTopicListener2' (Reason='New ServiceBus message detected on '{EntityNameHelper.FormatSubscriptionPath(TopicName, TopicSubscriptionName2)}'.', Id=",
                    $"Executed '{jobContainerType.Name}.SBTopicListener2' (Succeeded, Id=",
                    "Job host stopped"
                }.OrderBy(p => p).ToArray();

                Action <string>[] inspectors = expectedOutputLines.Select <string, Action <string> >(p => (string m) => m.StartsWith(p)).ToArray();
                Assert.Collection(consoleOutputLines, inspectors);
            }
        }
        public async Task MultipleAccountTest()
        {
            try
            {
                TestTraceWriter trace = new TestTraceWriter(TraceLevel.Info);
                _serviceBusConfig = new ServiceBusConfiguration();
                _serviceBusConfig.MessagingProvider = new CustomMessagingProvider(_serviceBusConfig, trace);

                JobHostConfiguration config = new JobHostConfiguration()
                {
                    NameResolver = _nameResolver,
                    TypeLocator = new FakeTypeLocator(typeof(ServiceBusTestJobs))
                };
                config.Tracing.Tracers.Add(trace);
                config.UseServiceBus(_serviceBusConfig);
                JobHost host = new JobHost(config);

                string queueName = ResolveName(StartQueueName);
                string queuePrefix = queueName.Replace("-queue-start", "");
                string firstTopicName = string.Format("{0}-topic/Subscriptions/{0}-queue-topic-1", queuePrefix);

                WriteQueueMessage(_secondaryNamespaceManager, _secondaryConnectionString, queueName, "Test");

                _topicSubscriptionCalled1 = new ManualResetEvent(initialState: false);

                await host.StartAsync();

                _topicSubscriptionCalled1.WaitOne(SBTimeout);

                // ensure all logs have had a chance to flush
                await Task.Delay(3000);

                // Wait for the host to terminate
                await host.StopAsync();
                host.Dispose();

                Assert.Equal("Test-topic-1", _resultMessage1);
            }
            finally
            {
                Cleanup();
            }
        }