ClearFunctionLogs() public static method

public static ClearFunctionLogs ( string functionName ) : void
functionName string
return void
        public async Task Scenario_DoneCalledMultipleTimes_ErrorIsLogged()
        {
            TestHelpers.ClearFunctionLogs("Scenarios");

            JObject input = new JObject
            {
                { "scenario", "doubleDone" }
            };
            Dictionary <string, object> arguments = new Dictionary <string, object>
            {
                { "input", input.ToString() }
            };
            await Fixture.Host.CallAsync("Scenarios", arguments);

            var logs = await TestHelpers.GetFunctionLogsAsync("Scenarios");

            Assert.Equal(4, logs.Count);
            Assert.True(logs.Any(p => p.Contains("Function started")));
            Assert.True(logs.Any(p => p.Contains("Running scenario 'doubleDone'")));

            // verify an error was written
            Assert.True(logs.Any(p => p.Contains("Error: 'done' has already been called. Please check your script for extraneous calls to 'done'.")));

            // verify the function completed successfully
            Assert.True(logs.Any(p => p.Contains("Function completed (Success")));
        }
Ejemplo n.º 2
0
        public async Task ListenerError_LogsAndDoesNotStopHost()
        {
            string queueName = "samples-input-nonexistent";
            bool   exists    = await Fixture.NamespaceManager.QueueExistsAsync(queueName);

            Assert.False(exists, $"This test expects the queue '{queueName}' to not exist, but it does.");

            IList <string> logs = null;

            await TestHelpers.Await(() =>
            {
                logs = TestHelpers.GetFunctionLogsAsync("ListenerStartupException", false).Result;

                string logToFind = "The listener for function 'Functions.ListenerStartupException' was unable to start.";
                return(logs.Any(l => l.Contains(logToFind)));
            });

            TestHelpers.ClearFunctionLogs("TimerTrigger");

            // assert that timer function is still running
            await TestHelpers.Await(() =>
            {
                logs = TestHelpers.GetFunctionLogsAsync("TimerTrigger", false).Result;

                string logToFind = "Timer function ran!";
                return(logs.Any(l => l.Contains(logToFind)));
            });

            // assert that Stop does not throw error
            Fixture.Host.Stop();
        }
        public async Task QueueTriggerToBlobTest()
        {
            TestHelpers.ClearFunctionLogs("QueueTriggerToBlob");

            string            id             = Guid.NewGuid().ToString();
            string            messageContent = string.Format("{{ \"id\": \"{0}\" }}", id);
            CloudQueueMessage message        = new CloudQueueMessage(messageContent);

            await Fixture.TestQueue.AddMessageAsync(message);

            var    resultBlob = Fixture.TestOutputContainer.GetBlockBlobReference(id);
            string result     = await TestHelpers.WaitForBlobAndGetStringAsync(resultBlob);

            Assert.Equal(TestHelpers.RemoveByteOrderMarkAndWhitespace(messageContent), TestHelpers.RemoveByteOrderMarkAndWhitespace(result));

            string     userCategory = LogCategories.CreateFunctionUserCategory("QueueTriggerToBlob");
            LogMessage traceEvent   = await WaitForTraceAsync(p => p?.FormattedMessage != null && p.FormattedMessage.Contains(id) && string.Equals(p.Category, userCategory, StringComparison.Ordinal));

            Assert.Equal(LogLevel.Information, traceEvent.Level);

            string trace = traceEvent.FormattedMessage;

            Assert.Contains("script processed queue message", trace);
            Assert.Contains(messageContent.Replace(" ", string.Empty), trace.Replace(" ", string.Empty));
        }
Ejemplo n.º 4
0
        private async Task RunTimeoutTest(string scriptLang, string functionName)
        {
            TestHelpers.ClearFunctionLogs(functionName);
            TimeSpan testTimeout = TimeSpan.FromSeconds(3);
            var      traceWriter = new TestTraceWriter(TraceLevel.Verbose);

            using (var manager = await CreateAndStartScriptHostManager(scriptLang, functionName, testTimeout, traceWriter))
            {
                string testData = Guid.NewGuid().ToString();

                Dictionary <string, object> arguments = new Dictionary <string, object>
                {
                    { "inputData", testData },
                };

                FunctionTimeoutException ex = await Assert.ThrowsAsync <FunctionTimeoutException>(() => manager.Instance.CallAsync(functionName, arguments));

                await TestHelpers.Await(() =>
                {
                    // make sure logging from within the function worked
                    // TODO: This doesn't appear to work for Powershell in AppVeyor. Need to investigate.
                    //bool hasTestData = inProgressLogs.Any(l => l.Contains(testData));
                    var expectedMessage = $"Timeout value of {testTimeout} was exceeded by function: Functions.{functionName}";
                    var traces          = string.Join(Environment.NewLine, traceWriter.Traces);
                    return(traces.Contains(expectedMessage));
                });

                var exception = GetExceptionHandler(manager).TimeoutExceptionInfos.Single().SourceException;
                Assert.IsType <FunctionTimeoutException>(exception);
            }
        }
        public async Task Scenario_Logging()
        {
            TestHelpers.ClearFunctionLogs("Scenarios");

            string  testData = Guid.NewGuid().ToString();
            JObject input    = new JObject
            {
                { "scenario", "logging" },
                { "input", testData },
            };
            Dictionary <string, object> arguments = new Dictionary <string, object>
            {
                { "input", input.ToString() }
            };
            await Fixture.Host.CallAsync("Scenarios", arguments);

            var logs = await TestHelpers.GetFunctionLogsAsync("Scenarios");

            // verify use of context.log to log complex objects
            TraceEvent scriptTrace = Fixture.TraceWriter.Traces.Single(p => p.Message.Contains(testData));

            Assert.Equal(TraceLevel.Info, scriptTrace.Level);
            JObject logEntry = JObject.Parse(scriptTrace.Message);

            Assert.Equal("This is a test", logEntry["message"]);
            Assert.Equal("v6.5.0", (string)logEntry["version"]);
            Assert.Equal(testData, logEntry["input"]);
        }
        public async Task ListenerError_LogsAndDoesNotStopHost()
        {
            IList <string> logs = null;

            await TestHelpers.Await(() =>
            {
                logs = TestHelpers.GetFunctionLogsAsync("ListenerStartupException", false).Result;
                return(logs.Count > 0);
            });

            // assert that listener error was captured
            Assert.Contains(logs, (log) => log.Contains("The listener for function 'Functions.ListenerStartupException' was unable to start."));

            TestHelpers.ClearFunctionLogs("TimerTrigger");
            await TestHelpers.Await(() =>
            {
                logs = TestHelpers.GetFunctionLogsAsync("TimerTrigger", false).Result;
                return(logs.Count > 0);
            });

            // assert that timer function is still running
            Assert.Contains(logs, (log) => log.Contains("Timer function ran!"));

            // assert that Stop does not throw error
            Fixture.Host.Stop();
        }
        public async Task BlobTriggerToBlobTest()
        {
            TestHelpers.ClearFunctionLogs("BlobTriggerToBlob");

            // write a binary blob
            string         name      = Guid.NewGuid().ToString();
            CloudBlockBlob inputBlob = Fixture.TestInputContainer.GetBlockBlobReference(name);

            byte[] inputBytes = new byte[] { 1, 2, 3, 4, 5 };
            using (var stream = inputBlob.OpenWrite())
            {
                stream.Write(inputBytes, 0, inputBytes.Length);
            }

            var resultBlob = Fixture.TestOutputContainer.GetBlockBlobReference(name);
            await TestHelpers.WaitForBlobAsync(resultBlob);

            byte[] resultBytes;
            using (var resultStream = resultBlob.OpenRead())
                using (var ms = new MemoryStream())
                {
                    resultStream.CopyTo(ms);
                    resultBytes = ms.ToArray();
                }

            JObject testResult = await GetFunctionTestResult("BlobTriggerToBlob");

            Assert.Equal(inputBytes, resultBytes);
            Assert.True((bool)testResult["isBuffer"]);
            Assert.Equal(5, (int)testResult["length"]);
        }
        public async Task PromiseApi_ResolveAfterDone()
        {
            TestHelpers.ClearFunctionLogs("Scenarios");

            JObject input = new JObject
            {
                { "scenario", "promiseApiDone" }
            };

            var arguments = new Dictionary <string, object>()
            {
                { "input", input.ToString() }
            };

            // call multiple times to reduce flakiness (function can exit before Promise.resolve executes)
            for (int i = 0; i < 10; i++)
            {
                await Task.WhenAny(Fixture.Host.CallAsync("Scenarios", arguments), Task.Delay(2000));

                var logs = await TestHelpers.GetFunctionLogsAsync("Scenarios");

                if (logs.Any(p => p.Contains("Error: Choose either to return a promise or call 'done'.  Do not use both in your script.")))
                {
                    // short circuit if we find log
                    return;
                }
            }

            // this should never be reached
            Assert.True(false, "There was no log found for duplicate calls to done");
        }
        public async Task HttpTrigger_Post_ByteArray(string contentType)
        {
            TestHelpers.ClearFunctionLogs("HttpTriggerByteArray");

            IHeaderDictionary headers = new HeaderDictionary();

            headers.Add("Content-Type", contentType);

            byte[] inputBytes = new byte[] { 1, 2, 3, 4, 5 };
            var    content    = inputBytes;

            HttpRequest request = HttpTestHelpers.CreateHttpRequest("POST", "http://localhost/api/httptriggerbytearray", headers, content);

            Dictionary <string, object> arguments = new Dictionary <string, object>
            {
                { "req", request }
            };
            await Fixture.JobHost.CallAsync("HttpTriggerByteArray", arguments);

            var result = (IActionResult)request.HttpContext.Items[ScriptConstants.AzureFunctionsHttpResponseKey];

            RawScriptResult objectResult = result as RawScriptResult;

            Assert.NotNull(objectResult);
            Assert.Equal(200, objectResult.StatusCode);

            JObject body = (JObject)objectResult.Content;

            Assert.True((bool)body["isBuffer"]);
            Assert.Equal(5, body["length"]);

            var rawBody = Encoding.UTF8.GetBytes((string)body["rawBody"]);

            Assert.Equal(inputBytes, rawBody);
        }
        public async Task HttpTrigger_CustomRoute_Post_ReturnsExpectedResponse()
        {
            TestHelpers.ClearFunctionLogs("HttpTrigger-CustomRoute-Post");

            string  id          = Guid.NewGuid().ToString();
            string  functionKey = "5u3pyihh8ldfelipm3qdabw69iah0oghgzw8n959";
            string  uri         = $"api/node/products/housewares/{id}?code={functionKey}";
            JObject product     = new JObject
            {
                { "id", id },
                { "name", "Waffle Maker Pro" },
                { "category", "Housewares" }
            };
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri)
            {
                Content = new StringContent(product.ToString())
            };

            HttpResponseMessage response = await this._fixture.HttpClient.SendAsync(request);

            Assert.Equal(HttpStatusCode.Created, response.StatusCode);

            // wait for function to execute and produce its result blob
            CloudBlobContainer outputContainer = _fixture.BlobClient.GetContainerReference("samples-output");
            string             path            = $"housewares/{id}";
            CloudBlockBlob     outputBlob      = outputContainer.GetBlockBlobReference(path);
            string             result          = await TestHelpers.WaitForBlobAndGetStringAsync(outputBlob);

            JObject resultProduct = JObject.Parse(Utility.RemoveUtf8ByteOrderMark(result));

            Assert.Equal(id, (string)resultProduct["id"]);
            Assert.Equal((string)product["name"], (string)resultProduct["name"]);
        }
        public async Task PromiseApi_ResolveAfterDone()
        {
            TestHelpers.ClearFunctionLogs("Scenarios");

            JObject input = new JObject
            {
                { "scenario", "promiseApiDone" }
            };

            var arguments = new Dictionary <string, object>()
            {
                { "input", input.ToString() }
            };

            // call multiple times to reduce flakiness (function can exit before Promise.resolve executes)
            for (int i = 0; i < 5; i++)
            {
                await Task.WhenAny(Fixture.Host.CallAsync("Scenarios", arguments), Task.Delay(3000));
            }

            var logs = await TestHelpers.GetFunctionLogsAsync("Scenarios");

            Assert.True(logs.Any(p => p.Contains("Error: Choose either to return a promise or call 'done'.  Do not use both in your script.")));
            Assert.True(logs.Any(p => p.Contains("Function completed (Success")));
        }
        public async Task Scenario_DoneCalledMultipleTimes_ErrorIsLogged()
        {
            TestHelpers.ClearFunctionLogs("Scenarios");

            JObject input = new JObject
            {
                { "scenario", "doubleDone" }
            };
            Dictionary <string, object> arguments = new Dictionary <string, object>
            {
                { "input", input.ToString() }
            };

            // call a few times since this is a timing related error
            for (int i = 0; i < 3; i++)
            {
                await Fixture.Host.CallAsync("Scenarios", arguments);
            }

            var logs = await TestHelpers.GetFunctionLogsAsync("Scenarios");

            // verify an error was written at least once
            Assert.True(logs.Any(p => p.Contains("Error: 'done' has already been called. Please check your script for extraneous calls to 'done'.")));

            // verify the function completed successfully each time
            Assert.Equal(3, logs.Count(p => p.Contains("Function completed (Success")));
        }
        public async Task HttpTrigger_Post_ByteArray()
        {
            TestHelpers.ClearFunctionLogs("HttpTriggerByteArray");

            byte[]             inputBytes = new byte[] { 1, 2, 3, 4, 5 };
            HttpRequestMessage request    = new HttpRequestMessage
            {
                RequestUri = new Uri(string.Format("http://localhost/api/httptriggerbytearray")),
                Method     = HttpMethod.Post,
                Content    = new ByteArrayContent(inputBytes)
            };

            request.SetConfiguration(new HttpConfiguration());
            request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

            Dictionary <string, object> arguments = new Dictionary <string, object>
            {
                { "req", request }
            };
            await Fixture.Host.CallAsync("HttpTriggerByteArray", arguments);

            HttpResponseMessage response = (HttpResponseMessage)request.Properties[ScriptConstants.AzureFunctionsHttpResponseKey];

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);

            JObject testResult = await GetFunctionTestResult("HttpTriggerByteArray");

            Assert.True((bool)testResult["isBuffer"]);
            Assert.Equal(5, (int)testResult["length"]);
        }
        protected EndToEndTestFixture(string rootPath, string testId)
        {
            _settingsManager = ScriptSettingsManager.Instance;
            FixtureId        = testId;
            string connectionString            = AmbientConnectionStringProvider.Instance.GetConnectionString(ConnectionStringNames.Storage);
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);

            QueueClient = storageAccount.CreateCloudQueueClient();
            BlobClient  = storageAccount.CreateCloudBlobClient();
            TableClient = storageAccount.CreateCloudTableClient();

            CreateTestStorageEntities();
            TraceWriter = new TestTraceWriter(TraceLevel.Verbose);

            ApiHubTestHelper.SetDefaultConnectionFactory();

            ScriptHostConfiguration config = new ScriptHostConfiguration()
            {
                RootScriptPath  = rootPath,
                TraceWriter     = TraceWriter,
                FileLoggingMode = FileLoggingMode.Always
            };

            RequestConfiguration = new HttpConfiguration();
            RequestConfiguration.Formatters.Add(new PlaintextMediaTypeFormatter());

            ScriptHostEnvironmentMock = new Mock <IScriptHostEnvironment>();

            // Reset the timer logs first, since one of the tests will
            // be checking them
            TestHelpers.ClearFunctionLogs("TimerTrigger");
            Host = ScriptHost.Create(ScriptHostEnvironmentMock.Object, config, _settingsManager);
            Host.Start();
        }
        public async Task ApiHubTableEntityIn()
        {
            TestHelpers.ClearFunctionLogs("ApiHubTableEntityIn");

            // Ensure the test entity exists.
            await ApiHubTestHelper.EnsureEntityAsync(ApiHubTestHelper.EntityId4);

            // Test table entity out binding.
            JObject input = new JObject
            {
                { "table", "SampleTable" },
                { "id", ApiHubTestHelper.EntityId4 }
            };
            await Fixture.Host.CallAsync("ApiHubTableEntityIn",
                                         new Dictionary <string, object>()
            {
                { "input", input.ToString() }
            });

            var logs = await TestHelpers.GetFunctionLogsAsync("ApiHubTableEntityIn");

            string expectedLog = string.Format("TestResult: {0}", ApiHubTestHelper.EntityId4);

            Assert.True(logs.Any(p => p.Contains(expectedLog)));
        }
        protected EndToEndTestFixture(string rootPath, string testId)
        {
            FixtureId = testId;
            string connectionString            = AmbientConnectionStringProvider.Instance.GetConnectionString(ConnectionStringNames.Storage);
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);

            QueueClient = storageAccount.CreateCloudQueueClient();
            BlobClient  = storageAccount.CreateCloudBlobClient();
            TableClient = storageAccount.CreateCloudTableClient();

            CreateTestStorageEntities();
            TraceWriter = new TestTraceWriter(TraceLevel.Verbose);

            ApiHubTestHelper.SetDefaultConnectionFactory();

            ScriptHostConfiguration config = new ScriptHostConfiguration()
            {
                RootScriptPath  = rootPath,
                TraceWriter     = TraceWriter,
                FileLoggingMode = FileLoggingMode.Always
            };

            // Clear the timer logs first, since one of the tests will
            // be checking them
            TestHelpers.ClearFunctionLogs("TimerTrigger");
            Host = ScriptHost.Create(config);
            Host.Start();
        }
Ejemplo n.º 17
0
        protected ScriptHostEndToEndTestFixture(string rootPath, string testId, ProxyClientExecutor proxyClient = null, bool startHost = true, ICollection <string> functions = null, string functionsWorkerLanguage = null)
        {
            if (!string.IsNullOrEmpty(functionsWorkerLanguage))
            {
                Environment.SetEnvironmentVariable(LanguageWorkerConstants.FunctionWorkerRuntimeSettingName, functionsWorkerLanguage);
            }
            _settingsManager = ScriptSettingsManager.Instance;
            FixtureId        = testId;
            string connectionString            = AmbientConnectionStringProvider.Instance.GetConnectionString(ConnectionStringNames.Storage);
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);

            QueueClient = storageAccount.CreateCloudQueueClient();
            BlobClient  = storageAccount.CreateCloudBlobClient();
            TableClient = storageAccount.CreateCloudTableClient();

            CreateTestStorageEntities().Wait();

            // ApiHubTestHelper.SetDefaultConnectionFactory();

            ScriptHostConfiguration config = new ScriptHostConfiguration()
            {
                RootScriptPath  = rootPath,
                FileLoggingMode = FileLoggingMode.Always,
            };

            if (functions != null)
            {
                config.OnConfigurationApplied = c => c.Functions = functions;
            }

            RequestConfiguration = new HttpConfiguration();

            EventManager = new ScriptEventManager();
            ScriptHostEnvironmentMock = new Mock <IScriptHostEnvironment>();
            LoggerProvider            = new TestLoggerProvider();
            ILoggerProviderFactory loggerProviderFactory = new TestLoggerProviderFactory(LoggerProvider);

            // Reset the timer logs first, since one of the tests will
            // be checking them
            TestHelpers.ClearFunctionLogs("TimerTrigger");
            TestHelpers.ClearFunctionLogs("ListenerStartupException");

            InitializeConfig(config);
            Func <string, FunctionDescriptor> funcLookup = (name) => this.Host.GetFunctionOrNull(name);
            var fastLogger = new FunctionInstanceLogger(funcLookup, new MetricsLogger());

            config.HostConfig.AddService <IAsyncCollector <FunctionInstanceLogEntry> >(fastLogger);
            Host = new ScriptHost(ScriptHostEnvironmentMock.Object, EventManager, config, _settingsManager,
                                  proxyClient: proxyClient, loggerProviderFactory: loggerProviderFactory);
            Host.Initialize();

            if (startHost)
            {
                Host.HostStarted += (s, e) => _hostStartedEvent.Set();
                Host.Start();
                _hostStartedEvent.Wait(TimeSpan.FromSeconds(30));
            }
        }
        public async Task Scenario_Logging()
        {
            // Sleep to make sure all logs from other "Scenarios" tests have flushed before
            // we delete the file.
            await Task.Delay(1000);

            TestHelpers.ClearFunctionLogs("Scenarios");

            string  testData = Guid.NewGuid().ToString();
            JObject input    = new JObject
            {
                { "scenario", "logging" },
                { "input", testData },
            };
            Dictionary <string, object> arguments = new Dictionary <string, object>
            {
                { "input", input.ToString() }
            };
            await Fixture.Host.CallAsync("Scenarios", arguments);

            IList <string> logs = null;
            await TestHelpers.Await(() =>
            {
                logs = TestHelpers.GetFunctionLogsAsync("Scenarios", throwOnNoLogs: false).Result;
                return(logs.Count > 0);
            });

            // verify use of context.log to log complex objects
            TraceEvent scriptTrace = Fixture.TraceWriter.Traces.Single(p => p.Message.Contains(testData));

            Assert.Equal(System.Diagnostics.TraceLevel.Info, scriptTrace.Level);
            JObject logEntry = JObject.Parse(scriptTrace.Message);

            Assert.Equal("This is a test", logEntry["message"]);
            Assert.Equal(testData, logEntry["input"]);

            // verify log levels in traces
            TraceEvent[] traces = Fixture.TraceWriter.Traces.Where(t => t.Message.Contains("loglevel")).ToArray();
            Assert.Equal(System.Diagnostics.TraceLevel.Info, traces[0].Level);
            Assert.Equal("loglevel default", traces[0].Message);
            Assert.Equal(System.Diagnostics.TraceLevel.Info, traces[1].Level);
            Assert.Equal("loglevel info", traces[1].Message);
            Assert.Equal(System.Diagnostics.TraceLevel.Verbose, traces[2].Level);
            Assert.Equal("loglevel verbose", traces[2].Message);
            Assert.Equal(System.Diagnostics.TraceLevel.Warning, traces[3].Level);
            Assert.Equal("loglevel warn", traces[3].Message);
            Assert.Equal(System.Diagnostics.TraceLevel.Error, traces[4].Level);
            Assert.Equal("loglevel error", traces[4].Message);

            // verify most of the logs look correct
            Assert.EndsWith("Mathew Charles", logs[4]);
            Assert.EndsWith("null", logs[5]);
            Assert.EndsWith("1234", logs[6]);
            Assert.EndsWith("true", logs[7]);
            Assert.EndsWith("loglevel default", logs[8]);
            Assert.EndsWith("loglevel info", logs[9]);
        }
        public async Task HttpTrigger_CustomRoute_Get_ReturnsExpectedResponse()
        {
            TestHelpers.ClearFunctionLogs("HttpTrigger-CustomRoute-Get");

            var                id          = Guid.NewGuid().ToString();
            string             functionKey = "82fprgh77jlbhcma3yr1zen8uv9yb0i7dwze3np2";
            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 this._fixture.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(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 this._fixture.HttpClient.SendAsync(request);

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            json = await response.Content.ReadAsStringAsync();

            JArray products = JArray.Parse(json);

            Assert.Equal(2, 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 this._fixture.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 this._fixture.HttpClient.SendAsync(request);

            Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);

            // verify route parameters were part of binding data
            var logs = await TestHelpers.GetFunctionLogsAsync("HttpTrigger-CustomRoute-Get");

            var log = logs.Single(p => p.Contains($"category: electronics id: {id}"));

            Assert.NotNull(log);
        }
        public async Task HttpTrigger_CSharp_CustomRoute_ReturnsExpectedResponse()
        {
            TestHelpers.ClearFunctionLogs("HttpTrigger-CSharp-CustomRoute");

            string             functionKey = "68qkqlughacc6f9n6t4ubk0jq7r5er7pta13yh20";
            string             uri         = $"api/csharp/products/electronics/123?code={functionKey}";
            HttpRequestMessage request     = new HttpRequestMessage(HttpMethod.Get, uri);

            HttpResponseMessage response = await this._fixture.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"]);

            // now try again without specifying optional id parameter
            uri      = $"api/csharp/products/electronics?code={functionKey}";
            request  = new HttpRequestMessage(HttpMethod.Get, uri);
            response = await this._fixture.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 a constraint violation (invalid id)
            uri      = $"api/csharp/products/electronics/1x3?code={functionKey}";
            request  = new HttpRequestMessage(HttpMethod.Get, uri);
            response = await this._fixture.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 this._fixture.HttpClient.SendAsync(request);

            Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);

            // verify route parameters were part of binding data
            var logs = await TestHelpers.GetFunctionLogsAsync("HttpTrigger-CSharp-CustomRoute");

            Assert.True(logs.Any(p => p.Contains("Parameters: category=electronics id=123")));
            Assert.True(logs.Any(p => p.Contains("ProductInfo: Category=electronics Id=123")));
        }
        public async Task SingleNamedExport()
        {
            TestHelpers.ClearFunctionLogs("SingleNamedExport");

            Dictionary <string, object> arguments = new Dictionary <string, object>
            {
                { "input", string.Empty }
            };
            await Fixture.Host.CallAsync("SingleNamedExport", arguments);

            var logs = await TestHelpers.GetFunctionLogsAsync("SingleNamedExport");

            Assert.Contains(logs, log => log.Contains("Exports: IsObject=true, Count=1"));
        }
        public async Task BlobTriggerToBlobTest()
        {
            TestHelpers.ClearFunctionLogs("BlobTriggerToBlob");

            // write a binary blob
            string         name      = Guid.NewGuid().ToString();
            CloudBlockBlob inputBlob = Fixture.TestInputContainer.GetBlockBlobReference(name);

            inputBlob.Metadata.Add("TestMetadataKey", "TestMetadataValue");
            byte[] inputBytes = new byte[] { 1, 2, 3, 4, 5 };
            using (var stream = inputBlob.OpenWrite())
            {
                stream.Write(inputBytes, 0, inputBytes.Length);
            }

            var resultBlob = Fixture.TestOutputContainer.GetBlockBlobReference(name);
            await TestHelpers.WaitForBlobAsync(resultBlob);

            byte[] resultBytes;
            using (var resultStream = resultBlob.OpenRead())
                using (var ms = new MemoryStream())
                {
                    resultStream.CopyTo(ms);
                    resultBytes = ms.ToArray();
                }

            JObject testResult = await GetFunctionTestResult("BlobTriggerToBlob");

            Assert.Equal(inputBytes, resultBytes);
            Assert.True((bool)testResult["isBuffer"]);
            Assert.Equal(5, (int)testResult["length"]);

            var blobMetadata = (JObject)testResult["blobMetadata"];

            Assert.Equal($"test-input-node/{name}", (string)blobMetadata["path"]);

            var metadata = (JObject)blobMetadata["metadata"];

            Assert.Equal("TestMetadataValue", (string)metadata["testMetadataKey"]);

            var properties = (JObject)blobMetadata["properties"];

            Assert.Equal("application/octet-stream", (string)properties["contentType"]);
            Assert.Equal("BlockBlob", (string)properties["blobType"]);
            Assert.Equal(5, properties["length"]);

            string invocationId = (string)testResult["invocationId"];

            Guid.Parse(invocationId);
        }
        public async Task MultipleExports()
        {
            TestHelpers.ClearFunctionLogs("MultipleExports");

            Dictionary <string, object> arguments = new Dictionary <string, object>
            {
                { "input", string.Empty }
            };
            await Fixture.Host.CallAsync("MultipleExports", arguments);

            var logs = await TestHelpers.GetFunctionLogsAsync("MultipleExports");

            Assert.Equal(3, logs.Count);
            Assert.True(logs[1].Contains("Exports: IsObject=true, Count=4"));
        }
        public async Task EventHubTrigger()
        {
            TestHelpers.ClearFunctionLogs("EventHubTrigger");

            // write 3 events
            List <EventData> events = new List <EventData>();

            string[] ids = new string[3];
            for (int i = 0; i < 3; i++)
            {
                ids[i] = Guid.NewGuid().ToString();
                JObject jo = new JObject
                {
                    { "value", ids[i] }
                };
                events.Add(new EventData(Encoding.UTF8.GetBytes(jo.ToString(Formatting.None))));
            }

            string connectionString = Environment.GetEnvironmentVariable("AzureWebJobsEventHubSender");
            ServiceBusConnectionStringBuilder builder = new ServiceBusConnectionStringBuilder(connectionString);
            EventHubClient eventHubClient;

            if (!string.IsNullOrWhiteSpace(builder.EntityPath))
            {
                eventHubClient = EventHubClient.CreateFromConnectionString(connectionString);
            }
            else
            {
                string eventHubPath = _settingsManager.GetSetting("AzureWebJobsEventHubPath");
                eventHubClient = EventHubClient.CreateFromConnectionString(connectionString, eventHubPath);
            }

            await eventHubClient.SendBatchAsync(events);

            string logs = null;
            await TestHelpers.Await(() =>
            {
                // wait for all 3 of the unique IDs send
                // above have been processed
                logs = string.Join("\r\n", TestHelpers.GetFunctionLogsAsync("EventHubTrigger", throwOnNoLogs: false).Result);
                return(ids.All(p => logs.Contains(p)));
            });

            Assert.True(logs.Contains("IsArray true"));
        }
        public async Task QueueTriggerByteArray()
        {
            TestHelpers.ClearFunctionLogs("QueueTriggerByteArray");

            // write a binary queue message
            byte[]            inputBytes = new byte[] { 1, 2, 3 };
            CloudQueueMessage message    = new CloudQueueMessage(inputBytes);
            var queue = Fixture.QueueClient.GetQueueReference("test-input-byte");

            queue.CreateIfNotExists();
            queue.Clear();
            queue.AddMessage(message);

            JObject testResult = await GetFunctionTestResult("QueueTriggerByteArray");

            Assert.True((bool)testResult["isBuffer"]);
            Assert.Equal(5, (int)testResult["length"]);
        }
        protected EndToEndTestFixture(string rootPath, string testId)
        {
            _settingsManager = ScriptSettingsManager.Instance;
            FixtureId        = testId;
            string connectionString            = AmbientConnectionStringProvider.Instance.GetConnectionString(ConnectionStringNames.Storage);
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);

            QueueClient = storageAccount.CreateCloudQueueClient();
            BlobClient  = storageAccount.CreateCloudBlobClient();
            TableClient = storageAccount.CreateCloudTableClient();

            CreateTestStorageEntities();
            TraceWriter = new TestTraceWriter(TraceLevel.Verbose);

            ApiHubTestHelper.SetDefaultConnectionFactory();

            ScriptHostConfiguration config = new ScriptHostConfiguration()
            {
                RootScriptPath  = rootPath,
                TraceWriter     = TraceWriter,
                FileLoggingMode = FileLoggingMode.Always
            };

            RequestConfiguration = new HttpConfiguration();
            RequestConfiguration.Formatters.Add(new PlaintextMediaTypeFormatter());

            EventManager = new ScriptEventManager();
            ScriptHostEnvironmentMock = new Mock <IScriptHostEnvironment>();

            // Reset the timer logs first, since one of the tests will
            // be checking them
            TestHelpers.ClearFunctionLogs("TimerTrigger");
            TestHelpers.ClearFunctionLogs("ListenerStartupException");

            InitializeConfig(config);
            Func <string, FunctionDescriptor> funcLookup = (name) => this.Host.GetFunctionOrNull(name);
            var fastLogger = new FunctionInstanceLogger(funcLookup, new MetricsLogger());

            config.HostConfig.AddService <IAsyncCollector <FunctionInstanceLogEntry> >(fastLogger);

            Host = ScriptHost.Create(ScriptHostEnvironmentMock.Object, EventManager, config, _settingsManager);
            Host.Start();
        }
        protected async Task TwilioReferenceInvokeSucceedsImpl(bool isDotNet)
        {
            if (isDotNet)
            {
                TestHelpers.ClearFunctionLogs("TwilioReference");

                string testData  = Guid.NewGuid().ToString();
                string inputName = "input";
                Dictionary <string, object> arguments = new Dictionary <string, object>
                {
                    { inputName, testData }
                };
                await Fixture.Host.CallAsync("TwilioReference", arguments);

                // make sure the input string made it all the way through
                var logs = await TestHelpers.GetFunctionLogsAsync("TwilioReference");

                Assert.True(logs.Any(p => p.Contains(testData)));
            }
        }
        public async Task HttpTriggerWithError_Get()
        {
            string functionName = "HttpTrigger-WithError";

            TestHelpers.ClearFunctionLogs(functionName);

            HttpRequestMessage request = new HttpRequestMessage
            {
                RequestUri =
                    new Uri(
                        "http://localhost/api/httptrigger-witherror?code=1388a6b0d05eca2237f10e4a4641260b0a08f3a5&name=testuser"),
                Method = HttpMethod.Get
            };

            request.SetConfiguration(new HttpConfiguration());

            Dictionary <string, object> arguments = new Dictionary <string, object>
            {
                { "req", request }
            };

            string    innerException     = "PowerShell script error";
            string    errorRecordMessage = "Test Error in Get-DateToday";
            Exception ex = await
                           Assert.ThrowsAsync <FunctionInvocationException>(async() => await Fixture.Host.CallAsync(functionName, arguments));

            var runtimeException = (RuntimeException)ex.InnerException;

            Assert.Equal(innerException, runtimeException.Message);
            Assert.Equal(errorRecordMessage, runtimeException.InnerException.Message);

            var logs = await TestHelpers.GetFunctionLogsAsync(functionName);

            Assert.True(logs.Any(p => p.Contains("Function started")));

            // verify an error was written
            Assert.True(logs.Any(p => p.Contains(errorRecordMessage)));

            // verify the function completed successfully
            Assert.True(logs.Any(p => p.Contains("Function completed (Failure")));
        }
        public async Task QueueTriggerPython_Succeeds()
        {
            TestHelpers.ClearFunctionLogs("QueueTrigger-Python");

            // write the input message
            CloudQueue inputQueue = _fixture.QueueClient.GetQueueReference("samples-python");

            inputQueue.CreateIfNotExists();

            string  id         = Guid.NewGuid().ToString();
            JObject jsonObject = new JObject
            {
                { "id", id }
            };
            var message = new CloudQueueMessage(jsonObject.ToString(Formatting.None));
            await inputQueue.AddMessageAsync(message);

            // wait for function to execute and produce its result blob
            CloudBlobContainer outputContainer = _fixture.BlobClient.GetContainerReference("samples-output");
            CloudBlockBlob     outputBlob      = outputContainer.GetBlockBlobReference(id);
            string             result          = await TestHelpers.WaitForBlobAndGetStringAsync(outputBlob);

            jsonObject = JObject.Parse(result);
            Assert.Equal(id, (string)jsonObject["id"]);

            // verify the function output
            var logs = await TestHelpers.GetFunctionLogsAsync("QueueTrigger-Python");

            // strip off the timestamps from the beginning of each line
            logs = logs.Select(l => l.Split(new[] { ' ' }, 2)[1]).ToList();
            int idx = logs.IndexOf("Read 5 Table entities");

            for (int i = idx + 1; i < 5; i++)
            {
                string  json   = logs[i];
                JObject entity = JObject.Parse(json);
                Assert.Equal("samples-python", entity["PartitionKey"]);
                Assert.Equal(0, (int)entity["Status"]);
            }
        }
        protected async Task TableInputTest()
        {
            TestHelpers.ClearFunctionLogs("TableIn");

            var args = new Dictionary <string, object>()
            {
                { "input", "{ \"Region\": \"West\" }" }
            };
            await Fixture.Host.CallAsync("TableIn", args);

            var logs = await TestHelpers.GetFunctionLogsAsync("TableIn");

            string result = logs.Where(p => p.Contains("Result:")).Single();

            result = result.Substring(result.IndexOf('{'));

            // verify singleton binding
            JObject resultObject = JObject.Parse(result);
            JObject single       = (JObject)resultObject["single"];

            Assert.Equal("AAA", (string)single["PartitionKey"]);
            Assert.Equal("001", (string)single["RowKey"]);

            // verify partition binding
            JArray partition = (JArray)resultObject["partition"];

            Assert.Equal(3, partition.Count);
            foreach (var entity in partition)
            {
                Assert.Equal("BBB", (string)entity["PartitionKey"]);
            }

            // verify query binding
            JArray query = (JArray)resultObject["query"];

            Assert.Equal(2, query.Count);
            Assert.Equal("003", (string)query[0]["RowKey"]);
            Assert.Equal("004", (string)query[1]["RowKey"]);
        }