diff --git a/src/WebJobs.Script.Host/Program.cs b/src/WebJobs.Script.Host/Program.cs index 34d0577fb7..965ba99242 100644 --- a/src/WebJobs.Script.Host/Program.cs +++ b/src/WebJobs.Script.Host/Program.cs @@ -22,8 +22,14 @@ static void Main(string[] args) RootPath = rootPath }; - ScriptHost host = ScriptHost.Create(config); - host.RunAndBlock(); + // Start the host and restart it if requested + ScriptHost host = null; + do + { + host = ScriptHost.Create(config); + host.RunAndBlock(); + } + while (host.Restart); } } } diff --git a/src/WebJobs.Script/Binding/Binding.cs b/src/WebJobs.Script/Binding/Binding.cs index 90c4885da5..abb46b438a 100644 --- a/src/WebJobs.Script/Binding/Binding.cs +++ b/src/WebJobs.Script/Binding/Binding.cs @@ -14,9 +14,9 @@ namespace Microsoft.Azure.WebJobs.Script { internal abstract class Binding { - private readonly JobHostConfiguration _config; + private readonly ScriptHostConfiguration _config; - protected Binding(JobHostConfiguration config, string name, string type, FileAccess fileAccess, bool isTrigger) + protected Binding(ScriptHostConfiguration config, string name, string type, FileAccess fileAccess, bool isTrigger) { _config = config; Name = name; @@ -37,7 +37,7 @@ protected Binding(JobHostConfiguration config, string name, string type, FileAcc public abstract Task BindAsync(IBinder binder, Stream stream, IReadOnlyDictionary bindingData); - internal static Collection GetBindings(JobHostConfiguration config, JArray bindingArray, FileAccess fileAccess) + internal static Collection GetBindings(ScriptHostConfiguration config, JArray bindingArray, FileAccess fileAccess) { Collection bindings = new Collection(); @@ -103,12 +103,12 @@ internal static Collection GetBindings(JobHostConfiguration config, JAr protected string Resolve(string name) { - if (_config.NameResolver == null) + if (_config.HostConfig.NameResolver == null) { return name; } - return _config.NameResolver.ResolveWholeString(name); + return _config.HostConfig.NameResolver.ResolveWholeString(name); } } } diff --git a/src/WebJobs.Script/Binding/BlobBinding.cs b/src/WebJobs.Script/Binding/BlobBinding.cs index 275a980731..7d1816853f 100644 --- a/src/WebJobs.Script/Binding/BlobBinding.cs +++ b/src/WebJobs.Script/Binding/BlobBinding.cs @@ -13,7 +13,7 @@ internal class BlobBinding : Binding { private readonly BindingTemplate _pathBindingTemplate; - public BlobBinding(JobHostConfiguration config, string name, string path, FileAccess fileAccess, bool isTrigger) : base(config, name, "blob", fileAccess, isTrigger) + public BlobBinding(ScriptHostConfiguration config, string name, string path, FileAccess fileAccess, bool isTrigger) : base(config, name, "blob", fileAccess, isTrigger) { Path = path; _pathBindingTemplate = BindingTemplate.FromString(Path); diff --git a/src/WebJobs.Script/Binding/QueueBinding.cs b/src/WebJobs.Script/Binding/QueueBinding.cs index 5dfb6fadd3..182e6b5e9b 100644 --- a/src/WebJobs.Script/Binding/QueueBinding.cs +++ b/src/WebJobs.Script/Binding/QueueBinding.cs @@ -13,7 +13,7 @@ internal class QueueBinding : Binding { private readonly BindingTemplate _queueNameBindingTemplate; - public QueueBinding(JobHostConfiguration config, string name, string queueName, FileAccess fileAccess, bool isTrigger) : base(config, name, "queue", fileAccess, isTrigger) + public QueueBinding(ScriptHostConfiguration config, string name, string queueName, FileAccess fileAccess, bool isTrigger) : base(config, name, "queue", fileAccess, isTrigger) { QueueName = queueName; _queueNameBindingTemplate = BindingTemplate.FromString(QueueName); diff --git a/src/WebJobs.Script/Binding/ServiceBusBinding.cs b/src/WebJobs.Script/Binding/ServiceBusBinding.cs index a2451a4479..7553f4bb27 100644 --- a/src/WebJobs.Script/Binding/ServiceBusBinding.cs +++ b/src/WebJobs.Script/Binding/ServiceBusBinding.cs @@ -13,7 +13,7 @@ internal class ServiceBusBinding : Binding { private readonly BindingTemplate _queueOrTopicNameBindingTemplate; - public ServiceBusBinding(JobHostConfiguration config, string name, string queueOrTopicName, FileAccess fileAccess, bool isTrigger) : base(config, name, "serviceBus", fileAccess, isTrigger) + public ServiceBusBinding(ScriptHostConfiguration config, string name, string queueOrTopicName, FileAccess fileAccess, bool isTrigger) : base(config, name, "serviceBus", fileAccess, isTrigger) { QueueOrTopicName = queueOrTopicName; _queueOrTopicNameBindingTemplate = BindingTemplate.FromString(QueueOrTopicName); diff --git a/src/WebJobs.Script/Binding/TableBinding.cs b/src/WebJobs.Script/Binding/TableBinding.cs index 8a961b238f..938eda9361 100644 --- a/src/WebJobs.Script/Binding/TableBinding.cs +++ b/src/WebJobs.Script/Binding/TableBinding.cs @@ -19,7 +19,7 @@ internal class TableBinding : Binding private readonly BindingTemplate _rowKeyBindingTemplate; private readonly TableQuery _tableQuery; - public TableBinding(JobHostConfiguration config, string name, string tableName, string partitionKey, string rowKey, FileAccess fileAccess, TableQuery tableQuery = null) : base(config, name, "queue", fileAccess, false) + public TableBinding(ScriptHostConfiguration config, string name, string tableName, string partitionKey, string rowKey, FileAccess fileAccess, TableQuery tableQuery = null) : base(config, name, "queue", fileAccess, false) { TableName = tableName; PartitionKey = partitionKey; diff --git a/src/WebJobs.Script/Config/ScriptHost.cs b/src/WebJobs.Script/Config/ScriptHost.cs index e5cf271246..f8ce05f6fb 100644 --- a/src/WebJobs.Script/Config/ScriptHost.cs +++ b/src/WebJobs.Script/Config/ScriptHost.cs @@ -16,29 +16,29 @@ namespace Microsoft.Azure.WebJobs.Script public class ScriptHost : JobHost { private const string HostAssemblyName = "ScriptHost"; + private FileSystemWatcher _fileWatcher; - protected ScriptHost(JobHostConfiguration config, ScriptHostConfiguration scriptConfig) - : base(config) + protected ScriptHost(ScriptHostConfiguration scriptConfig) + : base(scriptConfig.HostConfig) { - HostConfig = config; ScriptConfig = scriptConfig; } - public JobHostConfiguration HostConfig { get; private set; } - public ScriptHostConfiguration ScriptConfig { get; private set; } + public bool Restart { get; private set; } + protected virtual void Initialize() { List descriptionProviders = new List() { - new ScriptFunctionDescriptorProvider(HostConfig, ScriptConfig.RootPath), - new NodeFunctionDescriptorProvider(HostConfig, ScriptConfig.RootPath) + new ScriptFunctionDescriptorProvider(ScriptConfig), + new NodeFunctionDescriptorProvider(this, ScriptConfig) }; - if (HostConfig.IsDevelopment) + if (ScriptConfig.HostConfig.IsDevelopment) { - HostConfig.UseDevelopmentSettings(); + ScriptConfig.HostConfig.UseDevelopmentSettings(); } // read host.json and apply to JobHostConfiguration @@ -46,7 +46,7 @@ protected virtual void Initialize() Console.WriteLine(string.Format("Reading host configuration file '{0}'", hostConfigFilePath)); string json = File.ReadAllText(hostConfigFilePath); JObject hostConfig = JObject.Parse(json); - ApplyConfiguration(hostConfig, HostConfig); + ApplyConfiguration(hostConfig, ScriptConfig); // read all script functions and apply to JobHostConfiguration Collection functions = ReadFunctions(ScriptConfig, descriptionProviders); @@ -57,8 +57,33 @@ protected virtual void Initialize() List types = new List(); types.Add(type); - HostConfig.TypeLocator = new TypeLocator(types); - HostConfig.NameResolver = new NameResolver(); + ScriptConfig.HostConfig.TypeLocator = new TypeLocator(types); + ScriptConfig.HostConfig.NameResolver = new NameResolver(); + + if (ScriptConfig.WatchFiles) + { + _fileWatcher = new FileSystemWatcher(ScriptConfig.RootPath, "*.json") + { + IncludeSubdirectories = true, + EnableRaisingEvents = true + }; + _fileWatcher.Changed += OnConfigurationFileChanged; + } + } + + private void StopAndRestart() + { + if (Restart) + { + // we've already received a restart call + return; + } + + Console.WriteLine("The host configuration file has changed. Restarting."); + + // Flag for restart and stop the host. + Restart = true; + Stop(); } public static ScriptHost Create(ScriptHostConfiguration scriptConfig = null) @@ -76,8 +101,7 @@ public static ScriptHost Create(ScriptHostConfiguration scriptConfig = null) scriptConfig.RootPath = Path.Combine(Environment.CurrentDirectory, scriptConfig.RootPath); } - JobHostConfiguration config = new JobHostConfiguration(); - ScriptHost scriptHost = new ScriptHost(config, scriptConfig); + ScriptHost scriptHost = new ScriptHost(scriptConfig); scriptHost.Initialize(); return scriptHost; @@ -180,14 +204,22 @@ internal static Collection ReadFunctions(List((string)value, true, out consoleLevel)) { - jobHostConfig.Tracing.ConsoleLevel = consoleLevel; + hostConfig.Tracing.ConsoleLevel = consoleLevel; } } @@ -270,9 +302,33 @@ internal static void ApplyConfiguration(JObject config, JobHostConfiguration job { webHooksConfig = new WebHooksConfiguration((int)value); } - jobHostConfig.UseWebHooks(webHooksConfig); + hostConfig.UseWebHooks(webHooksConfig); + + hostConfig.UseTimers(); + } + + private void OnConfigurationFileChanged(object sender, FileSystemEventArgs e) + { + string fileName = Path.GetFileName(e.Name); + + if (!Restart && + ((string.Compare(fileName, "host.json") == 0) || string.Compare(fileName, "function.json") == 0)) + { + StopAndRestart(); + } + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (_fileWatcher != null) + { + _fileWatcher.Dispose(); + } + } - jobHostConfig.UseTimers(); + base.Dispose(disposing); } } } diff --git a/src/WebJobs.Script/Config/ScriptHostConfiguration.cs b/src/WebJobs.Script/Config/ScriptHostConfiguration.cs index fb1a7334f6..d821b16ef5 100644 --- a/src/WebJobs.Script/Config/ScriptHostConfiguration.cs +++ b/src/WebJobs.Script/Config/ScriptHostConfiguration.cs @@ -1,13 +1,34 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using System; + namespace Microsoft.Azure.WebJobs.Script { public class ScriptHostConfiguration { + public ScriptHostConfiguration() + { + HostConfig = new JobHostConfiguration(); + WatchFiles = true; + } + + /// + /// Gets the . + /// + public JobHostConfiguration HostConfig { get; private set; } + /// /// Gets or sets the path to the script function directory. /// public string RootPath { get; set; } + + /// + /// Gets or sets a value dicating whether the should + /// monitor file for changes (default is true). When set to true, the host will + /// automatically react to source/config file changes. When set to false no file + /// monitoring will be performed. + /// + public bool WatchFiles { get; set; } } } diff --git a/src/WebJobs.Script/Description/FunctionDescriptorProvider.cs b/src/WebJobs.Script/Description/FunctionDescriptorProvider.cs index 8d6a3678e1..9350d02fef 100644 --- a/src/WebJobs.Script/Description/FunctionDescriptorProvider.cs +++ b/src/WebJobs.Script/Description/FunctionDescriptorProvider.cs @@ -14,15 +14,24 @@ public abstract class FunctionDescriptorProvider { public abstract bool TryCreate(FunctionFolderInfo functionFolderInfo, out FunctionDescriptor functionDescriptor); - protected bool IsDisabled(string functionName, JObject trigger) + protected bool IsDisabled(string functionName, JObject value) + { + if (value != null && IsDisabled(value["disabled"])) + { + Console.WriteLine(string.Format("Function '{0}' is disabled", functionName)); + return true; + } + + return false; + } + + private bool IsDisabled(JToken isDisabledValue) { - bool isDisabled = false; - JToken isDisabledValue = trigger["disabled"]; if (isDisabledValue != null) { if (isDisabledValue.Type == JTokenType.Boolean && (bool)isDisabledValue) { - isDisabled = true; + return true; } else { @@ -32,17 +41,12 @@ protected bool IsDisabled(string functionName, JObject trigger) (string.Compare(value, "1", StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(value, "true", StringComparison.OrdinalIgnoreCase) == 0)) { - isDisabled = true; + return true; } } } - if (isDisabled) - { - Console.WriteLine(string.Format("Function '{0}' is disabled", functionName)); - } - - return isDisabled; + return false; } protected ParameterDescriptor ParseQueueTrigger(JObject trigger, Type triggerParameterType = null) diff --git a/src/WebJobs.Script/Description/NodeFunctionDescriptorProvider.cs b/src/WebJobs.Script/Description/NodeFunctionDescriptorProvider.cs index 2dd5b6525b..472e130952 100644 --- a/src/WebJobs.Script/Description/NodeFunctionDescriptorProvider.cs +++ b/src/WebJobs.Script/Description/NodeFunctionDescriptorProvider.cs @@ -12,13 +12,15 @@ namespace Microsoft.Azure.WebJobs.Script { internal class NodeFunctionDescriptorProvider : FunctionDescriptorProvider { - private readonly JobHostConfiguration _config; + private ScriptHost _host; + private readonly ScriptHostConfiguration _config; private readonly string _rootPath; - public NodeFunctionDescriptorProvider(JobHostConfiguration config, string rootPath) + public NodeFunctionDescriptorProvider(ScriptHost host, ScriptHostConfiguration config) { + _host = host; _config = config; - _rootPath = rootPath; + _rootPath = config.RootPath; } public override bool TryCreate(FunctionFolderInfo functionFolderInfo, out FunctionDescriptor functionDescriptor) @@ -42,7 +44,9 @@ public override bool TryCreate(FunctionFolderInfo functionFolderInfo, out Functi JObject trigger = (JObject)inputs.FirstOrDefault(p => ((string)p["type"]).ToLowerInvariant().EndsWith("trigger")); - if (IsDisabled(functionFolderInfo.Name, trigger)) + // A function can be disabled at the trigger or function level + if (IsDisabled(functionFolderInfo.Name, trigger) || + IsDisabled(functionFolderInfo.Name, functionFolderInfo.Configuration)) { return false; } @@ -55,7 +59,7 @@ public override bool TryCreate(FunctionFolderInfo functionFolderInfo, out Functi trigger["name"] = triggerParameterName = "input"; } - NodeFunctionInvoker invoker = new NodeFunctionInvoker(triggerParameterName, functionFolderInfo.Source, inputBindings, outputBindings); + NodeFunctionInvoker invoker = new NodeFunctionInvoker(_host, triggerParameterName, functionFolderInfo, inputBindings, outputBindings); ParameterDescriptor triggerParameter = null; switch (triggerType) diff --git a/src/WebJobs.Script/Description/NodeFunctionInvoker.cs b/src/WebJobs.Script/Description/NodeFunctionInvoker.cs index cbfa4e78d9..03dcec97af 100644 --- a/src/WebJobs.Script/Description/NodeFunctionInvoker.cs +++ b/src/WebJobs.Script/Description/NodeFunctionInvoker.cs @@ -20,11 +20,16 @@ namespace Microsoft.Azure.WebJobs.Script public class NodeFunctionInvoker : IFunctionInvoker { private Func> _scriptFunc; + private Func> _clearRequireCache; private static string FunctionTemplate; + private static string ClearRequireCacheScript; private readonly Collection _inputBindings; private readonly Collection _outputBindings; private readonly string _triggerParameterName; private readonly string _script; + private readonly FileSystemWatcher _fileWatcher; + private readonly string _functionName; + private readonly ScriptHost _host; static NodeFunctionInvoker() { @@ -33,6 +38,10 @@ static NodeFunctionInvoker() { FunctionTemplate = reader.ReadToEnd(); } + using (StreamReader reader = new StreamReader(assembly.GetManifestResourceStream("Microsoft.Azure.WebJobs.Script.clearRequireCache.js"))) + { + ClearRequireCacheScript = reader.ReadToEnd(); + } } private Func> ScriptFunc @@ -50,13 +59,31 @@ private Func> ScriptFunc } } - internal NodeFunctionInvoker(string triggerParameterName, string scriptFilePath, Collection inputBindings, Collection outputBindings) + internal NodeFunctionInvoker(ScriptHost host, string triggerParameterName, FunctionFolderInfo folderInfo, Collection inputBindings, Collection outputBindings) { + _host = host; _triggerParameterName = triggerParameterName; - scriptFilePath = scriptFilePath.Replace('\\', '/'); + string scriptFilePath = folderInfo.Source.Replace('\\', '/'); _script = string.Format(FunctionTemplate, scriptFilePath); _inputBindings = inputBindings; _outputBindings = outputBindings; + _functionName = folderInfo.Name; + + _clearRequireCache = Edge.Func(ClearRequireCacheScript); + + if (host.ScriptConfig.WatchFiles) + { + string functionDirectory = Path.GetDirectoryName(scriptFilePath); + _fileWatcher = new FileSystemWatcher(functionDirectory, "*.*") + { + IncludeSubdirectories = true, + EnableRaisingEvents = true + }; + _fileWatcher.Changed += OnScriptFileChanged; + _fileWatcher.Created += OnScriptFileChanged; + _fileWatcher.Deleted += OnScriptFileChanged; + _fileWatcher.Renamed += OnScriptFileChanged; + } } public async Task Invoke(object[] parameters) @@ -127,6 +154,29 @@ public async Task Invoke(object[] parameters) } } + private void OnScriptFileChanged(object sender, FileSystemEventArgs e) + { + if (_scriptFunc == null) + { + // we're not loaded yet, so nothing to reload + return; + } + + // The ScriptHost is already monitoring for changes to function.json, so we skip those + string fileName = Path.GetFileName(e.Name); + if (string.Compare(fileName, "function.json") != 0) + { + // one of the script files for this function changed + // force a reload on next execution + _scriptFunc = null; + + // clear the node module cache + _clearRequireCache(null).Wait(); + + Console.WriteLine(string.Format("Script function '{0}' changed. Reloading function.", _functionName)); + } + } + private Dictionary CreateContext(object input, TraceWriter traceWriter, IBinder binder) { Type triggerParameterType = input.GetType(); diff --git a/src/WebJobs.Script/Description/ScriptFunctionDescriptionProvider.cs b/src/WebJobs.Script/Description/ScriptFunctionDescriptionProvider.cs index 4bfd97494d..17fe9f4b6e 100644 --- a/src/WebJobs.Script/Description/ScriptFunctionDescriptionProvider.cs +++ b/src/WebJobs.Script/Description/ScriptFunctionDescriptionProvider.cs @@ -11,13 +11,13 @@ namespace Microsoft.Azure.WebJobs.Script { internal class ScriptFunctionDescriptorProvider : FunctionDescriptorProvider { - private readonly JobHostConfiguration _config; + private readonly ScriptHostConfiguration _config; private readonly string _rootPath; - public ScriptFunctionDescriptorProvider(JobHostConfiguration config, string rootPath) + public ScriptFunctionDescriptorProvider(ScriptHostConfiguration config) { _config = config; - _rootPath = rootPath; + _rootPath = config.RootPath; } public override bool TryCreate(FunctionFolderInfo functionFolderInfo, out FunctionDescriptor functionDescriptor) @@ -43,7 +43,9 @@ public override bool TryCreate(FunctionFolderInfo functionFolderInfo, out Functi JObject trigger = (JObject)inputs.FirstOrDefault(p => ((string)p["type"]).ToLowerInvariant().EndsWith("trigger")); - if (IsDisabled(functionFolderInfo.Name, trigger)) + // A function can be disabled at the trigger or function level + if (IsDisabled(functionFolderInfo.Name, trigger) || + IsDisabled(functionFolderInfo.Name, functionFolderInfo.Configuration)) { return false; } diff --git a/src/WebJobs.Script/WebJobs.Script.csproj b/src/WebJobs.Script/WebJobs.Script.csproj index 24b0659dbe..cd066cfa08 100644 --- a/src/WebJobs.Script/WebJobs.Script.csproj +++ b/src/WebJobs.Script/WebJobs.Script.csproj @@ -198,6 +198,7 @@ + PreserveNewest diff --git a/src/WebJobs.Script/clearRequireCache.js b/src/WebJobs.Script/clearRequireCache.js new file mode 100644 index 0000000000..b981ba6bd2 --- /dev/null +++ b/src/WebJobs.Script/clearRequireCache.js @@ -0,0 +1,6 @@ +return function (context, callback) { + Object.keys(require.cache).forEach(function (key) { + delete require.cache[key]; + }); + callback(); +} \ No newline at end of file diff --git a/test/WebJobs.Script.Tests/EndToEndTestFixture.cs b/test/WebJobs.Script.Tests/EndToEndTestFixture.cs index 790da0195f..486d0f46bd 100644 --- a/test/WebJobs.Script.Tests/EndToEndTestFixture.cs +++ b/test/WebJobs.Script.Tests/EndToEndTestFixture.cs @@ -25,7 +25,7 @@ protected EndToEndTestFixture(string rootPath) Host = ScriptHost.Create(config); TraceWriter = new TestTraceWriter(TraceLevel.Verbose); - Host.HostConfig.Tracing.Tracers.Add(TraceWriter); + Host.ScriptConfig.HostConfig.Tracing.Tracers.Add(TraceWriter); Host.Start(); } diff --git a/test/WebJobs.Script.Tests/NodeFunctionGenerationTests.cs b/test/WebJobs.Script.Tests/NodeFunctionGenerationTests.cs index 0842b4cf30..4e2d9d6caf 100644 --- a/test/WebJobs.Script.Tests/NodeFunctionGenerationTests.cs +++ b/test/WebJobs.Script.Tests/NodeFunctionGenerationTests.cs @@ -144,9 +144,10 @@ private static void VerifyCommonProperties(MethodInfo method) private static MethodInfo GenerateMethod(JObject trigger) { + string rootPath = Path.Combine(Environment.CurrentDirectory, @"TestScripts"); FunctionFolderInfo functionFolderInfo = new FunctionFolderInfo(); functionFolderInfo.Name = "Test"; - functionFolderInfo.Source = Path.Combine(Environment.CurrentDirectory, @"TestScripts\Node\Common\test.js"); + functionFolderInfo.Source = Path.Combine(rootPath, @"Node\Common\test.js"); JArray inputs = new JArray(trigger); functionFolderInfo.Configuration = new JObject(); @@ -156,10 +157,14 @@ private static MethodInfo GenerateMethod(JObject trigger) List functionFolderInfos = new List(); functionFolderInfos.Add(functionFolderInfo); - JobHostConfiguration config = new JobHostConfiguration(); + ScriptHostConfiguration scriptConfig = new ScriptHostConfiguration() + { + RootPath = rootPath + }; + ScriptHost host = ScriptHost.Create(scriptConfig); FunctionDescriptorProvider[] descriptorProviders = new FunctionDescriptorProvider[] { - new NodeFunctionDescriptorProvider(config, Environment.CurrentDirectory) + new NodeFunctionDescriptorProvider(host, scriptConfig) }; var functionDescriptors = ScriptHost.ReadFunctions(functionFolderInfos, descriptorProviders); Type t = FunctionGenerator.Generate("TestScriptHost", "Host.Functions", functionDescriptors); diff --git a/test/WebJobs.Script.Tests/ScriptHostTests.cs b/test/WebJobs.Script.Tests/ScriptHostTests.cs index 8d34ddadd8..be6aeb0cef 100644 --- a/test/WebJobs.Script.Tests/ScriptHostTests.cs +++ b/test/WebJobs.Script.Tests/ScriptHostTests.cs @@ -18,11 +18,11 @@ public void ApplyConfiguration_TopLevel() { JObject config = new JObject(); config["id"] = ID; - JobHostConfiguration jobHostConfig = new JobHostConfiguration(); + ScriptHostConfiguration scriptConfig = new ScriptHostConfiguration(); - ScriptHost.ApplyConfiguration(config, jobHostConfig); + ScriptHost.ApplyConfiguration(config, scriptConfig); - Assert.Equal(ID, jobHostConfig.HostId); + Assert.Equal(ID, scriptConfig.HostConfig.HostId); } [Fact] @@ -32,27 +32,27 @@ public void ApplyConfiguration_Queues() config["id"] = ID; JObject queuesConfig = new JObject(); config["queues"] = queuesConfig; - JobHostConfiguration jobHostConfig = new JobHostConfiguration(); + ScriptHostConfiguration scriptConfig = new ScriptHostConfiguration(); - ScriptHost.ApplyConfiguration(config, jobHostConfig); + ScriptHost.ApplyConfiguration(config, scriptConfig); - Assert.Equal(ID, jobHostConfig.HostId); - Assert.Equal(60 * 1000, jobHostConfig.Queues.MaxPollingInterval.TotalMilliseconds); - Assert.Equal(16, jobHostConfig.Queues.BatchSize); - Assert.Equal(5, jobHostConfig.Queues.MaxDequeueCount); - Assert.Equal(8, jobHostConfig.Queues.NewBatchThreshold); + Assert.Equal(ID, scriptConfig.HostConfig.HostId); + Assert.Equal(60 * 1000, scriptConfig.HostConfig.Queues.MaxPollingInterval.TotalMilliseconds); + Assert.Equal(16, scriptConfig.HostConfig.Queues.BatchSize); + Assert.Equal(5, scriptConfig.HostConfig.Queues.MaxDequeueCount); + Assert.Equal(8, scriptConfig.HostConfig.Queues.NewBatchThreshold); queuesConfig["maxPollingInterval"] = 5000; queuesConfig["batchSize"] = 17; queuesConfig["maxDequeueCount"] = 3; queuesConfig["newBatchThreshold"] = 123; - ScriptHost.ApplyConfiguration(config, jobHostConfig); + ScriptHost.ApplyConfiguration(config, scriptConfig); - Assert.Equal(5000, jobHostConfig.Queues.MaxPollingInterval.TotalMilliseconds); - Assert.Equal(17, jobHostConfig.Queues.BatchSize); - Assert.Equal(3, jobHostConfig.Queues.MaxDequeueCount); - Assert.Equal(123, jobHostConfig.Queues.NewBatchThreshold); + Assert.Equal(5000, scriptConfig.HostConfig.Queues.MaxPollingInterval.TotalMilliseconds); + Assert.Equal(17, scriptConfig.HostConfig.Queues.BatchSize); + Assert.Equal(3, scriptConfig.HostConfig.Queues.MaxDequeueCount); + Assert.Equal(123, scriptConfig.HostConfig.Queues.NewBatchThreshold); } [Fact] @@ -62,16 +62,16 @@ public void ApplyConfiguration_Singleton() config["id"] = ID; JObject singleton = new JObject(); config["singleton"] = singleton; - JobHostConfiguration jobHostConfig = new JobHostConfiguration(); + ScriptHostConfiguration scriptConfig = new ScriptHostConfiguration(); - ScriptHost.ApplyConfiguration(config, jobHostConfig); + ScriptHost.ApplyConfiguration(config, scriptConfig); - Assert.Equal(ID, jobHostConfig.HostId); - Assert.Equal(15, jobHostConfig.Singleton.LockPeriod.TotalSeconds); - Assert.Equal(1, jobHostConfig.Singleton.ListenerLockPeriod.TotalMinutes); - Assert.Equal(1, jobHostConfig.Singleton.ListenerLockRecoveryPollingInterval.TotalMinutes); - Assert.Equal(1, jobHostConfig.Singleton.LockAcquisitionTimeout.TotalMinutes); - Assert.Equal(3, jobHostConfig.Singleton.LockAcquisitionPollingInterval.TotalSeconds); + Assert.Equal(ID, scriptConfig.HostConfig.HostId); + Assert.Equal(15, scriptConfig.HostConfig.Singleton.LockPeriod.TotalSeconds); + Assert.Equal(1, scriptConfig.HostConfig.Singleton.ListenerLockPeriod.TotalMinutes); + Assert.Equal(1, scriptConfig.HostConfig.Singleton.ListenerLockRecoveryPollingInterval.TotalMinutes); + Assert.Equal(1, scriptConfig.HostConfig.Singleton.LockAcquisitionTimeout.TotalMinutes); + Assert.Equal(3, scriptConfig.HostConfig.Singleton.LockAcquisitionPollingInterval.TotalSeconds); singleton["lockPeriod"] = "00:00:17"; singleton["listenerLockPeriod"] = "00:00:22"; @@ -79,13 +79,13 @@ public void ApplyConfiguration_Singleton() singleton["lockAcquisitionTimeout"] = "00:05:00"; singleton["lockAcquisitionPollingInterval"] = "00:00:08"; - ScriptHost.ApplyConfiguration(config, jobHostConfig); + ScriptHost.ApplyConfiguration(config, scriptConfig); - Assert.Equal(17, jobHostConfig.Singleton.LockPeriod.TotalSeconds); - Assert.Equal(22, jobHostConfig.Singleton.ListenerLockPeriod.TotalSeconds); - Assert.Equal(33, jobHostConfig.Singleton.ListenerLockRecoveryPollingInterval.TotalSeconds); - Assert.Equal(5, jobHostConfig.Singleton.LockAcquisitionTimeout.TotalMinutes); - Assert.Equal(8, jobHostConfig.Singleton.LockAcquisitionPollingInterval.TotalSeconds); + Assert.Equal(17, scriptConfig.HostConfig.Singleton.LockPeriod.TotalSeconds); + Assert.Equal(22, scriptConfig.HostConfig.Singleton.ListenerLockPeriod.TotalSeconds); + Assert.Equal(33, scriptConfig.HostConfig.Singleton.ListenerLockRecoveryPollingInterval.TotalSeconds); + Assert.Equal(5, scriptConfig.HostConfig.Singleton.LockAcquisitionTimeout.TotalMinutes); + Assert.Equal(8, scriptConfig.HostConfig.Singleton.LockAcquisitionPollingInterval.TotalSeconds); } [Fact] @@ -95,14 +95,14 @@ public void ApplyConfiguration_Tracing() config["id"] = ID; JObject tracing = new JObject(); config["tracing"] = tracing; - JobHostConfiguration jobHostConfig = new JobHostConfiguration(); + ScriptHostConfiguration scriptConfig = new ScriptHostConfiguration(); - Assert.Equal(TraceLevel.Info, jobHostConfig.Tracing.ConsoleLevel); + Assert.Equal(TraceLevel.Info, scriptConfig.HostConfig.Tracing.ConsoleLevel); tracing["consoleLevel"] = "Verbose"; - ScriptHost.ApplyConfiguration(config, jobHostConfig); - Assert.Equal(TraceLevel.Verbose, jobHostConfig.Tracing.ConsoleLevel); + ScriptHost.ApplyConfiguration(config, scriptConfig); + Assert.Equal(TraceLevel.Verbose, scriptConfig.HostConfig.Tracing.ConsoleLevel); } } } diff --git a/test/WebJobs.Script.Tests/TestScripts/host.json b/test/WebJobs.Script.Tests/TestScripts/host.json new file mode 100644 index 0000000000..a1c24302e7 --- /dev/null +++ b/test/WebJobs.Script.Tests/TestScripts/host.json @@ -0,0 +1,3 @@ +{ + "id": "5a709861cab44e68bfed5d2c2fe7fc0c" +} \ No newline at end of file diff --git a/test/WebJobs.Script.Tests/WebJobs.Script.Tests.csproj b/test/WebJobs.Script.Tests/WebJobs.Script.Tests.csproj index 2d3964b086..13d61418d1 100644 --- a/test/WebJobs.Script.Tests/WebJobs.Script.Tests.csproj +++ b/test/WebJobs.Script.Tests/WebJobs.Script.Tests.csproj @@ -203,6 +203,9 @@ Always + + Always + Always