Example #1
0
        public async Task EmptyHost_StartsSuccessfully()
        {
            string functionDir = Path.Combine(TestHelpers.FunctionsTestDirectory, "Functions", Guid.NewGuid().ToString());

            Directory.CreateDirectory(functionDir);

            // important for the repro that this directory does not exist
            string logDir = Path.Combine(TestHelpers.FunctionsTestDirectory, "Logs", Guid.NewGuid().ToString());

            JObject hostConfig = new JObject
            {
                { "id", "123456" }
            };

            File.WriteAllText(Path.Combine(functionDir, ScriptConstants.HostMetadataFileName), hostConfig.ToString());

            ScriptHostConfiguration config = new ScriptHostConfiguration
            {
                RootScriptPath  = functionDir,
                RootLogPath     = logDir,
                FileLoggingMode = FileLoggingMode.Always
            };

            var eventManagerMock          = new Mock <IScriptEventManager>();
            ScriptHostManager hostManager = new ScriptHostManager(config, eventManagerMock.Object);

            // start the host and wait for it to be running
            Task runTask = Task.Run(() => hostManager.RunAndBlock());
            await TestHelpers.Await(() => hostManager.State == ScriptHostState.Running, timeout : 10000);

            // exercise restart
            hostManager.RestartHost();
            Assert.Equal(ScriptHostState.Default, hostManager.State);
            await TestHelpers.Await(() => hostManager.State == ScriptHostState.Running, timeout : 10000);

            // stop the host fully
            hostManager.Stop();
            Assert.Equal(ScriptHostState.Default, hostManager.State);

            await Task.Delay(FileTraceWriter.LogFlushIntervalMs);

            string hostLogFilePath = Directory.EnumerateFiles(Path.Combine(logDir, "Host")).Single();
            string hostLogs        = File.ReadAllText(hostLogFilePath);

            Assert.Contains("Generating 0 job function(s)", hostLogs);
            Assert.Contains("No job functions found.", hostLogs);
            Assert.Contains("Job host started", hostLogs);
            Assert.Contains("Job host stopped", hostLogs);
        }
        public async Task RunAndBlock_ParseError_LogsError()
        {
            TestLoggerProvider        loggerProvider = new TestLoggerProvider();
            TestLoggerProviderFactory factory        = new TestLoggerProviderFactory(loggerProvider, includeDefaultLoggerProviders: false);

            string rootPath = Path.Combine(Environment.CurrentDirectory, "ScriptHostTests");

            if (!Directory.Exists(rootPath))
            {
                Directory.CreateDirectory(rootPath);
            }

            var configPath = Path.Combine(rootPath, "host.json");

            File.WriteAllText(configPath, @"{<unparseable>}");

            var config = new ScriptHostConfiguration()
            {
                RootScriptPath = rootPath
            };

            config.HostConfig.HostId = ID;

            var  scriptHostFactory = new TestScriptHostFactory();
            var  eventManagerMock  = new Mock <IScriptEventManager>();
            var  hostManager       = new ScriptHostManager(config, _settingsManager, scriptHostFactory, eventManagerMock.Object, loggerProviderFactory: factory);
            Task taskIgnore        = Task.Run(() => hostManager.RunAndBlock());

            await TestHelpers.Await(() => hostManager.State == ScriptHostState.Error, 3000, 50);

            Assert.Equal(ScriptHostState.Error, hostManager.State);

            hostManager.Stop();

            var ex = hostManager.LastError;

            Assert.True(ex is FormatException);
            var expectedMessage = $"Unable to parse host configuration file '{configPath}'.";

            Assert.Equal(expectedMessage, ex.Message);

            var logger     = loggerProvider.CreatedLoggers.Last();
            var logMessage = logger.GetLogMessages()[0];

            Assert.StartsWith("A ScriptHost error has occurred", logMessage.FormattedMessage);
            Assert.Equal(expectedMessage, logMessage.Exception.Message);
        }
Example #3
0
        public async Task UpdateFileAndRestart()
        {
            Random r = new Random();

            CancellationTokenSource cts = new CancellationTokenSource();

            var fixture = new NodeEndToEndTests.TestFixture();
            var blob1   = UpdateOutputName("testblob", "first", fixture);

            await fixture.Host.StopAsync();

            var config = fixture.Host.ScriptConfig;

            using (var manager = new ScriptHostManager(config))
            {
                // Background task to run while the main thread is pumping events at RunAndBlock().
                Thread t = new Thread(_ =>
                {
                    // Wait for initial execution.
                    TestHelpers.Await(() =>
                    {
                        return(blob1.Exists());
                    }, timeout: 10 * 1000).Wait();

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

                    // wait for newly executed
                    TestHelpers.Await(() =>
                    {
                        return(blob2.Exists());
                    }, timeout: 10 * 1000).Wait();

                    manager.Stop();
                });
                t.Start();

                manager.RunAndBlock(cts.Token);

                t.Join();
            }
        }
Example #4
0
        public async Task EmptyHost_StartsSuccessfully()
        {
            string functionDir = Path.Combine(TestHelpers.FunctionsTestDirectory, "Functions", Guid.NewGuid().ToString());

            Directory.CreateDirectory(functionDir);

            // important for the repro that this directory does not exist
            string logDir = Path.Combine(TestHelpers.FunctionsTestDirectory, "Logs", Guid.NewGuid().ToString());

            JObject hostConfig = new JObject
            {
                { "id", "123456" }
            };

            File.WriteAllText(Path.Combine(functionDir, ScriptConstants.HostMetadataFileName), hostConfig.ToString());

            ScriptHostConfiguration config = new ScriptHostConfiguration
            {
                RootScriptPath     = functionDir,
                RootLogPath        = logDir,
                FileLoggingEnabled = true
            };
            ScriptHostManager hostManager = new ScriptHostManager(config);

            Task runTask = Task.Run(() => hostManager.RunAndBlock());

            await TestHelpers.Await(() => hostManager.IsRunning, timeout : 10000);

            hostManager.Stop();
            Assert.False(hostManager.IsRunning);

            string hostLogFilePath = Directory.EnumerateFiles(Path.Combine(logDir, "Host")).Single();
            string hostLogs        = File.ReadAllText(hostLogFilePath);

            Assert.True(hostLogs.Contains("Generating 0 job function(s)"));
            Assert.True(hostLogs.Contains("No job functions found."));
            Assert.True(hostLogs.Contains("Job host started"));
            Assert.True(hostLogs.Contains("Job host stopped"));
        }
        public async Task RunAndBlock_HostJsonValueError_LogsError()
        {
            // Try to load valid host.json file that has an out-of-range value.
            // Ensure that it's logged to ILogger

            string rootPath = Path.Combine(Environment.CurrentDirectory, @"TestScripts\OutOfRange");

            ScriptHostConfiguration config = new ScriptHostConfiguration()
            {
                RootScriptPath = rootPath
            };

            TestLoggerProvider provider = new TestLoggerProvider();
            var loggerProviderFactory   = new TestLoggerProviderFactory(provider, includeDefaultLoggerProviders: false);

            var  factoryMock       = new Mock <IScriptHostFactory>();
            var  scriptHostFactory = new TestScriptHostFactory();
            var  eventManagerMock  = new Mock <IScriptEventManager>();
            var  hostManager       = new ScriptHostManager(config, _settingsManager, scriptHostFactory, eventManagerMock.Object, loggerProviderFactory: loggerProviderFactory);
            Task taskIgnore        = Task.Run(() => hostManager.RunAndBlock());

            await TestHelpers.Await(() => hostManager.State == ScriptHostState.Error, 3000, 50);

            Assert.Equal(ScriptHostState.Error, hostManager.State);
            Assert.False(hostManager.CanInvoke());

            hostManager.Stop();
            var ex = hostManager.LastError;

            Assert.True(ex is ArgumentOutOfRangeException);

            string msg = "A ScriptHost error has occurred";

            var startupLogger = provider.CreatedLoggers.Last();
            var loggerMessage = startupLogger.GetLogMessages().First();

            Assert.Equal(msg, loggerMessage.FormattedMessage);
            Assert.Same(ex, loggerMessage.Exception);
        }
        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);
                            }
                        }
                    }
        }
        public async Task EmptyHost_StartsSuccessfully()
        {
            string functionDir = Path.Combine(TestHelpers.FunctionsTestDirectory, "Functions", Guid.NewGuid().ToString());
            Directory.CreateDirectory(functionDir);

            // important for the repro that this directory does not exist
            string logDir = Path.Combine(TestHelpers.FunctionsTestDirectory, "Logs", Guid.NewGuid().ToString());

            JObject hostConfig = new JObject
            {
                { "id", "123456" }
            };
            File.WriteAllText(Path.Combine(functionDir, ScriptConstants.HostMetadataFileName), hostConfig.ToString());

            ScriptHostConfiguration config = new ScriptHostConfiguration
            {
                RootScriptPath = functionDir,
                RootLogPath = logDir,
                FileLoggingMode = FileLoggingMode.Always
            };
            ScriptHostManager hostManager = new ScriptHostManager(config);

            Task runTask = Task.Run(() => hostManager.RunAndBlock());

            await TestHelpers.Await(() => hostManager.State == ScriptHostState.Running, timeout: 10000);

            hostManager.Stop();
            Assert.Equal(ScriptHostState.Default, hostManager.State);

            await Task.Delay(FileTraceWriter.LogFlushIntervalMs);

            string hostLogFilePath = Directory.EnumerateFiles(Path.Combine(logDir, "Host")).Single();
            string hostLogs = File.ReadAllText(hostLogFilePath);

            Assert.Contains("Generating 0 job function(s)", hostLogs);
            Assert.Contains("No job functions found.", hostLogs);
            Assert.Contains("Job host started", hostLogs);
            Assert.Contains("Job host stopped", hostLogs);
        }