public async Task UpdateFileAndRestart()
        {
            var fixture = new NodeScriptHostTests.TestFixture(false);
            var config  = fixture.Host.ScriptConfig;

            config.OnConfigurationApplied = c =>
            {
                c.Functions = new Collection <string> {
                    "TimerTrigger"
                };
            };

            var blob1 = await UpdateOutputName("testblob", "first", fixture);

            using (var eventManager = new ScriptEventManager())
                using (var manager = new ScriptHostManager(config, eventManager))
                {
                    string GetErrorTraces()
                    {
                        var messages = fixture.LoggerProvider.GetAllLogMessages()
                                       .Where(t => t.Level == LogLevel.Error)
                                       .Select(t => t.FormattedMessage);

                        return(string.Join(Environment.NewLine, messages));
                    }

                    List <Exception> exceptions = new List <Exception>();

                    // Background task to run while the main thread is pumping events at RunAndBlock().
                    Thread backgroundThread = new Thread(_ =>
                    {
                        try
                        {
                            // don't start until the manager is running
                            TestHelpers.Await(() => manager.State == ScriptHostState.Running,
                                              userMessageCallback: GetErrorTraces).GetAwaiter().GetResult();

                            // Wait for initial execution.
                            TestHelpers.Await(async() =>
                            {
                                bool exists = await blob1.ExistsAsync();
                                return(exists);
                            }, timeout: 10 * 1000, userMessageCallback: GetErrorTraces).GetAwaiter().GetResult();

                            // This changes the bindings so that we now write to blob2
                            var blob2 = UpdateOutputName("first", "testblob", fixture).Result;

                            // wait for newly executed
                            TestHelpers.Await(async() =>
                            {
                                bool exists = await blob2.ExistsAsync();
                                return(exists);
                            }, timeout: 30 * 1000, userMessageCallback: GetErrorTraces).GetAwaiter().GetResult();

                            // The TimerTrigger can fire before the host is fully started. To be more
                            // reliably clean up the test, wait until it is running before calling Stop.
                            TestHelpers.Await(() => manager.State == ScriptHostState.Running,
                                              userMessageCallback: GetErrorTraces).GetAwaiter().GetResult();
                        }
                        catch (Exception ex)
                        {
                            exceptions.Add(ex);
                        }
                        finally
                        {
                            try
                            {
                                // Calling Stop (rather than using a token) lets us wait until all listeners have stopped.
                                manager.Stop();
                            }
                            catch (Exception ex)
                            {
                                exceptions.Add(ex);
                            }
                        }
                    });

                    try
                    {
                        backgroundThread.Start();
                        manager.RunAndBlock();
                        Assert.True(backgroundThread.Join(60000), "The background task did not complete in 60 seconds.");

                        string exceptionString = string.Join(Environment.NewLine, exceptions.Select(p => p.ToString()));
                        Assert.True(exceptions.Count() == 0, exceptionString);
                    }
                    finally
                    {
                        // make sure to put the original names back
                        await UpdateOutputName("first", "testblob", fixture);
                    }
                }
        }
        public async Task RenameFunctionAndRestart()
        {
            var oldDirectory = Path.Combine(Directory.GetCurrentDirectory(), "TestScripts/Node/TimerTrigger");
            var newDirectory = Path.Combine(Directory.GetCurrentDirectory(), "TestScripts/Node/MovedTrigger");

            var fixture = new NodeScriptHostTests.TestFixture(false);
            var config  = fixture.Host.ScriptConfig;

            config.OnConfigurationApplied = c =>
            {
                c.Functions = new Collection <string> {
                    "TimerTrigger", "MovedTrigger"
                };
            };

            var blob = fixture.TestOutputContainer.GetBlockBlobReference("testblob");
            await blob.DeleteIfExistsAsync();

            var mockEnvironment = new Mock <IScriptHostEnvironment>();

            using (var eventManager = new ScriptEventManager())
                using (var manager = new ScriptHostManager(config, eventManager, mockEnvironment.Object))
                    using (var resetEvent = new ManualResetEventSlim())
                    {
                        List <Exception> exceptions = new List <Exception>();

                        mockEnvironment.Setup(e => e.RestartHost())
                        .Callback(() =>
                        {
                            resetEvent.Set();
                            manager.RestartHost();
                        });

                        // Background task to run while the main thread is pumping events at RunAndBlock().
                        Thread backgroundThread = new Thread(_ =>
                        {
                            try
                            {
                                // don't start until the manager is running
                                TestHelpers.Await(() => manager.State == ScriptHostState.Running,
                                                  userMessageCallback: () => "Host did not start in time.").GetAwaiter().GetResult();

                                // Wait for initial execution.
                                TestHelpers.Await(async() =>
                                {
                                    bool exists = await blob.ExistsAsync();
                                    return(exists);
                                }, timeout: 10 * 1000,
                                                  userMessageCallback: () => $"Blob '{blob.Uri}' was not created by 'TimerTrigger' in time.").GetAwaiter().GetResult();

                                // find __dirname from blob
                                string text;
                                using (var stream = new MemoryStream())
                                {
                                    blob.DownloadToStreamAsync(stream).Wait();
                                    text = System.Text.Encoding.UTF8.GetString(stream.ToArray());
                                }

                                Assert.Contains("TimerTrigger", text);

                                // rename directory & delete old blob
                                Directory.Move(oldDirectory, newDirectory);

                                resetEvent.Wait(TimeSpan.FromSeconds(10));

                                blob.DeleteIfExistsAsync().GetAwaiter().GetResult();

                                // wait for newly executed
                                TestHelpers.Await(async() =>
                                {
                                    bool exists = await blob.ExistsAsync();
                                    return(exists);
                                }, timeout: 30 * 1000,
                                                  userMessageCallback: () => $"Blob '{blob.Uri}' was not created by 'MovedTrigger' in time.").GetAwaiter().GetResult();

                                using (var stream = new MemoryStream())
                                {
                                    blob.DownloadToStreamAsync(stream).Wait();
                                    text = System.Text.Encoding.UTF8.GetString(stream.ToArray());
                                }

                                Assert.Contains("MovedTrigger", text);

                                // The TimerTrigger can fire before the host is fully started. To be more
                                // reliably clean up the test, wait until it is running before calling Stop.
                                TestHelpers.Await(() => manager.State == ScriptHostState.Running).GetAwaiter().GetResult();
                            }
                            catch (Exception ex)
                            {
                                exceptions.Add(ex);
                            }
                            finally
                            {
                                try
                                {
                                    manager.Stop();
                                }
                                catch (Exception ex)
                                {
                                    exceptions.Add(ex);
                                }
                            }
                        });

                        try
                        {
                            backgroundThread.Start();
                            manager.RunAndBlock();
                            Assert.True(backgroundThread.Join(60000), "The background task did not complete in 60 seconds.");

                            string exceptionString = string.Join(Environment.NewLine, exceptions.Select(p => p.ToString()));
                            Assert.True(exceptions.Count() == 0, exceptionString);
                        }
                        finally
                        {
                            // Move the directory back after the host has stopped to prevent
                            // unnecessary host restarts
                            if (Directory.Exists(newDirectory))
                            {
                                Directory.Move(newDirectory, oldDirectory);
                            }
                        }
                    }
        }