public void MissingHostJson_CreatesHostJson_withDefaultExtensionBundleId()
        {
            Assert.False(File.Exists(_hostJsonFile));
            TestMetricsLogger testMetricsLogger = new TestMetricsLogger();

            BuildHostJsonConfiguration(testMetricsLogger);

            AreExpectedMetricsGenerated(testMetricsLogger);

            Assert.Equal(_hostJsonWithBundles, File.ReadAllText(_hostJsonFile));

            var log = _loggerProvider.GetAllLogMessages().Single(l => l.FormattedMessage == "No host configuration file found. Creating a default host.json file.");

            Assert.Equal(LogLevel.Information, log.Level);
        }
コード例 #2
0
        public async Task Starting_MultipleJobhostChannels_Failed()
        {
            _testLoggerProvider.ClearAllLogMessages();
            int expectedProcessCount = 3;
            RpcFunctionInvocationDispatcher functionDispatcher = GetTestFunctionDispatcher(expectedProcessCount, throwOnProcessStartUp: true);
            await functionDispatcher.InitializeAsync(GetTestFunctionsList(RpcWorkerConstants.NodeLanguageWorkerName));

            var finalChannelCount = await WaitForJobhostWorkerChannelsToStartup(functionDispatcher, expectedProcessCount, false);

            Assert.Equal(expectedProcessCount, finalChannelCount);

            var logMessages = _testLoggerProvider.GetAllLogMessages().ToList();

            Assert.Equal(logMessages.Where(x => x.FormattedMessage
                                           .Contains("Failed to start a new language worker")).Count(), 3);
        }
コード例 #3
0
        public void LogExceptionReceivedEvent_NonTransientEvent_LoggedAsError()
        {
            var ex = new ServiceBusException(false);

            Assert.False(ex.IsTransient);
            ExceptionReceivedEventArgs e = new ExceptionReceivedEventArgs(ex, "TestAction", "TestEndpoint", "TestEntity", "TestClient");

            ServiceBusExtensionConfigProvider.LogExceptionReceivedEvent(e, _loggerFactory);

            var expectedMessage = $"MessageReceiver error (Action=TestAction, ClientId=TestClient, EntityPath=TestEntity, Endpoint=TestEndpoint)";
            var logMessage      = _loggerProvider.GetAllLogMessages().Single();

            Assert.Equal(LogLevel.Error, logMessage.Level);
            Assert.Same(ex, logMessage.Exception);
            Assert.Equal(expectedMessage, logMessage.FormattedMessage);
        }
コード例 #4
0
        public async Task HostRestart_Specialization_Succeeds()
        {
            _host.Setup(h => h.StartAsync(It.IsAny <CancellationToken>()))
            .Returns(Task.CompletedTask);

            var hostBuilder = new Mock <IScriptHostBuilder>();

            hostBuilder.Setup(b => b.BuildHost(It.IsAny <bool>(), It.IsAny <bool>()))
            .Returns(_host.Object);

            _webHostLoggerProvider = new TestLoggerProvider();
            _loggerFactory         = new LoggerFactory();
            _loggerFactory.AddProvider(_webHostLoggerProvider);

            _hostService = new WebJobsScriptHostService(
                _monitor, hostBuilder.Object, _loggerFactory, _mockRootServiceProvider.Object, _mockRootScopeFactory.Object,
                _mockScriptWebHostEnvironment.Object, _mockEnvironment.Object, _hostPerformanceManager, _healthMonitorOptions);

            await _hostService.StartAsync(CancellationToken.None);

            Thread restartHostThread    = new Thread(new ThreadStart(RestartHost));
            Thread specializeHostThread = new Thread(new ThreadStart(SpecializeHost));

            restartHostThread.Start();
            specializeHostThread.Start();
            restartHostThread.Join();
            specializeHostThread.Join();

            var logMessages = _webHostLoggerProvider.GetAllLogMessages().Where(m => m.FormattedMessage.Contains("Restarting host."));

            Assert.Equal(2, logMessages.Count());
        }
        public async Task HostRestart_BeforeStart_WaitsForStartToContinue()
        {
            _host = CreateMockHost();

            var hostBuilder = new Mock <IScriptHostBuilder>();

            hostBuilder.SetupSequence(b => b.BuildHost(It.IsAny <bool>(), It.IsAny <bool>()))
            .Returns(_host.Object)
            .Returns(_host.Object);

            _webHostLoggerProvider = new TestLoggerProvider();
            _loggerFactory         = new LoggerFactory();
            _loggerFactory.AddProvider(_webHostLoggerProvider);

            _hostService = new WebJobsScriptHostService(
                _monitor, hostBuilder.Object, _loggerFactory, _mockRootServiceProvider.Object, _mockRootScopeFactory.Object,
                _mockScriptWebHostEnvironment.Object, _mockEnvironment.Object, _hostPerformanceManager, _healthMonitorOptions);

            // Simulate a call to specialize coming from the PlaceholderSpecializationMiddleware. This
            // can happen before we ever start the service, which could create invalid state.
            Task restartTask = _hostService.RestartHostAsync(CancellationToken.None);

            await _hostService.StartAsync(CancellationToken.None);

            await restartTask;

            var messages = _webHostLoggerProvider.GetAllLogMessages();

            // The CancellationToken is canceled quick enough that we never build the initial host, so the
            // only one we start is the restarted/specialized one.
            Assert.NotNull(messages.Single(p => p.EventId.Id == 513)); // "Building" message
            Assert.NotNull(messages.Single(p => p.EventId.Id == 514)); // "StartupWasCanceled" message
            Assert.NotNull(messages.Single(p => p.EventId.Id == 520)); // "RestartBeforeStart" message
            _host.Verify(p => p.StartAsync(It.IsAny <CancellationToken>()), Times.Once);
        }
        public async Task GetExtensionsStartupTypes_UnableToDownloadExtensionBundle_ReturnsNull()
        {
            var mockExtensionBundleManager = new Mock <IExtensionBundleManager>();

            mockExtensionBundleManager.Setup(e => e.IsExtensionBundleConfigured()).Returns(true);
            mockExtensionBundleManager.Setup(e => e.GetExtensionBundlePath()).ReturnsAsync(string.Empty);

            TestLoggerProvider testLoggerProvider = new TestLoggerProvider();
            LoggerFactory      factory            = new LoggerFactory();
            TestMetricsLogger  testMetricsLogger  = new TestMetricsLogger();

            factory.AddProvider(testLoggerProvider);
            var testLogger = factory.CreateLogger <ScriptStartupTypeLocator>();

            var mockFunctionMetadataManager = GetTestFunctionMetadataManager(ImmutableArray <FunctionMetadata> .Empty);
            var discoverer = new ScriptStartupTypeLocator(string.Empty, testLogger, mockExtensionBundleManager.Object, mockFunctionMetadataManager, testMetricsLogger);

            // Act
            var types = await discoverer.GetExtensionsStartupTypesAsync();

            var traces = testLoggerProvider.GetAllLogMessages();

            // Assert
            Assert.True(traces.Any(m => string.Equals(m.FormattedMessage, $"Unable to find or download extension bundle")));
            AreExpectedMetricsGenerated(testMetricsLogger);
            Assert.NotNull(types);
            Assert.Equal(types.Count(), 0);
        }
コード例 #7
0
        public async Task RunAndBlock_SelfHost_Succeeds()
        {
            var loggerProvider             = new TestLoggerProvider();
            var loggerProviderFactory      = new TestLoggerProviderFactory(loggerProvider);
            ScriptHostConfiguration config = new ScriptHostConfiguration()
            {
                RootScriptPath = Environment.CurrentDirectory,
                IsSelfHost     = true
            };

            ScriptHostManager manager = null;

            LogMessage[] logs = null;
            using (manager = new ScriptHostManager(config, loggerProviderFactory: loggerProviderFactory))
            {
                var tIgnore = Task.Run(() => manager.RunAndBlock());

                await TestHelpers.Await(() =>
                {
                    logs = loggerProvider.GetAllLogMessages().Where(p => p.FormattedMessage != null).ToArray();
                    return(manager.State == ScriptHostState.Error || logs.Any(p => p.FormattedMessage.Contains("Job host started")));
                });

                Assert.Equal(ScriptHostState.Running, manager.State);
                Assert.Equal(0, logs.Count(p => p.Level == LogLevel.Error));
            }
        }
コード例 #8
0
        public void Capability_Handled_Correctly(string value)
        {
            MapField <string, string> addedCapabilities = new MapField <string, string>
            {
                { testCapability2, value }
            };

            _capabilities.UpdateCapabilities(addedCapabilities);

            Assert.Equal(value, _capabilities.GetCapabilityState(testCapability2));

            var logs = _loggerProvider.GetAllLogMessages().Select(p => p.FormattedMessage).ToArray();

            Assert.Collection(logs,
                              p => Assert.Equal($"Updating capabilities: {{ \"{testCapability2}\": \"{value}\" }}", p));
        }
        public async Task GetExtensionsStartupTypes_FiltersBuiltinExtensionsAsync()
        {
            var references = new[]
            {
                new ExtensionReference {
                    Name = "Http", TypeName = typeof(HttpWebJobsStartup).AssemblyQualifiedName
                },
                new ExtensionReference {
                    Name = "Timers", TypeName = typeof(ExtensionsWebJobsStartup).AssemblyQualifiedName
                },
                new ExtensionReference {
                    Name = "Storage", TypeName = typeof(AzureStorageWebJobsStartup).AssemblyQualifiedName
                },
            };

            var extensions = new JObject
            {
                { "extensions", JArray.FromObject(references) }
            };

            var mockExtensionBundleManager = new Mock <IExtensionBundleManager>();

            mockExtensionBundleManager.Setup(e => e.IsExtensionBundleConfigured()).Returns(false);

            using (var directory = new TempDirectory())
            {
                var binPath = Path.Combine(directory.Path, "bin");
                Directory.CreateDirectory(binPath);

                void CopyToBin(string path)
                {
                    File.Copy(path, Path.Combine(binPath, Path.GetFileName(path)));
                }

                CopyToBin(typeof(HttpWebJobsStartup).Assembly.Location);
                CopyToBin(typeof(ExtensionsWebJobsStartup).Assembly.Location);
                CopyToBin(typeof(AzureStorageWebJobsStartup).Assembly.Location);

                File.WriteAllText(Path.Combine(binPath, "extensions.json"), extensions.ToString());

                TestLoggerProvider testLoggerProvider = new TestLoggerProvider();
                LoggerFactory      factory            = new LoggerFactory();
                factory.AddProvider(testLoggerProvider);
                var testLogger = factory.CreateLogger <ScriptStartupTypeLocator>();

                var mockFunctionMetadataProvider = GetTestFunctionMetadataProvider(ImmutableArray <FunctionMetadata> .Empty);
                var discoverer = new ScriptStartupTypeLocator(directory.Path, testLogger, mockExtensionBundleManager.Object, mockFunctionMetadataProvider);

                // Act
                var types = await discoverer.GetExtensionsStartupTypesAsync();

                var traces = testLoggerProvider.GetAllLogMessages();

                // Assert
                Assert.Single(types);
                Assert.Equal(typeof(AzureStorageWebJobsStartup).FullName, types.Single().FullName);
                Assert.True(traces.Any(m => string.Equals(m.FormattedMessage, $"The extension startup type '{references[0].TypeName}' belongs to a builtin extension")));
                Assert.True(traces.Any(m => string.Equals(m.FormattedMessage, $"The extension startup type '{references[1].TypeName}' belongs to a builtin extension")));
            }
        }
コード例 #10
0
        public async Task ListCheckpointsAsync_LogsOnInvalidCheckpoints()
        {
            var testLoggerProvider = new TestLoggerProvider();
            Mock <BlobContainerClient> containerClientMock = new Mock <BlobContainerClient>(MockBehavior.Strict);

            containerClientMock.Setup(c => c.GetBlobsAsync(It.IsAny <BlobTraits>(), It.IsAny <BlobStates>(), It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Returns(AsyncPageable <BlobItem> .FromPages(new[]
            {
                Page <BlobItem> .FromValues(new[]
                {
                    BlobsModelFactory.BlobItem("testnamespace/testeventhubname/testconsumergroup/checkpoint/0", false, BlobsModelFactory.BlobItemProperties(false), metadata: new Dictionary <string, string>())
                }, null, Mock.Of <Response>())
            }));

            BlobsCheckpointStore store = new BlobsCheckpointStore(
                containerClientMock.Object,
                new BasicRetryPolicy(new EventHubsRetryOptions()),
                _functionId,
                testLoggerProvider.CreateLogger("TestLogger")
                );

            await store.ListCheckpointsAsync(_namespace, _eventHubName, _consumerGroup, CancellationToken.None);

            var warning         = testLoggerProvider.GetAllLogMessages().Single(p => p.Level == Extensions.Logging.LogLevel.Warning);
            var expectedWarning = "Function 'EventHubsTriggerFunction': An invalid checkpoint was found for partition: '0' of " +
                                  "FullyQualifiedNamespace: 'TestNamespace'; EventHubName: 'TestEventHubName'; ConsumerGroup: 'TestConsumerGroup'.  " +
                                  "This checkpoint is not valid and will be ignored.";

            Assert.AreEqual(expectedWarning, warning.FormattedMessage);
            testLoggerProvider.ClearAllLogMessages();
        }
        public void Initialize_AppliesLoggerConfig()
        {
            // Default mininum level is Information, so set this to Warning and make
            // sure Information-level logs are filtered

            TestLoggerProvider loggerProvider = new TestLoggerProvider();
            IHost host = new HostBuilder()
                         .ConfigureAppConfiguration(c =>
            {
                c.AddInMemoryCollection(new Dictionary <string, string>
                {
                    { ConfigurationPath.Combine(_loggingPath, "LogLevel", "Default"), "Warning" },
                });
            })
                         .ConfigureDefaultTestWebScriptHost()
                         .ConfigureLogging(l =>
            {
                l.AddProvider(loggerProvider);
            })
                         .Build();

            ILogger logger = host.Services.GetService <ILogger <LoggingConfigurationTests> >();

            logger.LogInformation("Information");
            logger.LogWarning("Warning");

            LogMessage messages = loggerProvider.GetAllLogMessages().Single();

            Assert.Equal("Warning", messages.FormattedMessage);
        }
コード例 #12
0
        public async Task GetExtensionsStartupTypes_ExtensionBundleReturnsNullPath_ReturnsNull()
        {
            var mockExtensionBundleManager = new Mock <IExtensionBundleManager>();

            mockExtensionBundleManager.Setup(e => e.IsExtensionBundleConfigured()).Returns(true);
            mockExtensionBundleManager.Setup(e => e.GetExtensionBundlePath()).ReturnsAsync(string.Empty);

            using (var directory = new TempDirectory())
            {
                TestLoggerProvider testLoggerProvider = new TestLoggerProvider();
                LoggerFactory      factory            = new LoggerFactory();
                factory.AddProvider(testLoggerProvider);
                var testLogger = factory.CreateLogger <ScriptStartupTypeLocator>();
                var discoverer = new ScriptStartupTypeLocator(string.Empty, testLogger, mockExtensionBundleManager.Object);

                // Act
                var types = await discoverer.GetExtensionsStartupTypesAsync();

                var traces = testLoggerProvider.GetAllLogMessages();

                // Assert
                Assert.Null(types);
                Assert.True(traces.Any(m => string.Equals(m.FormattedMessage, $"Unable to find or download extension bundle")));
            }
        }
コード例 #13
0
        public async Task Invoke_HandlesHttpExceptions()
        {
            var ex = new HttpException(StatusCodes.Status502BadGateway);

            using (var server = GetTestServer(_ => throw ex))
            {
                var client = server.CreateClient();
                HttpResponseMessage response = await client.GetAsync(string.Empty);

                Assert.Equal(ex.StatusCode, (int)response.StatusCode);

                var log = _loggerProvider.GetAllLogMessages().Single(p => p.Category.Contains(nameof(ExceptionMiddleware)));
                Assert.Equal("An unhandled host error has occurred.", log.FormattedMessage);
                Assert.Same(ex, log.Exception);
            }
        }
コード例 #14
0
        public async Task GetExtensionsStartupTypes_RejectsBundleBelowMinimumVersion()
        {
            using (var directory = GetTempDirectory())
            {
                TestMetricsLogger  testMetricsLogger  = new TestMetricsLogger();
                TestLoggerProvider testLoggerProvider = new TestLoggerProvider();
                LoggerFactory      factory            = new LoggerFactory();
                factory.AddProvider(testLoggerProvider);
                var testLogger = factory.CreateLogger <ScriptStartupTypeLocator>();

                var binPath = Path.Combine(directory.Path, "bin");

                var mockExtensionBundleManager = new Mock <IExtensionBundleManager>();
                mockExtensionBundleManager.Setup(e => e.IsExtensionBundleConfigured()).Returns(true);
                mockExtensionBundleManager.Setup(e => e.GetExtensionBundleBinPathAsync()).Returns(Task.FromResult(binPath));
                mockExtensionBundleManager.Setup(e => e.IsLegacyExtensionBundle()).Returns(false);
                mockExtensionBundleManager.Setup(e => e.GetExtensionBundleDetails()).Returns(Task.FromResult(GetV2BundleDetails("2.1.0")));

                var mockFunctionMetadataManager = GetTestFunctionMetadataManager();
                var languageWorkerOptions       = new OptionsWrapper <LanguageWorkerOptions>(new LanguageWorkerOptions());
                var discoverer = new ScriptStartupTypeLocator(directory.Path, testLogger, mockExtensionBundleManager.Object, mockFunctionMetadataManager, testMetricsLogger, languageWorkerOptions);

                // Act
                var exception = await Assert.ThrowsAsync <HostInitializationException>(async() => await discoverer.GetExtensionsStartupTypesAsync());

                var traces = testLoggerProvider.GetAllLogMessages();

                // Assert
                Assert.True(traces.Any(m => string.Equals(m.FormattedMessage, $"Referenced bundle Microsoft.Azure.Functions.ExtensionBundle of version 2.1.0 does not meet the required minimum version of 2.6.1. Update your extension bundle reference in host.json to reference 2.6.1 or later.")));
            }
        }
コード例 #15
0
        public async Task CustomMessageProcessorTest()
        {
            try
            {
                // Pass in a separate LoggerFactory to the CusomtMessagingProvider to make validation easier.
                LoggerFactory      loggerFactory  = new LoggerFactory();
                TestLoggerProvider loggerProvider = new TestLoggerProvider();
                loggerFactory.AddProvider(loggerProvider);

                _serviceBusConfig = new ServiceBusConfiguration();
                _serviceBusConfig.MessagingProvider = new CustomMessagingProvider(_serviceBusConfig, loggerFactory);

                JobHostConfiguration config = new JobHostConfiguration()
                {
                    NameResolver  = _nameResolver,
                    TypeLocator   = new FakeTypeLocator(typeof(ServiceBusTestJobs)),
                    LoggerFactory = _loggerFactory
                };

                config.UseServiceBus(_serviceBusConfig);
                JobHost host = new JobHost(config);

                await ServiceBusEndToEndInternal(typeof(ServiceBusTestJobs), host : host);

                // in addition to verifying that our custom processor was called, we're also
                // verifying here that extensions can log
                IEnumerable <LogMessage> messages = loggerProvider.GetAllLogMessages();
                Assert.Equal(4, messages.Count(p => p.FormattedMessage.Contains("Custom processor Begin called!")));
                Assert.Equal(4, messages.Count(p => p.FormattedMessage.Contains("Custom processor End called!")));
            }
            finally
            {
                await Cleanup();
            }
        }
コード例 #16
0
        public async Task AsyncChainEndToEnd()
        {
            using (_functionCompletedEvent = new ManualResetEvent(initialState: false))
            {
                TestLoggerProvider loggerProvider = await AsyncChainEndToEndInternal(_hostBuilder);

                string firstQueueName    = _resolver.ResolveInString(Queue1Name);
                string secondQueueName   = _resolver.ResolveInString(Queue2Name);
                string blobContainerName = _resolver.ResolveInString(ContainerName);

                string[] loggerOutputLines = loggerProvider.GetAllLogMessages()
                                             .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:",
                    "Microsoft.Azure.WebJobs.Host.EndToEndTests.AsyncChainEndToEndTests.WriteStartDataMessageToQueue",
                    "Microsoft.Azure.WebJobs.Host.EndToEndTests.AsyncChainEndToEndTests.QueueToQueueAsync",
                    "Microsoft.Azure.WebJobs.Host.EndToEndTests.AsyncChainEndToEndTests.QueueToBlobAsync",
                    "Microsoft.Azure.WebJobs.Host.EndToEndTests.AsyncChainEndToEndTests.AlwaysFailJob",
                    "Microsoft.Azure.WebJobs.Host.EndToEndTests.AsyncChainEndToEndTests.DisabledJob",
                    "Microsoft.Azure.WebJobs.Host.EndToEndTests.AsyncChainEndToEndTests.TimeoutJob",
                    "Microsoft.Azure.WebJobs.Host.EndToEndTests.AsyncChainEndToEndTests.TimeoutJob_Throw",
                    "Microsoft.Azure.WebJobs.Host.EndToEndTests.AsyncChainEndToEndTests.TimeoutJob_Throw_NoToken",
                    "Microsoft.Azure.WebJobs.Host.EndToEndTests.AsyncChainEndToEndTests.BlobToBlobAsync",
                    "Microsoft.Azure.WebJobs.Host.EndToEndTests.AsyncChainEndToEndTests.ReadResultBlob",
                    "Microsoft.Azure.WebJobs.Host.EndToEndTests.AsyncChainEndToEndTests.SystemParameterBindingOutput",
                    "Function 'AsyncChainEndToEndTests.DisabledJob' is disabled",
                    "Job host started",
                    "Executing 'AsyncChainEndToEndTests.WriteStartDataMessageToQueue' (Reason='This function was programmatically called via the host APIs.', Id=",
                    "Executed 'AsyncChainEndToEndTests.WriteStartDataMessageToQueue' (Succeeded, Id=",
                    string.Format("Executing 'AsyncChainEndToEndTests.QueueToQueueAsync' (Reason='New queue message detected on '{0}'.', Id=", firstQueueName),
                    "Executed 'AsyncChainEndToEndTests.QueueToQueueAsync' (Succeeded, Id=",
                    string.Format("Executing 'AsyncChainEndToEndTests.QueueToBlobAsync' (Reason='New queue message detected on '{0}'.', Id=", secondQueueName),
                    "Executed 'AsyncChainEndToEndTests.QueueToBlobAsync' (Succeeded, Id=",
                    string.Format("Executing 'AsyncChainEndToEndTests.BlobToBlobAsync' (Reason='New blob detected: {0}/Blob1', Id=", blobContainerName),
                    "Executed 'AsyncChainEndToEndTests.BlobToBlobAsync' (Succeeded, Id=",
                    "Job host stopped",
                    "Executing 'AsyncChainEndToEndTests.ReadResultBlob' (Reason='This function was programmatically called via the host APIs.', Id=",
                    "Executed 'AsyncChainEndToEndTests.ReadResultBlob' (Succeeded, Id=",
                    "User ILogger log",
                    "User TraceWriter log 1",
                    "User TraceWriter log 2",
                    "Starting JobHost",
                    "Stopping JobHost"
                }.OrderBy(p => p).ToArray();

                bool hasError = loggerOutputLines.Any(p => p.Contains("Function had errors"));
                Assert.False(hasError);

                // Validate logger output
                for (int i = 0; i < expectedOutputLines.Length; i++)
                {
                    Assert.StartsWith(expectedOutputLines[i], loggerOutputLines[i]);
                }
            }
        }
コード例 #17
0
        public async Task Initialize_PerformsExpectedRegistrations()
        {
            JobHostConfiguration config = new JobHostConfiguration();

            config.AddService <INameResolver>(new RandomNameResolver());

            TestLoggerProvider loggerProvider = new TestLoggerProvider();
            ILoggerFactory     loggerFactory  = new LoggerFactory();

            loggerFactory.AddProvider(loggerProvider);
            config.LoggerFactory = loggerFactory;

            ServiceBusConfiguration   serviceBusConfig          = new ServiceBusConfiguration();
            ServiceBusExtensionConfig serviceBusExtensionConfig = new ServiceBusExtensionConfig(serviceBusConfig);

            IExtensionRegistry extensions = config.GetService <IExtensionRegistry>();

            ITriggerBindingProvider[] triggerBindingProviders = extensions.GetExtensions <ITriggerBindingProvider>().ToArray();
            Assert.Empty(triggerBindingProviders);
            IBindingProvider[] bindingProviders = extensions.GetExtensions <IBindingProvider>().ToArray();
            Assert.Empty(bindingProviders);

            ExtensionConfigContext context = new ExtensionConfigContext
            {
                Config = config,
            };

            serviceBusExtensionConfig.Initialize(context);

            // ensure the ServiceBusTriggerAttributeBindingProvider was registered
            triggerBindingProviders = extensions.GetExtensions <ITriggerBindingProvider>().ToArray();
            Assert.Single(triggerBindingProviders);
            ServiceBusTriggerAttributeBindingProvider triggerBindingProvider = (ServiceBusTriggerAttributeBindingProvider)triggerBindingProviders[0];

            Assert.NotNull(triggerBindingProvider);

            // ensure the ServiceBusAttributeBindingProvider was registered
            bindingProviders = extensions.GetExtensions <IBindingProvider>().ToArray();
            Assert.Single(bindingProviders);
            ServiceBusAttributeBindingProvider bindingProvider = (ServiceBusAttributeBindingProvider)bindingProviders[0];

            Assert.NotNull(bindingProvider);

            // ensure the default MessageOptions exception handler is wired up
            var messageOptions = serviceBusConfig.MessageOptions;
            var ex             = new ServiceBusException(false);
            var args           = new ExceptionReceivedEventArgs(ex, "TestAction", "TestEndpoint", "TestEntityPath", "TestClientId");

            Assert.NotNull(serviceBusConfig.ExceptionHandler);

            // invoke the handler and make sure it logs
            await serviceBusConfig.MessageOptions.ExceptionReceivedHandler(args);

            string expectedMessage = "MessageReceiver error (Action=TestAction, ClientId=TestClientId, EntityPath=TestEntityPath, Endpoint=TestEndpoint)";
            var    logMessage      = loggerProvider.GetAllLogMessages().Single();

            Assert.Equal(LogLevel.Error, logMessage.Level);
            Assert.Equal(expectedMessage, logMessage.FormattedMessage);
            Assert.Same(ex, logMessage.Exception);
        }
コード例 #18
0
        public void LogExceptionReceivedEvent_NonTransientEvent_LoggedAsError()
        {
            var ex = new ServiceBusException(isTransient: false, message: "message");

            Assert.False(ex.IsTransient);
            ProcessErrorEventArgs e = new ProcessErrorEventArgs(ex, ServiceBusErrorSource.Abandon, "TestEndpoint", "TestEntity", CancellationToken.None);

            ServiceBusExtensionConfigProvider.LogExceptionReceivedEvent(e, _loggerFactory);

            var expectedMessage = $"Message processing error (Action=Abandon, EntityPath=TestEntity, Endpoint=TestEndpoint)";
            var logMessage      = _loggerProvider.GetAllLogMessages().Single();

            Assert.AreEqual(LogLevel.Error, logMessage.Level);
            Assert.AreSame(ex, logMessage.Exception);
            Assert.AreEqual(expectedMessage, logMessage.FormattedMessage);
        }
コード例 #19
0
        private async Task <LogMessage> RunTest(Action <IServiceCollection> configure = null)
        {
            LogMessage         invalidServicesMessage = null;
            TestLoggerProvider loggerProvider         = new TestLoggerProvider();

            var builder = Program.CreateWebHostBuilder(null)
                          .ConfigureLogging(b =>
            {
                b.AddProvider(loggerProvider);
            })
                          .ConfigureServices(s =>
            {
                s.AddSingleton <IConfigureBuilder <ILoggingBuilder> >(new DelegatedConfigureBuilder <ILoggingBuilder>(b =>
                {
                    b.AddProvider(loggerProvider);
                    configure?.Invoke(b.Services);
                }));

                string uniqueTestRootPath = Path.Combine(Path.GetTempPath(), "FunctionsTest", "DependencyValidatorTests");

                s.PostConfigureAll <ScriptApplicationHostOptions>(o =>
                {
                    o.IsSelfHost  = true;
                    o.LogPath     = Path.Combine(uniqueTestRootPath, "logs");
                    o.SecretsPath = Path.Combine(uniqueTestRootPath, "secrets");
                    o.ScriptPath  = uniqueTestRootPath;
                });
            });

            using (var host = builder.Build())
            {
                await host.StartAsync();

                await TestHelpers.Await(() =>
                {
                    return(loggerProvider.GetAllLogMessages()
                           .FirstOrDefault(p => p.FormattedMessage.StartsWith("Host initialization")) != null);
                }, userMessageCallback : () => loggerProvider.GetLog());

                invalidServicesMessage = loggerProvider.GetAllLogMessages()
                                         .FirstOrDefault(m => m.Category.EndsWith(nameof(DependencyValidator)));

                await host.StopAsync();
            }

            return(invalidServicesMessage);
        }
コード例 #20
0
        public async Task FunctionListener_RetriesOnListenerFailure_WhenPartialHostStartupEnabled()
        {
            Mock <IListener> badListener = new Mock <IListener>(MockBehavior.Strict);
            int failureCount             = 0;

            badListener.Setup(bl => bl.StartAsync(It.IsAny <CancellationToken>()))
            .Callback <CancellationToken>((ct) =>
            {
                if (failureCount++ < 3)
                {
                    throw new Exception("Listener Exploded!");
                }
            })
            .Returns(Task.CompletedTask);
            badListener.Setup(bl => bl.StopAsync(It.IsAny <CancellationToken>())).Returns(Task.CompletedTask);
            var listener = new FunctionListener(badListener.Object, fd, _loggerFactory, allowPartialHostStartup: true, minRetryInterval: TimeSpan.FromMilliseconds(10), maxRetryInterval: TimeSpan.FromMilliseconds(100));

            // we should return right away with the listener
            // attempting to restart in the background
            await listener.StartAsync(ct);

            string[] logs = null;
            await TestHelpers.Await(() =>
            {
                logs = _loggerProvider.GetAllLogMessages().Select(p => p.FormattedMessage).ToArray();
                return(logs.Last() == "Listener successfully started for function 'testfunc' after 3 retries.");
            });

            badListener.Verify(p => p.StartAsync(It.IsAny <CancellationToken>()), Times.Exactly(4));

            var validators = new Action <string>[]
            {
                p => Assert.Equal("The listener for function 'testfunc' was unable to start.", p),
                p => Assert.Equal("Retrying to start listener for function 'testfunc' (Attempt 1)", p),
                p => Assert.Equal("The listener for function 'testfunc' was unable to start.", p),
                p => Assert.Equal("Retrying to start listener for function 'testfunc' (Attempt 2)", p),
                p => Assert.Equal("The listener for function 'testfunc' was unable to start.", p),
                p => Assert.Equal("Retrying to start listener for function 'testfunc' (Attempt 3)", p),
                p => Assert.Equal("Listener successfully started for function 'testfunc' after 3 retries.", p)
            };

            Assert.Collection(logs, validators);

            await listener.StopAsync(ct);

            badListener.Verify(p => p.StopAsync(It.IsAny <CancellationToken>()), Times.Once());
        }
コード例 #21
0
        public async Task StartAssignment_AppliesAssignmentContext()
        {
            var envValue = new
            {
                Name  = Path.GetTempFileName().Replace(".", string.Empty),
                Value = Guid.NewGuid().ToString()
            };

            _settingsManager.SetSetting(EnvironmentSettingNames.AzureWebsitePlaceholderMode, "1");
            WebScriptHostManager.ResetStandbyMode();
            var context = new HostAssignmentContext
            {
                Environment = new Dictionary <string, string>
                {
                    { envValue.Name, envValue.Value }
                }
            };
            bool result = _instanceManager.StartAssignment(context);

            Assert.True(result);
            Assert.True(WebScriptHostManager.InStandbyMode);

            // specialization is done in the background
            await Task.Delay(500);

            var value = Environment.GetEnvironmentVariable(envValue.Name);

            Assert.Equal(value, envValue.Value);

            // verify logs
            var logs = _loggerProvider.GetAllLogMessages().Select(p => p.FormattedMessage).ToArray();

            Assert.Collection(logs,
                              p => Assert.StartsWith("Starting Assignment", p),
                              p => Assert.StartsWith("Applying 1 app setting(s)", p),
                              p => Assert.StartsWith("Triggering specialization", p));

            // calling again should return false, since we're no longer
            // in placeholder mode
            _loggerProvider.ClearAllLogMessages();
            result = _instanceManager.StartAssignment(context);
            Assert.False(result);

            logs = _loggerProvider.GetAllLogMessages().Select(p => p.FormattedMessage).ToArray();
            Assert.Collection(logs,
                              p => Assert.StartsWith("Assign called while host is not in placeholder mode", p));
        }
コード例 #22
0
        public void Synchronize_UpdatesValue()
        {
            _mockEnvironment.Setup(p => p.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteHostName)).Returns((string)null);
            _mockEnvironment.Setup(p => p.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteName)).Returns((string)null);

            Assert.Equal(null, _hostNameProvider.Value);

            // no header present
            HttpRequest request = new DefaultHttpContext().Request;

            _hostNameProvider.Synchronize(request, _logger);
            Assert.Equal(null, _hostNameProvider.Value);

            // empty header value
            request = new DefaultHttpContext().Request;
            request.Headers.Add(ScriptConstants.AntaresDefaultHostNameHeader, string.Empty);
            _hostNameProvider.Synchronize(request, _logger);
            Assert.Equal(null, _hostNameProvider.Value);

            // host provided via header - expect update
            request = new DefaultHttpContext().Request;
            request.Headers.Add(ScriptConstants.AntaresDefaultHostNameHeader, "test.azurewebsites.net");
            _hostNameProvider.Synchronize(request, _logger);
            Assert.Equal("test.azurewebsites.net", _hostNameProvider.Value);
            var logs = _loggerProvider.GetAllLogMessages();

            Assert.Equal(1, logs.Count);
            Assert.Equal("HostName updated from '(null)' to 'test.azurewebsites.net'", logs[0].FormattedMessage);

            // no change in header value - no update expected
            _loggerProvider.ClearAllLogMessages();
            _hostNameProvider.Synchronize(request, _logger);
            Assert.Equal("test.azurewebsites.net", _hostNameProvider.Value);
            Assert.Equal("test.azurewebsites.net", _hostNameProvider.Value);
            logs = _loggerProvider.GetAllLogMessages();
            Assert.Equal(0, logs.Count);

            // another change - expect update
            request = new DefaultHttpContext().Request;
            request.Headers.Add(ScriptConstants.AntaresDefaultHostNameHeader, "test2.azurewebsites.net");
            _hostNameProvider.Synchronize(request, _logger);
            Assert.Equal("test2.azurewebsites.net", _hostNameProvider.Value);
            logs = _loggerProvider.GetAllLogMessages();
            Assert.Equal(1, logs.Count);
            Assert.Equal("HostName updated from 'test.azurewebsites.net' to 'test2.azurewebsites.net'", logs[0].FormattedMessage);
        }
コード例 #23
0
        public void LogExceptionReceivedEvent_NonTransientEvent_LoggedAsError()
        {
            var ex = new EventHubsException(false);

            Assert.False(ex.IsTransient);
            var ctor = typeof(ExceptionReceivedEventArgs).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).Single();
            var e    = (ExceptionReceivedEventArgs)ctor.Invoke(new object[] { "TestHostName", "TestPartitionId", ex, "TestAction" });

            EventHubExtensionConfigProvider.LogExceptionReceivedEvent(e, _loggerFactory);

            string expectedMessage = "EventProcessorHost error (Action=TestAction, HostName=TestHostName, PartitionId=TestPartitionId)";
            var    logMessage      = _loggerProvider.GetAllLogMessages().Single();

            Assert.Equal(LogLevel.Error, logMessage.Level);
            Assert.Same(ex, logMessage.Exception);
            Assert.Equal(expectedMessage, logMessage.FormattedMessage);
        }
コード例 #24
0
        public void LogExceptionReceivedEvent_NonTransientEvent_LoggedAsError()
        {
            var ex = new ServiceBusException(false);

            Assert.False(ex.IsTransient);
            ExceptionReceivedEventArgs e = new ExceptionReceivedEventArgs(ex, "TestAction", "TestEndpoint", "TestEntity", "TestClient");

            ServiceBusTriggerAttributeBindingProvider.LogExceptionReceivedEvent(e, "TestFunction", _loggerFactory);

            var expectedMessage = $"Message processing error (Action=TestAction, ClientId=TestClient, EntityPath=TestEntity, Endpoint=TestEndpoint)";
            var logMessage      = _loggerProvider.GetAllLogMessages().Single();

            Assert.Equal(LogLevel.Error, logMessage.Level);
            Assert.Same(ex, logMessage.Exception);
            Assert.Equal(expectedMessage, logMessage.FormattedMessage);
            Assert.True(logMessage.Category.Contains("TestFunction"));
        }
コード例 #25
0
        public async Task SecretMigrate_Successful()
        {
            using (var directory = new TempDirectory())
            {
                try
                {
                    await _fixture.TestInitialize(SecretsRepositoryType.FileSystem, directory.Path);

                    var loggerProvider = new TestLoggerProvider();

                    var    fileRepo        = _fixture.GetFileSystemSecretsRepository();
                    string hostContent     = Guid.NewGuid().ToString();
                    string functionContent = Guid.NewGuid().ToString();
                    await fileRepo.WriteAsync(ScriptSecretsType.Host, "host", hostContent);

                    await fileRepo.WriteAsync(ScriptSecretsType.Function, "test1", functionContent);

                    _settingsManager.SetSetting(EnvironmentSettingNames.AzureWebsiteSlotName, "Production");
                    _settingsManager.SetSetting(EnvironmentSettingNames.AzureWebsiteName, "test-app");

                    var blobRepoMigration = _fixture.GetBlobStorageSecretsMigrationRepository(loggerProvider.CreateLogger(ScriptConstants.LogCategoryMigration));

                    await blobRepoMigration.ReadAsync(ScriptSecretsType.Host, "host");

                    var logs = loggerProvider.GetAllLogMessages().ToArray();
                    Assert.Contains(logs[logs.Length - 1].FormattedMessage, "Finished successfully.");
                    string hostContentFromBlob = await blobRepoMigration.ReadAsync(ScriptSecretsType.Host, "");

                    Assert.Equal(hostContent, hostContentFromBlob);
                    string hostContentFromFunction = await blobRepoMigration.ReadAsync(ScriptSecretsType.Function, "test1");

                    Assert.Equal(functionContent, hostContentFromFunction);

                    var blobRepoMigration2 = _fixture.GetBlobStorageSecretsMigrationRepository(loggerProvider.CreateLogger(""));
                    await blobRepoMigration2.ReadAsync(ScriptSecretsType.Host, "host");

                    logs = loggerProvider.GetAllLogMessages().ToArray();
                    Assert.Contains(logs[logs.Length - 1].FormattedMessage, "Sentinel file is detected.");
                }
                finally
                {
                    _settingsManager.SetSetting(EnvironmentSettingNames.AzureWebsiteSlotName, null);
                    _settingsManager.SetSetting(EnvironmentSettingNames.AzureWebsiteName, null);
                }
            }
        }
コード例 #26
0
        private async Task InitializeTestHostAsync(string testDirName, IEnvironment environment)
        {
            var httpConfig         = new HttpConfiguration();
            var uniqueTestRootPath = Path.Combine(_testRootPath, testDirName, Guid.NewGuid().ToString());

            _loggerProvider = new TestLoggerProvider();

            if (environment.IsAppServiceEnvironment())
            {
                // if the test is mocking App Service environment, we need
                // to also set the HOME and WEBSITE_SITE_NAME variables
                environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteHomePath, uniqueTestRootPath);
                environment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteName, "test-host-name");
            }

            var webHostBuilder = Program.CreateWebHostBuilder()
                                 .ConfigureAppConfiguration(c =>
            {
                // This source reads from AzureWebJobsScriptRoot, which does not work
                // with the custom paths that these tests are using.
                var source = c.Sources.OfType <WebScriptHostConfigurationSource>().SingleOrDefault();
                if (source != null)
                {
                    c.Sources.Remove(source);
                }
            })
                                 .ConfigureLogging(c =>
            {
                c.AddProvider(_loggerProvider);
            })
                                 .ConfigureServices(c =>
            {
                c.ConfigureAll <ScriptApplicationHostOptions>(o =>
                {
                    o.IsSelfHost  = true;
                    o.LogPath     = Path.Combine(uniqueTestRootPath, "logs");
                    o.SecretsPath = Path.Combine(uniqueTestRootPath, "secrets");
                    o.ScriptPath  = _expectedScriptPath = Path.Combine(uniqueTestRootPath, "wwwroot");
                });

                c.AddSingleton <IEnvironment>(_ => environment);

                c.AddSingleton <IConfigureBuilder <ILoggingBuilder> >(new DelegatedConfigureBuilder <ILoggingBuilder>(b => b.AddProvider(_loggerProvider)));
            });

            _httpServer             = new TestServer(webHostBuilder);
            _httpClient             = _httpServer.CreateClient();
            _httpClient.BaseAddress = new Uri("https://localhost/");

            TestHelpers.WaitForWebHost(_httpClient);

            var traces = _loggerProvider.GetAllLogMessages().ToArray();

            Assert.NotNull(traces.Single(p => p.FormattedMessage.StartsWith("Host is in standby mode")));

            _expectedHostId = await _httpServer.Host.Services.GetService <IHostIdProvider>().GetHostIdAsync(CancellationToken.None);
        }
コード例 #27
0
        public async Task DisposesScriptHost()
        {
            var metricsLogger = new TestMetricsLogger();

            var services = new ServiceCollection()
                           .AddLogging(l =>
            {
                l.Services.AddSingleton <ILoggerProvider, TestLoggerProvider>();
                l.AddFilter(_ => true);
            })
                           .BuildServiceProvider();

            var host = new Mock <IHost>();

            host.Setup(h => h.Services)
            .Returns(services);

            host.Setup(h => h.Dispose())
            .Callback(() =>
            {
                services.Dispose();
            });

            var hostBuilder = new Mock <IScriptHostBuilder>();

            hostBuilder.Setup(b => b.BuildHost(It.IsAny <bool>(), It.IsAny <bool>()))
            .Returns(host.Object);

            _webHostLoggerProvider = new TestLoggerProvider();
            _loggerFactory         = new LoggerFactory();
            _loggerFactory.AddProvider(_webHostLoggerProvider);

            _hostService = new WebJobsScriptHostService(
                _monitor, hostBuilder.Object, _loggerFactory,
                _mockScriptWebHostEnvironment.Object, _mockEnvironment.Object,
                _hostPerformanceManager, _healthMonitorOptions,
                metricsLogger, new Mock <IApplicationLifetime>().Object,
                _mockConfig, new TestScriptEventManager());

            var hostLogger = host.Object.GetTestLoggerProvider();

            await _hostService.StartAsync(CancellationToken.None);

            await _hostService.RestartHostAsync(CancellationToken.None);

            Assert.True(AreRequiredMetricsGenerated(metricsLogger));

            host.Verify(m => m.StopAsync(It.IsAny <CancellationToken>()), Times.Exactly(1));
            host.Verify(m => m.Dispose(), Times.Exactly(1));

            var allLogMessages = _webHostLoggerProvider.GetAllLogMessages();

            Assert.Contains(allLogMessages,
                            m => m.FormattedMessage != null &&
                            m.FormattedMessage.Contains("ScriptHost disposed"));
        }
コード例 #28
0
        public async Task ValidateContext_InvalidZipUrl_WebsiteUseZip_ReturnsError()
        {
            var environmentSettings = new Dictionary <string, string>()
            {
                { EnvironmentSettingNames.AzureWebsiteZipDeployment, "http://invalid.com/invalid/dne" }
            };

            var environment = new TestEnvironment();

            foreach (var(key, value) in environmentSettings)
            {
                environment.SetEnvironmentVariable(key, value);
            }

            var scriptWebEnvironment = new ScriptWebHostEnvironment(environment);

            var loggerFactory  = new LoggerFactory();
            var loggerProvider = new TestLoggerProvider();

            loggerFactory.AddProvider(loggerProvider);

            var handlerMock = new Mock <HttpMessageHandler>(MockBehavior.Strict);

            handlerMock.Protected().Setup <Task <HttpResponseMessage> >("SendAsync",
                                                                        ItExpr.IsAny <HttpRequestMessage>(),
                                                                        ItExpr.IsAny <CancellationToken>()).ReturnsAsync(new HttpResponseMessage
            {
                StatusCode = HttpStatusCode.NotFound
            });

            var instanceManager = new InstanceManager(_optionsFactory, new HttpClient(handlerMock.Object),
                                                      scriptWebEnvironment, environment, loggerFactory.CreateLogger <InstanceManager>(),
                                                      new TestMetricsLogger(), null);

            var assignmentContext = new HostAssignmentContext
            {
                SiteId          = 1234,
                SiteName        = "TestSite",
                Environment     = environmentSettings,
                IsWarmupRequest = false
            };

            string error = await instanceManager.ValidateContext(assignmentContext);

            Assert.Equal("Invalid zip url specified (StatusCode: NotFound)", error);

            var logs = loggerProvider.GetAllLogMessages().Select(p => p.FormattedMessage).ToArray();

            Assert.Collection(logs,
                              p => Assert.StartsWith("Validating host assignment context (SiteId: 1234, SiteName: 'TestSite'. IsWarmup: 'False')", p),
                              p => Assert.StartsWith($"Will be using {EnvironmentSettingNames.AzureWebsiteZipDeployment} app setting as zip url. IsWarmup: 'False'", p),
                              p => Assert.StartsWith("linux.container.specialization.zip.head failed", p),
                              p => Assert.StartsWith("linux.container.specialization.zip.head failed", p),
                              p => Assert.StartsWith("linux.container.specialization.zip.head failed", p),
                              p => Assert.StartsWith("ValidateContext failed", p));
        }
コード例 #29
0
        public async Task Invoke_HandlesHttpExceptions()
        {
            var             ex   = new HttpException(StatusCodes.Status502BadGateway);
            RequestDelegate next = (ctxt) =>
            {
                throw ex;
            };
            var middleware = new ExceptionMiddleware(next, _logger);

            var context = new DefaultHttpContext();
            await middleware.Invoke(context);

            Assert.Equal(ex.StatusCode, context.Response.StatusCode);

            var log = _loggerProvider.GetAllLogMessages().Single();

            Assert.Equal("An unhandled host error has occurred.", log.FormattedMessage);
            Assert.Same(ex, log.Exception);
        }
コード例 #30
0
        public async Task LoggerLogging()
        {
            using (_functionCompletedEvent = new ManualResetEvent(initialState: false))
            {
                TestLoggerProvider loggerProvider = await AsyncChainEndToEndInternal(_hostBuilder);

                // Validate Logger
                bool hasError = loggerProvider.GetAllLogMessages().Where(p => p.FormattedMessage != null && p.FormattedMessage.Contains("Error")).Any();
                Assert.False(hasError);

                IEnumerable <string> userLogMessages = loggerProvider.GetAllLogMessages()
                                                       .Where(p => p.Category.StartsWith("Function.") && p.Category.EndsWith(".User"))
                                                       .Select(p => p.FormattedMessage);

                Assert.Equal(3, userLogMessages.Count());
                Assert.NotNull(userLogMessages.SingleOrDefault(p => p == "User TraceWriter log 1"));
                Assert.NotNull(userLogMessages.SingleOrDefault(p => p == "User TraceWriter log 2"));
                Assert.NotNull(userLogMessages.SingleOrDefault(p => p == "User ILogger log"));
            }
        }