public void Trace_Ignores_FunctionUserCategory() { // Create a logger with the Function.{FunctionName}.User category, which is what determines user logs. ILogger logger = new SystemLogger(Guid.NewGuid().ToString(), LogCategories.CreateFunctionUserCategory(_functionName), _mockEventGenerator.Object, _settingsManager); logger.LogDebug("TestMessage"); // Make sure it's never been called. _mockEventGenerator.Verify(p => p.LogFunctionTraceEvent(It.IsAny <LogLevel>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), string.Empty, string.Empty, string.Empty, string.Empty, string.Empty), Times.Never); }
public Task <IValueProvider> BindAsync(BindingContext context) { if (context == null) { throw new ArgumentNullException("context"); } ILogger logger = _loggerFactory.CreateLogger(LogCategories.CreateFunctionUserCategory(context.ValueContext.FunctionContext.MethodName)); return(BindAsync(logger, context.ValueContext)); }
public SampleBotApplication( ILineMessagingClient lineMessagingClient, LineMessagingApiSettings settings, IDurableClientFactory durableClientFactory, INaturalLanguageUnderstandingClient nluClient, ILoggerFactory loggerFactory, params ISkill[] skills) : base(lineMessagingClient, settings, durableClientFactory, nluClient, loggerFactory.CreateLogger(LogCategories.CreateFunctionUserCategory(nameof(WebhookEndpointFunction))), skills) { LineMessagingClient = lineMessagingClient; }
protected async Task <LogMessage> WaitForTraceAsync(string functionName, Func <LogMessage, bool> filter) { LogMessage logMessage = null; await TestHelpers.Await(() => { logMessage = Fixture.Host.GetLogMessages(LogCategories.CreateFunctionUserCategory(functionName)).SingleOrDefault(filter); return(logMessage != null); }); return(logMessage); }
private static void ValidateMetric(MetricTelemetry telemetry, string expectedOperationId, string expectedOperationName) { ValidateTelemetry(telemetry, expectedOperationId, expectedOperationName, LogCategories.CreateFunctionUserCategory(expectedOperationName), SeverityLevel.Information); Assert.Equal("TestMetric", telemetry.Name); Assert.Equal(1234, telemetry.Sum); Assert.Equal(50, telemetry.Count); Assert.Equal(10.4, telemetry.Min); Assert.Equal(23, telemetry.Max); Assert.Equal("100", telemetry.Properties[$"{LogConstants.CustomPropertyPrefix}MyCustomMetricProperty"]); ValidateSdkVersion(telemetry); }
public async Task Scenario_Logging() { string testData = Guid.NewGuid().ToString(); JObject input = new JObject { { "scenario", "logging" }, { "input", testData }, }; Fixture.Host.ClearLogMessages(); await Fixture.Host.BeginFunctionAsync("Scenarios", input); string userCategory = LogCategories.CreateFunctionUserCategory("Scenarios"); IList <string> logs = null; await TestHelpers.Await(() => { logs = Fixture.Host.GetLogMessages(userCategory).Select(p => p.FormattedMessage).ToList(); return(logs.Count == 10); }, userMessageCallback : Fixture.Host.GetLog); // verify use of context.log to log complex objects LogMessage scriptTrace = Fixture.Host.GetLogMessages(userCategory).Single(p => p.FormattedMessage != null && p.FormattedMessage.Contains(testData)); Assert.Equal(LogLevel.Information, scriptTrace.Level); JObject logEntry = JObject.Parse(scriptTrace.FormattedMessage); Assert.Equal("This is a test", logEntry["message"]); Assert.Equal(testData, logEntry["input"]); // verify log levels in traces LogMessage[] traces = Fixture.Host.GetLogMessages(userCategory).Where(t => t.FormattedMessage != null && t.FormattedMessage.Contains("loglevel")).ToArray(); Assert.Equal(LogLevel.Information, traces[0].Level); Assert.Equal("loglevel default", traces[0].FormattedMessage); Assert.Equal(LogLevel.Information, traces[1].Level); Assert.Equal("loglevel info", traces[1].FormattedMessage); Assert.Equal(LogLevel.Trace, traces[2].Level); Assert.Equal("loglevel verbose", traces[2].FormattedMessage); Assert.Equal(LogLevel.Warning, traces[3].Level); Assert.Equal("loglevel warn", traces[3].FormattedMessage); Assert.Equal(LogLevel.Error, traces[4].Level); Assert.Equal("loglevel error", traces[4].FormattedMessage); // verify most of the logs look correct Assert.EndsWith("Mathew Charles", logs[1]); Assert.EndsWith("null", logs[2]); Assert.EndsWith("1234", logs[3]); Assert.EndsWith("true", logs[4]); Assert.EndsWith("loglevel default", logs[5]); Assert.EndsWith("loglevel info", logs[6]); }
public async Task ApplicationInsights_SuccessfulFunction() { string testName = nameof(TestApplicationInsightsInformation); using (IHost host = ConfigureHost()) { await host.StartAsync(); MethodInfo methodInfo = GetType().GetMethod(testName, BindingFlags.Public | BindingFlags.Static); await host.GetJobHost().CallAsync(methodInfo, new { input = "function input" }); await host.StopAsync(); Assert.Equal(11, _channel.Telemetries.Count); // Validate the request RequestTelemetry request = _channel.Telemetries .OfType <RequestTelemetry>() .Single(); ValidateRequest(request, testName, true); // invocation id is retrievable from the request request.Properties.TryGetValue(LogConstants.InvocationIdKey, out string invocationId); // 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, invocationId); ValidateTrace(telemetries[1], "Executing ", expectedFunctionCategory, testName, invocationId, request.Context.Operation.Id, request.Id); 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, invocationId, request.Context.Operation.Id, request.Id, hasCustomScope: true); ValidateTrace(telemetries[6], "Starting JobHost", "Microsoft.Azure.WebJobs.Hosting.JobHostService"); ValidateTrace(telemetries[7], "Stopping JobHost", "Microsoft.Azure.WebJobs.Hosting.JobHostService"); ValidateTrace(telemetries[8], "Trace", expectedFunctionUserCategory, testName, invocationId, request.Context.Operation.Id, request.Id); // We should have 1 custom metric. MetricTelemetry metric = _channel.Telemetries .OfType <MetricTelemetry>() .Single(); ValidateMetric(metric, testName); } }
private static ILogger CreateILogger(IServiceProvider serviceProvider) { ILogger toReturn = null; ILoggerFactory loggerFactory = serviceProvider.GetService <ILoggerFactory>(); string categoryName = LogCategories.CreateFunctionUserCategory( nameof(Dfe.CdcEventApi)); toReturn = loggerFactory.CreateLogger(categoryName); return(toReturn); }
private static void ValidateMetric(MetricTelemetry telemetry, string expectedOperationName) { Assert.Equal(expectedOperationName, telemetry.Context.Operation.Name); Assert.NotNull(telemetry.Context.Operation.Id); Assert.Equal(LogCategories.CreateFunctionUserCategory(expectedOperationName), telemetry.Properties[LogConstants.CategoryNameKey]); Assert.Equal(LogLevel.Information.ToString(), telemetry.Properties[LogConstants.LogLevelKey]); Assert.Equal("MyCustomMetric", telemetry.Name); Assert.Equal(5.1, telemetry.Sum); Assert.Equal(50, telemetry.Count); Assert.Equal(10.4, telemetry.Min); Assert.Equal(23, telemetry.Max); Assert.Null(telemetry.StandardDeviation); Assert.Equal("100", telemetry.Properties[$"{LogConstants.CustomPropertyPrefix}MyCustomMetricProperty"]); ValidateCustomScopeProperty(telemetry); ValidateSdkVersion(telemetry); }
public Task <IValueProvider> BindAsync(BindingContext context) { if (context == null) { throw new ArgumentNullException("context"); } ILogger logger = _loggerFactory.CreateLogger(LogCategories.CreateFunctionUserCategory(context.ValueContext.FunctionContext.MethodName)); TraceWriter trace = new LoggerTraceWriter(logger); object tracer = trace; if (_parameter.ParameterType == typeof(TextWriter)) { // bind to an adapter tracer = TextWriterTraceAdapter.Synchronized(trace); } return(BindAsync(tracer, context.ValueContext)); }
public IServiceProvider Build() { var services = new ServiceCollection(); services.AddSingleton(_ => _loggerFactory.CreateLogger(LogCategories.CreateFunctionUserCategory("Common"))); services.AddMediatR(typeof(ContactCreatedHandler).GetTypeInfo().Assembly); services.AddDbContext <ContactDbContext>(options => { options.UseSqlServer(_config.GetConnectionString("DefaultConnection")); }) .AddSingleton <IContactDbContext>(c => c.GetRequiredService <ContactDbContext>()) .AddSingleton <IUnitOfWork>(c => c.GetRequiredService <ContactDbContext>()); services.AddTransient <IContactService, ContactService>(); services.AddTransient <IContactRepository, ContactRepository>(); return(services.BuildServiceProvider()); }
public IServiceProvider Build() { var services = new ServiceCollection(); services.Configure <global::DAS.DigitalEngagement.Models.Infrastructure.Configuration>(Configuration.GetSection("Values")); services.AddOptions(); // Important: We need to call CreateFunctionUserCategory, otherwise our log entries might be filtered out. services.AddSingleton <ILogger>(_ => _loggerFactory.CreateLogger(LogCategories.CreateFunctionUserCategory("Common"))); services.AddTransient <IRegisterHandler, RegisterHandler>(); services.AddTransient <IUserDataValidator, UserDataValidator>(); services.AddTransient(typeof(IHttpClient <>), typeof(HttpClient <>)); services.AddTransient <IMarketoService, MarketoLeadService>(); services.AddMarketoClient(Configuration); return(services.BuildServiceProvider()); }
protected async Task <JObject> GetFunctionTestResult(string functionName) { string logEntry = null; await TestHelpers.Await(() => { // search the logs for token "TestResult:" and parse the following JSON var logs = Fixture.Host.GetLogMessages(LogCategories.CreateFunctionUserCategory(functionName)); if (logs != null) { logEntry = logs.Select(p => p.FormattedMessage).SingleOrDefault(p => p != null && p.Contains("TestResult:")); } return(logEntry != null); }); int idx = logEntry.IndexOf("{"); logEntry = logEntry.Substring(idx); return(JObject.Parse(logEntry)); }
public void CreateLogger_UsesSameFileWriter_ForSameFile() { var rootPath = Path.GetTempPath(); using (var provider = new FunctionFileLoggerProvider(Guid.NewGuid().ToString(), rootPath, () => true, () => true)) { provider.CreateLogger(LogCategories.CreateFunctionCategory("Test1")); provider.CreateLogger(LogCategories.CreateFunctionUserCategory("Test1")); provider.CreateLogger(LogCategories.CreateFunctionCategory("Test1")); Assert.Single(provider.FileWriterCache); // This creates a new entry. provider.CreateLogger(LogCategories.CreateFunctionCategory("Test2")); Assert.Equal(2, provider.FileWriterCache.Count); Assert.NotSame( provider.FileWriterCache[Path.Combine("Function", "Test1")], provider.FileWriterCache[Path.Combine("Function", "Test2")]); } }
public IServiceProvider Build() { var services = new ServiceCollection(); services.Configure <ForecastingJobsConfiguration>(Configuration.GetSection("ForecastingJobs")); var nLogConfiguration = new NLogConfiguration(); services.AddLogging((options) => { options.AddConfiguration(Configuration.GetSection("Logging")); options.SetMinimumLevel(LogLevel.Trace); options.AddNLog(new NLogProviderOptions { CaptureMessageTemplates = true, CaptureMessageProperties = true }); options.AddConsole(); options.AddDebug(); nLogConfiguration.ConfigureNLog(Configuration); }); services.AddSingleton(typeof(ILogger <>), typeof(Logger <>)); services.AddSingleton(_ => _loggerFactory.CreateLogger(LogCategories.CreateFunctionUserCategory("Common"))); EncodingConfig encodingConfig = GetEncodingConfig(); services.AddSingleton(encodingConfig); services.AddSingleton <IEncodingService, EncodingService>(); services.AddSingleton <ILevyCompleteTriggerHandler, LevyCompleteTriggerHandler>(); services.AddSingleton <IRefreshPaymentDataCompletedTriggerHandler, PaymentCompleteTriggerHandler>(); services.AddSingleton <ILevyForecastService, LevyForecastService>(); services.AddSingleton <IPaymentForecastService, PaymentForecastService>(); services.AddSingleton(typeof(IHttpFunctionClient <>), typeof(HttpFunctionClient <>)); return(services.BuildServiceProvider()); }
private static void ValidateException( ExceptionTelemetry telemetry, string expectedCategory, string expectedOperationName, string expectedOperationId, string expectedParentId) { Assert.Equal(expectedCategory, telemetry.Properties[LogConstants.CategoryNameKey]); Assert.Equal(expectedOperationName, telemetry.Context.Operation.Name); Assert.Equal(expectedOperationId, telemetry.Context.Operation.Id); Assert.Equal(expectedParentId, telemetry.Context.Operation.ParentId); if (expectedCategory == LogCategories.CreateFunctionUserCategory(expectedOperationName)) { // It came directly from the user Assert.IsType <Exception>(telemetry.Exception); // Result logs do not include custom scopes. ValidateCustomScopeProperty(telemetry); } else if (expectedCategory == LogCategories.CreateFunctionCategory(expectedOperationName)) { // It came directly from the host, so wrapped in a FunctionInvocationException Assert.IsType <FunctionInvocationException>(telemetry.Exception); } else if (expectedCategory == LogCategories.Results) { // Check that the Function details show up as 'prop__'. We may change this in the future as // it may not be exceptionally useful. Assert.Equal(expectedOperationName, telemetry.Properties[$"{LogConstants.CustomPropertyPrefix}{LogConstants.NameKey}"]); Assert.Equal("This function was programmatically called via the host APIs.", telemetry.Properties[$"{LogConstants.CustomPropertyPrefix}{LogConstants.TriggerReasonKey}"]); Assert.IsType <FunctionInvocationException>(telemetry.Exception); Assert.IsType <Exception>(telemetry.Exception.InnerException); } ValidateSdkVersion(telemetry); }
public void ILogger_Succeeds() { string functionName = nameof(ILoggerFunctions.ILogger); using (JobHost host = new JobHost(CreateConfig())) { var method = typeof(ILoggerFunctions).GetMethod(functionName); host.Call(method); } // Six loggers are the startup, singleton, results, function and function.user Assert.Equal(5, _loggerProvider.CreatedLoggers.Count()); var functionLogger = _loggerProvider.CreatedLoggers.Where(l => l.Category == LogCategories.CreateFunctionUserCategory(functionName)).Single(); var resultsLogger = _loggerProvider.CreatedLoggers.Where(l => l.Category == LogCategories.Results).Single(); var messages = functionLogger.GetLogMessages(); Assert.Equal(2, messages.Count); var infoMessage = messages[0]; var errorMessage = messages[1]; // These get the {OriginalFormat} property as well as the 2 from structured log properties Assert.Equal(3, infoMessage.State.Count()); Assert.Equal(3, errorMessage.State.Count()); Assert.Equal(1, resultsLogger.GetLogMessages().Count); // TODO: beef these verifications up }
public VentriloquismLineBotApp(ILineMessagingClient client, SkillSettings settings, ILoggerFactory loggerFactory) : base(client, settings.ChannelSecret) { Logger = loggerFactory.CreateLogger(LogCategories.CreateFunctionUserCategory(nameof(LineBotFunctions))); }
public void TimerTrigger() { var logs = Fixture.Host.GetLogMessages(LogCategories.CreateFunctionUserCategory("TimerTrigger")); Assert.Contains(logs, log => log.FormattedMessage.Contains("Timer function ran!")); }
private void AddLogging(IServiceCollection services) { services.AddLogging(); services.AddScoped <ILogger>(provider => provider.GetService <ILoggerFactory>().CreateLogger(LogCategories.CreateFunctionUserCategory("GiasAdapter"))); services.AddScoped <ILoggerWrapper, LoggerWrapper>(); }
private void AddLogging(IServiceCollection services) { services.AddLogging(); services.AddScoped <ILogger>(provider => provider.GetService <ILoggerFactory>().CreateLogger(LogCategories.CreateFunctionUserCategory("Common"))); services.AddScoped <ILoggerWrapper, LoggerWrapper>(); services.AddScoped <IHttpSpiExecutionContextManager, HttpSpiExecutionContextManager>(); services.AddScoped <ISpiExecutionContextManager>((provider) => (ISpiExecutionContextManager)provider.GetService(typeof(IHttpSpiExecutionContextManager))); services.AddScoped <ILoggerWrapper, LoggerWrapper>(); }
/// <summary> /// Initializes a new instance of the <see cref="StartUp"/> class. /// </summary> public StartUp() { var functionLoggerFactory = new LoggerFactory(); _logger = functionLoggerFactory.CreateLogger(LogCategories.CreateFunctionUserCategory("Common")); }
public async Task TraceWriter_ForwardsTo_ILogger() { string functionName = nameof(ILoggerFunctions.TraceWriterWithILoggerFactory); IHost host = ConfigureHostBuilder().Build(); var loggerProvider = host.GetTestLoggerProvider(); using (host) { var method = typeof(ILoggerFunctions).GetMethod(functionName); await host.GetJobHost().CallAsync(method); } // Five loggers are the startup, singleton, results, function and function.user Assert.Equal(7, loggerProvider.CreatedLoggers.Count); // $$$ was 9? var functionLogger = loggerProvider.CreatedLoggers.Where(l => l.Category == LogCategories.CreateFunctionUserCategory(functionName)).Single(); Assert.Equal(2, functionLogger.GetLogMessages().Count); var infoMessage = functionLogger.GetLogMessages()[0]; var errorMessage = functionLogger.GetLogMessages()[1]; // These get the {OriginalFormat} only Assert.Single(infoMessage.State); Assert.Single(errorMessage.State); //TODO: beef these verifications up }
public void CreateLogger_ReturnsNullLogger_ForUserCategory() { Assert.IsType <NullLogger>(_provider.CreateLogger(LogCategories.CreateFunctionUserCategory("TestFunction"))); }
public void ILogger_Succeeds() { string functionName = nameof(ILoggerFunctions.ILogger); IHost host = ConfigureHostBuilder().Build(); var loggerProvider = host.GetTestLoggerProvider(); using (host) { var method = typeof(ILoggerFunctions).GetMethod(functionName); host.GetJobHost().Call(method); } // Six loggers are the startup, singleton, results, function and function.user // Note: We currently have 3 additional Logger<T> categories that need to be renamed Assert.Equal(7, loggerProvider.CreatedLoggers.Count); // $$$ was 9? var functionLogger = loggerProvider.CreatedLoggers.Where(l => l.Category == LogCategories.CreateFunctionUserCategory(functionName)).Single(); var resultsLogger = loggerProvider.CreatedLoggers.Where(l => l.Category == LogCategories.Results).Single(); Assert.Equal(2, functionLogger.GetLogMessages().Count); var infoMessage = functionLogger.GetLogMessages()[0]; var errorMessage = functionLogger.GetLogMessages()[1]; // These get the {OriginalFormat} property as well as the 2 from structured log properties Assert.Equal(3, infoMessage.State.Count()); Assert.Equal(3, errorMessage.State.Count()); Assert.Equal(1, resultsLogger.GetLogMessages().Count); // TODO: beef these verifications up }
private async Task WaitForFunctionTrace(string functionName, string functionTrace) { // watch for the specific user log, then make sure the request telemetry has flushed, which // indicates all logging is done for this function invocation await TestHelpers.Await(() => { bool done = false; TraceTelemetry logTrace = _fixture.Channel.Telemetries.OfType <TraceTelemetry>().SingleOrDefault(p => p.Message.Contains(functionTrace) && p.Properties[LogConstants.CategoryNameKey] == LogCategories.CreateFunctionUserCategory(functionName)); if (logTrace != null) { string invocationId = logTrace.Properties[LogConstants.InvocationIdKey]; RequestTelemetry request = _fixture.Channel.Telemetries.OfType <RequestTelemetry>().SingleOrDefault(p => GetInvocationId(p) == invocationId); done = request != null; } return(done); }, userMessageCallback : _fixture.TestHost.GetLog); }
public async Task Scenario_Logging() { string testData = Guid.NewGuid().ToString(); JObject input = new JObject { { "scenario", "logging" }, { "input", testData }, }; Fixture.Host.ClearLogMessages(); Fixture.MetricsLogger.ClearCollections(); await Fixture.Host.BeginFunctionAsync("Scenarios", input); string userCategory = LogCategories.CreateFunctionUserCategory("Scenarios"); IList <string> userLogs = null; string consoleLog = null; await TestHelpers.Await(() => { userLogs = Fixture.Host.GetScriptHostLogMessages(userCategory).Select(p => p.FormattedMessage).ToList(); consoleLog = Fixture.Host.GetScriptHostLogMessages(LanguageWorkerConstants.FunctionConsoleLogCategoryName).Select(p => p.FormattedMessage).SingleOrDefault(); return(userLogs.Count == 10 && consoleLog != null); }, userMessageCallback : Fixture.Host.GetLog); // verify use of context.log to log complex objects LogMessage scriptTrace = Fixture.Host.GetScriptHostLogMessages(userCategory).Single(p => p.FormattedMessage != null && p.FormattedMessage.Contains(testData)); Assert.Equal(LogLevel.Information, scriptTrace.Level); JObject logEntry = JObject.Parse(scriptTrace.FormattedMessage); Assert.Equal("This is a test", logEntry["message"]); Assert.Equal(testData, logEntry["input"]); // verify log levels in traces LogMessage[] traces = Fixture.Host.GetScriptHostLogMessages(userCategory).Where(t => t.FormattedMessage != null && t.FormattedMessage.Contains("loglevel")).ToArray(); Assert.Equal(LogLevel.Information, traces[0].Level); Assert.Equal("loglevel default", traces[0].FormattedMessage); Assert.Equal(LogLevel.Information, traces[1].Level); Assert.Equal("loglevel info", traces[1].FormattedMessage); Assert.Equal(LogLevel.Trace, traces[2].Level); Assert.Equal("loglevel verbose", traces[2].FormattedMessage); Assert.Equal(LogLevel.Warning, traces[3].Level); Assert.Equal("loglevel warn", traces[3].FormattedMessage); Assert.Equal(LogLevel.Error, traces[4].Level); Assert.Equal("loglevel error", traces[4].FormattedMessage); // verify most of the logs look correct Assert.EndsWith("Mathew Charles", userLogs[1]); Assert.EndsWith("null", userLogs[2]); Assert.EndsWith("1234", userLogs[3]); Assert.EndsWith("true", userLogs[4]); Assert.EndsWith("loglevel default", userLogs[5]); Assert.EndsWith("loglevel info", userLogs[6]); // verify the console log Assert.Equal("console log", consoleLog); // TODO: Re-enable once we can override IMetricsLogger // We only expect 9 user log metrics to be counted, since // verbose logs are filtered by default (the TestLogger explicitly // allows all levels for testing purposes) var key = MetricsEventManager.GetAggregateKey(MetricEventNames.FunctionUserLog, "Scenarios"); // Assert.Equal(9, Fixture.MetricsLogger.LoggedEvents.Where(p => p == key).Count()); }
public async Task HttpTrigger_CustomRoute_Get_ReturnsExpectedResponse() { var id = "4e2796ae-b865-4071-8a20-2a15cbaf856c"; string functionKey = await _fixture.Host.GetFunctionSecretAsync("HttpTrigger-CustomRoute-Get"); string uri = $"api/node/products/electronics/{id}?code={functionKey}"; HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain")); HttpResponseMessage response = await _fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.OK, response.StatusCode); string json = await response.Content.ReadAsStringAsync(); JArray products = JArray.Parse(json); Assert.Equal(1, products.Count); var product = products[0]; Assert.Equal("electronics", (string)product["category"]); Assert.Equal(id, (string)product["id"]); // test optional route param (id) uri = $"api/node/products/electronics?code={functionKey}"; request = new HttpRequestMessage(HttpMethod.Get, uri); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain")); response = await _fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.OK, response.StatusCode); json = await response.Content.ReadAsStringAsync(); products = JArray.Parse(json); Assert.Equal(2, products.Count); // test optional route param (category) uri = $"api/node/products?code={functionKey}"; request = new HttpRequestMessage(HttpMethod.Get, uri); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain")); response = await _fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.OK, response.StatusCode); json = await response.Content.ReadAsStringAsync(); products = JArray.Parse(json); Assert.Equal(3, products.Count); // test a constraint violation (invalid id) uri = $"api/node/products/electronics/notaguid?code={functionKey}"; request = new HttpRequestMessage(HttpMethod.Get, uri); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain")); response = await _fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); // test a constraint violation (invalid category) uri = $"api/node/products/999/{id}?code={functionKey}"; request = new HttpRequestMessage(HttpMethod.Get, uri); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain")); response = await _fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); // verify route parameters were part of binding data var logs = _fixture.Host.GetLogMessages(LogCategories.CreateFunctionUserCategory("HttpTrigger-CustomRoute-Get")); var log = logs.Single(p => p.FormattedMessage.Contains($"category: electronics id: {id}")); Assert.NotNull(log); }
public async Task HttpTrigger_CSharp_CustomRoute_ReturnsExpectedResponse() { string functionName = "HttpTrigger-CSharp-CustomRoute"; string functionKey = await _fixture.Host.GetFunctionSecretAsync(functionName); string uri = $"api/csharp/products/electronics/123?code={functionKey}"; HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri); HttpResponseMessage response = await _fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.OK, response.StatusCode); string json = await response.Content.ReadAsStringAsync(); var product = JObject.Parse(json); Assert.Equal("electronics", (string)product["category"]); Assert.Equal(123, (int?)product["id"]); // test optional id parameter uri = $"api/csharp/products/electronics?code={functionKey}"; request = new HttpRequestMessage(HttpMethod.Get, uri); response = await _fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.OK, response.StatusCode); json = await response.Content.ReadAsStringAsync(); product = JObject.Parse(json); Assert.Equal("electronics", (string)product["category"]); Assert.Null((int?)product["id"]); // test optional category parameter uri = $"api/csharp/products?code={functionKey}"; request = new HttpRequestMessage(HttpMethod.Get, uri); response = await _fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.OK, response.StatusCode); json = await response.Content.ReadAsStringAsync(); product = JObject.Parse(json); Assert.Null((string)product["category"]); Assert.Null((int?)product["id"]); // test a constraint violation (invalid id) uri = $"api/csharp/products/electronics/1x3?code={functionKey}"; request = new HttpRequestMessage(HttpMethod.Get, uri); response = await _fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); // test a constraint violation (invalid category) uri = $"api/csharp/products/999/123?code={functionKey}"; request = new HttpRequestMessage(HttpMethod.Get, uri); response = await _fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); // verify route parameters were part of binding data var logs = _fixture.Host.GetLogMessages(LogCategories.CreateFunctionUserCategory(functionName)); Assert.True(logs.Any(p => p.FormattedMessage.Contains("Parameters: category=electronics id=123"))); Assert.True(logs.Any(p => p.FormattedMessage.Contains("ProductInfo: Category=electronics Id=123"))); }
public void TraceWriter_ForwardsTo_ILogger() { string functionName = nameof(ILoggerFunctions.TraceWriterWithILoggerFactory); using (JobHost host = new JobHost(CreateConfig())) { var method = typeof(ILoggerFunctions).GetMethod(functionName); host.Call(method); } // Five loggers are the startup, singleton, results, function and function.user Assert.Equal(5, _loggerProvider.CreatedLoggers.Count()); var functionLogger = _loggerProvider.CreatedLoggers.Where(l => l.Category == LogCategories.CreateFunctionUserCategory(functionName)).Single(); var messages = functionLogger.GetLogMessages(); Assert.Equal(2, messages.Count); var infoMessage = messages[0]; var errorMessage = messages[1]; // These get the {OriginalFormat} only Assert.Single(infoMessage.State); Assert.Single(errorMessage.State); //TODO: beef these verifications up }