public async Task BindAsync_ReturnsExpectedTriggerData() { ParameterInfo parameter = GetType().GetMethod("TestTimerJob").GetParameters()[0]; MethodInfo methodInfo = (MethodInfo)parameter.Member; string timerName = string.Format("{0}.{1}", methodInfo.DeclaringType.FullName, methodInfo.Name); Mock <ScheduleMonitor> mockScheduleMonitor = new Mock <ScheduleMonitor>(MockBehavior.Strict); ScheduleStatus status = new ScheduleStatus(); mockScheduleMonitor.Setup(p => p.GetStatusAsync(timerName)).ReturnsAsync(status); TimerTriggerAttribute attribute = parameter.GetCustomAttribute <TimerTriggerAttribute>(); TimersConfiguration config = new TimersConfiguration(); config.ScheduleMonitor = mockScheduleMonitor.Object; TestTraceWriter trace = new TestTraceWriter(); TimerTriggerBinding binding = new TimerTriggerBinding(parameter, attribute, config, trace); // when we bind to a non-TimerInfo (e.g. in a Dashboard invocation) a new // TimerInfo is created, with the ScheduleStatus populated FunctionBindingContext functionContext = new FunctionBindingContext(Guid.NewGuid(), CancellationToken.None, trace); ValueBindingContext context = new ValueBindingContext(functionContext, CancellationToken.None); TriggerData triggerData = (TriggerData)(await binding.BindAsync("", context)); TimerInfo timerInfo = (TimerInfo)triggerData.ValueProvider.GetValue(); Assert.Same(status, timerInfo.ScheduleStatus); // when we pass in a TimerInfo that is used TimerInfo expected = new TimerInfo(attribute.Schedule, status); triggerData = (TriggerData)(await binding.BindAsync(expected, context)); timerInfo = (TimerInfo)triggerData.ValueProvider.GetValue(); Assert.Same(expected, timerInfo); }
public void Create_ConstantSchedule_CreatesExpectedSchedule() { TimerTriggerAttribute attribute = new TimerTriggerAttribute("00:00:15"); INameResolver nameResolver = new TestNameResolver(); ConstantSchedule schedule = (ConstantSchedule)TimerSchedule.Create(attribute, nameResolver); Assert.False(attribute.UseMonitor); DateTime now = new DateTime(2015, 5, 22, 9, 45, 00); DateTime nextOccurrence = schedule.GetNextOccurrence(now); Assert.Equal(new TimeSpan(0, 0, 15), nextOccurrence - now); // For schedules occuring on an interval greater than a minute, we expect // UseMonitor to be defaulted to true attribute = new TimerTriggerAttribute("01:00:00"); schedule = (ConstantSchedule)TimerSchedule.Create(attribute, nameResolver); Assert.True(attribute.UseMonitor); // verify that if UseMonitor is set explicitly, it is not overridden attribute = new TimerTriggerAttribute("01:00:00"); attribute.UseMonitor = false; schedule = (ConstantSchedule)TimerSchedule.Create(attribute, nameResolver); Assert.False(attribute.UseMonitor); }
public void Create_ConstantSchedule_CreatesExpectedSchedule() { TimerTriggerAttribute attribute = new TimerTriggerAttribute("00:00:15"); INameResolver nameResolver = new TestNameResolver(); ConstantSchedule schedule = (ConstantSchedule)TimerSchedule.Create(attribute, nameResolver, _logger); Assert.False(attribute.UseMonitor); var log = _loggerProvider.GetAllLogMessages().Single(); Assert.Equal("UseMonitor changed to false based on schedule frequency.", log.FormattedMessage); Assert.Equal(LogLevel.Debug, log.Level); DateTime now = new DateTime(2015, 5, 22, 9, 45, 00); DateTime nextOccurrence = schedule.GetNextOccurrence(now); Assert.Equal(new TimeSpan(0, 0, 15), nextOccurrence - now); // For schedules occuring on an interval greater than a minute, we expect // UseMonitor to be defaulted to true _loggerProvider.ClearAllLogMessages(); attribute = new TimerTriggerAttribute("01:00:00"); schedule = (ConstantSchedule)TimerSchedule.Create(attribute, nameResolver, _logger); Assert.True(attribute.UseMonitor); Assert.Empty(_loggerProvider.GetAllLogMessages()); // verify that if UseMonitor is set explicitly, it is not overridden attribute = new TimerTriggerAttribute("01:00:00"); attribute.UseMonitor = false; schedule = (ConstantSchedule)TimerSchedule.Create(attribute, nameResolver, _logger); Assert.False(attribute.UseMonitor); Assert.Empty(_loggerProvider.GetAllLogMessages()); }
public TimerTriggerBinding(ParameterInfo parameter, TimerTriggerAttribute attribute, TimersConfiguration config) { _attribute = attribute; _parameter = parameter; _config = config; _bindingContract = CreateBindingDataContract(); }
public async Task Generate_EndToEnd() { // construct our TimerTrigger attribute ([TimerTrigger("00:00:02", RunOnStartup = true)]) Collection <ParameterDescriptor> parameters = new Collection <ParameterDescriptor>(); ParameterDescriptor parameter = new ParameterDescriptor("timerInfo", typeof(TimerInfo)); ConstructorInfo ctorInfo = typeof(TimerTriggerAttribute).GetConstructor(new Type[] { typeof(string) }); PropertyInfo runOnStartupProperty = typeof(TimerTriggerAttribute).GetProperty("RunOnStartup"); CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder( ctorInfo, new object[] { "00:00:02" }, new PropertyInfo[] { runOnStartupProperty }, new object[] { true }); parameter.CustomAttributes.Add(attributeBuilder); parameters.Add(parameter); // create the FunctionDefinition FunctionMetadata metadata = new FunctionMetadata(); TestInvoker invoker = new TestInvoker(); FunctionDescriptor function = new FunctionDescriptor("TimerFunction", invoker, metadata, parameters, null, null, null); Collection <FunctionDescriptor> functions = new Collection <FunctionDescriptor>(); functions.Add(function); // Get the Type Attributes (in this case, a TimeoutAttribute) ScriptHostConfiguration scriptConfig = new ScriptHostConfiguration(); scriptConfig.FunctionTimeout = TimeSpan.FromMinutes(5); Collection <CustomAttributeBuilder> typeAttributes = new Collection <CustomAttributeBuilder>(); // generate the Type Type functionType = FunctionGenerator.Generate("TestScriptHost", "TestFunctions", typeAttributes, functions); // verify the generated function MethodInfo method = functionType.GetMethod("TimerFunction"); ParameterInfo triggerParameter = method.GetParameters()[0]; TimerTriggerAttribute triggerAttribute = triggerParameter.GetCustomAttribute <TimerTriggerAttribute>(); Assert.NotNull(triggerAttribute); // start the JobHost which will start running the timer function JobHostConfiguration config = new JobHostConfiguration() { TypeLocator = new TypeLocator(functionType), LoggerFactory = new LoggerFactory() }; config.UseTimers(); JobHost host = new JobHost(config); await host.StartAsync(); await Task.Delay(3000); await host.StopAsync(); // verify our custom invoker was called Assert.True(invoker.InvokeCount >= 2); }
public void Constructor_ScheduleType() { TimerTriggerAttribute attribute = new TimerTriggerAttribute(typeof(DailySchedule)); Assert.Null(attribute.ScheduleExpression); Assert.Equal(typeof(DailySchedule), attribute.ScheduleType); Assert.True(attribute.UseMonitor); }
public void Constructor_ScheduleExpression() { TimerTriggerAttribute attribute = new TimerTriggerAttribute("00:00:15"); Assert.Equal("00:00:15", attribute.ScheduleExpression); Assert.Null(attribute.ScheduleType); Assert.True(attribute.UseMonitor); }
public void Create_InvalidSchedule() { TimerTriggerAttribute attribute = new TimerTriggerAttribute("invalid"); ArgumentException ex = Assert.Throws <ArgumentException>(() => { TimerSchedule.Create(attribute, new TestNameResolver()); }); Assert.Equal("The schedule expression 'invalid' was not recognized as a valid cron expression or timespan string.", ex.Message); }
public TimerTriggerBinding(ParameterInfo parameter, TimerTriggerAttribute attribute, TimersConfiguration config, TraceWriter trace) { _attribute = attribute; _parameter = parameter; _config = config; _trace = trace; _bindingContract = CreateBindingDataContract(); MethodInfo methodInfo = (MethodInfo)parameter.Member; _timerName = string.Format("{0}.{1}", methodInfo.DeclaringType.FullName, methodInfo.Name); }
public void Constructor_CreatesCronSchedule() { TimerTriggerAttribute attribute = new TimerTriggerAttribute("*/15 * * * * *"); Assert.Equal(typeof(CronSchedule), attribute.Schedule.GetType()); DateTime now = new DateTime(2015, 5, 22, 9, 45, 00); DateTime nextOccurrence = attribute.Schedule.GetNextOccurrence(now); Assert.Equal(new TimeSpan(0, 0, 15), nextOccurrence - now); }
public void Constructor_CreatesConstantSchedule() { TimerTriggerAttribute attribute = new TimerTriggerAttribute("00:00:15"); Assert.Equal(typeof(ConstantSchedule), attribute.Schedule.GetType()); DateTime now = DateTime.Now; DateTime nextOccurrence = attribute.Schedule.GetNextOccurrence(now); Assert.Equal(new TimeSpan(0, 0, 15), nextOccurrence - now); }
public TimerListener(TimerTriggerAttribute attribute, TimerSchedule schedule, string timerName, TimersOptions options, ITriggeredFunctionExecutor executor, ILogger logger, ScheduleMonitor scheduleMonitor) { _attribute = attribute; _timerName = timerName; _options = options; _executor = executor; _logger = logger; _cancellationTokenSource = new CancellationTokenSource(); _schedule = schedule; ScheduleMonitor = _attribute.UseMonitor ? scheduleMonitor : null; }
public TimerListener(TimerTriggerAttribute attribute, string timerName, TimersConfiguration config, ITriggeredFunctionExecutor executor) { _attribute = attribute; _timerName = timerName; _config = config; _executor = executor; _cancellationTokenSource = new CancellationTokenSource(); _schedule = _attribute.Schedule; _scheduleMonitor = _config.ScheduleMonitor; }
public TimerListener(TimerTriggerAttribute attribute, string timerName, TimersConfiguration config, ITriggeredFunctionExecutor executor, TraceWriter trace) { _attribute = attribute; _timerName = timerName; _config = config; _executor = executor; _trace = trace; _cancellationTokenSource = new CancellationTokenSource(); _schedule = _attribute.Schedule; ScheduleMonitor = _attribute.UseMonitor ? _config.ScheduleMonitor : null; }
public TimerTriggerBinding(ParameterInfo parameter, TimerTriggerAttribute attribute, TimerSchedule schedule, TimersOptions options, ILogger logger, ScheduleMonitor scheduleMonitor) { _attribute = attribute; _schedule = schedule; _parameter = parameter; _options = options; _logger = logger; _scheduleMonitor = scheduleMonitor; _bindingContract = CreateBindingDataContract(); MethodInfo methodInfo = (MethodInfo)parameter.Member; _timerName = string.Format("{0}.{1}", methodInfo.DeclaringType.FullName, methodInfo.Name); }
public void Create_CustomSchedule_CreatesExpectedSchedule() { TimerTriggerAttribute attribute = new TimerTriggerAttribute(typeof(CustomSchedule)); INameResolver nameResolver = new TestNameResolver(); CustomSchedule schedule = (CustomSchedule)TimerSchedule.Create(attribute, nameResolver); Assert.NotNull(schedule); Assert.True(attribute.UseMonitor); // verify that if UseMonitor is set explicitly, it is not overridden attribute = new TimerTriggerAttribute(typeof(CustomSchedule)); attribute.UseMonitor = false; schedule = (CustomSchedule)TimerSchedule.Create(attribute, nameResolver); Assert.False(attribute.UseMonitor); }
public void Create_UsesNameResolver() { TimerTriggerAttribute attribute = new TimerTriggerAttribute("%test_schedule%"); TestNameResolver nameResolver = new TestNameResolver(); nameResolver.Values.Add("test_schedule", "*/15 * * * * *"); CronSchedule schedule = (CronSchedule)TimerSchedule.Create(attribute, nameResolver); Assert.False(attribute.UseMonitor); DateTime now = new DateTime(2015, 5, 22, 9, 45, 00); DateTime nextOccurrence = schedule.GetNextOccurrence(now); Assert.Equal(new TimeSpan(0, 0, 15), nextOccurrence - now); }
public void GenerateTimerTriggerFunction() { BindingMetadata trigger = BindingMetadata.Create(new JObject { { "type", "TimerTrigger" }, { "name", "timerInfo" }, { "schedule", "* * * * * *" }, { "runOnStartup", true }, { "direction", "in" } }); MethodInfo method = GenerateMethod(trigger); VerifyCommonProperties(method); // verify trigger parameter ParameterInfo parameter = method.GetParameters()[0]; Assert.Equal("timerInfo", parameter.Name); Assert.Equal(typeof(TimerInfo), parameter.ParameterType); TimerTriggerAttribute attribute = parameter.GetCustomAttribute <TimerTriggerAttribute>(); Assert.Equal("* * * * * *", attribute.ScheduleExpression); Assert.True(attribute.UseMonitor); Assert.True(attribute.RunOnStartup); trigger = BindingMetadata.Create(new JObject { { "type", "TimerTrigger" }, { "name", "timerInfo" }, { "schedule", "* * * * * *" }, { "useMonitor", false }, { "direction", "in" } }); method = GenerateMethod(trigger); VerifyCommonProperties(method); // verify trigger parameter parameter = method.GetParameters()[0]; Assert.Equal("timerInfo", parameter.Name); Assert.Equal(typeof(TimerInfo), parameter.ParameterType); attribute = parameter.GetCustomAttribute <TimerTriggerAttribute>(); Assert.Equal("* * * * * *", attribute.ScheduleExpression); Assert.False(attribute.UseMonitor); Assert.False(attribute.RunOnStartup); }
private void VerifyConstantSchedule(string expression, TimeSpan expectedInterval) { Assert.True(TimeSpan.TryParse(expression, out TimeSpan timeSpan)); Assert.Equal(timeSpan, expectedInterval); TimerTriggerAttribute attribute = new TimerTriggerAttribute(expression); INameResolver nameResolver = new TestNameResolver(); ConstantSchedule schedule = (ConstantSchedule)TimerSchedule.Create(attribute, nameResolver, _logger); DateTime now = new DateTime(2015, 5, 22, 9, 45, 00); var occurrences = schedule.GetNextOccurrences(5, now); for (int i = 0; i < 4; i++) { var delta = occurrences.ElementAt(i + 1) - occurrences.ElementAt(i); Assert.Equal(expectedInterval, delta); } }
private void CreateTestListener(string expression, bool useMonitor = true) { _attribute = new TimerTriggerAttribute(expression); _attribute.UseMonitor = useMonitor; _config = new TimersConfiguration(); _mockScheduleMonitor = new Mock <ScheduleMonitor>(MockBehavior.Strict); _config.ScheduleMonitor = _mockScheduleMonitor.Object; _mockTriggerExecutor = new Mock <ITriggeredFunctionExecutor>(MockBehavior.Strict); FunctionResult result = new FunctionResult(true); _mockTriggerExecutor.Setup(p => p.TryExecuteAsync(It.IsAny <TriggeredFunctionData>(), It.IsAny <CancellationToken>())) .Callback <TriggeredFunctionData, CancellationToken>((mockFunctionData, mockToken) => { _triggeredFunctionData = mockFunctionData; }) .Returns(Task.FromResult(result)); _listener = new TimerListener(_attribute, _testTimerName, _config, _mockTriggerExecutor.Object); }
private void CreateTestListener(string expression, bool useMonitor = true, Action functionAction = null) { _attribute = new TimerTriggerAttribute(expression); _schedule = TimerSchedule.Create(_attribute, new TestNameResolver()); _attribute.UseMonitor = useMonitor; _options = new TimersOptions(); _mockScheduleMonitor = new Mock <ScheduleMonitor>(MockBehavior.Strict); _mockTriggerExecutor = new Mock <ITriggeredFunctionExecutor>(MockBehavior.Strict); FunctionResult result = new FunctionResult(true); _mockTriggerExecutor.Setup(p => p.TryExecuteAsync(It.IsAny <TriggeredFunctionData>(), It.IsAny <CancellationToken>())) .Callback <TriggeredFunctionData, CancellationToken>((mockFunctionData, mockToken) => { _triggeredFunctionData = mockFunctionData; functionAction?.Invoke(); }) .Returns(Task.FromResult(result)); _logger = new TestLogger(null); _listener = new TimerListener(_attribute, _schedule, _testTimerName, _options, _mockTriggerExecutor.Object, _logger, _mockScheduleMonitor.Object); }
public Task <ITriggerBinding> TryCreateAsync(TriggerBindingProviderContext context) { if (context == null) { throw new ArgumentNullException("context"); } ParameterInfo parameter = context.Parameter; TimerTriggerAttribute timerTriggerAttribute = parameter.GetCustomAttribute <TimerTriggerAttribute>(inherit: false); if (timerTriggerAttribute == null) { return(Task.FromResult <ITriggerBinding>(null)); } if (parameter.ParameterType != typeof(TimerInfo)) { throw new InvalidOperationException(string.Format("Can't bind TimerTriggerAttribute to type '{0}'.", parameter.ParameterType)); } return(Task.FromResult <ITriggerBinding>(new TimerTriggerBinding(parameter, timerTriggerAttribute, _config, _trace))); }
public void GenerateTimerTriggerFunction() { TimerBindingMetadata trigger = new TimerBindingMetadata { Type = BindingType.TimerTrigger, Schedule = "* * * * * *", RunOnStartup = true }; MethodInfo method = GenerateMethod(trigger); VerifyCommonProperties(method); // verify trigger parameter ParameterInfo parameter = method.GetParameters()[0]; Assert.Equal("input", parameter.Name); Assert.Equal(typeof(TimerInfo), parameter.ParameterType); TimerTriggerAttribute attribute = parameter.GetCustomAttribute <TimerTriggerAttribute>(); Assert.Equal("* * * * * *", attribute.ScheduleExpression); Assert.True(attribute.RunOnStartup); }
public async Task BindAsync_ReturnsExpectedTriggerData() { ParameterInfo parameter = GetType().GetMethod("TestTimerJob").GetParameters()[0]; MethodInfo methodInfo = (MethodInfo)parameter.Member; string timerName = string.Format("{0}.{1}", methodInfo.DeclaringType.FullName, methodInfo.Name); Mock <ScheduleMonitor> mockScheduleMonitor = new Mock <ScheduleMonitor>(MockBehavior.Strict); ScheduleStatus status = new ScheduleStatus(); mockScheduleMonitor.Setup(p => p.GetStatusAsync(timerName)).ReturnsAsync(status); TimerTriggerAttribute attribute = parameter.GetCustomAttribute <TimerTriggerAttribute>(); INameResolver nameResolver = new TestNameResolver(); TimerSchedule schedule = TimerSchedule.Create(attribute, nameResolver); TimersOptions options = new TimersOptions(); ILoggerFactory loggerFactory = new LoggerFactory(); loggerFactory.AddProvider(new TestLoggerProvider()); TimerTriggerBinding binding = new TimerTriggerBinding(parameter, attribute, schedule, options, loggerFactory.CreateLogger("Test"), mockScheduleMonitor.Object); // when we bind to a non-TimerInfo (e.g. in a Dashboard invocation) a new // TimerInfo is created, with the ScheduleStatus populated FunctionBindingContext functionContext = new FunctionBindingContext(Guid.NewGuid(), CancellationToken.None); ValueBindingContext context = new ValueBindingContext(functionContext, CancellationToken.None); TriggerData triggerData = (TriggerData)(await binding.BindAsync(string.Empty, context)); TimerInfo timerInfo = (TimerInfo)(await triggerData.ValueProvider.GetValueAsync()); Assert.Same(status, timerInfo.ScheduleStatus); // when we pass in a TimerInfo that is used TimerInfo expected = new TimerInfo(schedule, status); triggerData = (TriggerData)(await binding.BindAsync(expected, context)); timerInfo = (TimerInfo)(await triggerData.ValueProvider.GetValueAsync()); Assert.Same(expected, timerInfo); }
public async Task Generate_EndToEnd() { // construct our TimerTrigger attribute ([TimerTrigger("00:00:02", RunOnStartup = true)]) Collection <ParameterDescriptor> parameters = new Collection <ParameterDescriptor>(); ParameterDescriptor parameter = new ParameterDescriptor("timerInfo", typeof(TimerInfo)); ConstructorInfo ctorInfo = typeof(TimerTriggerAttribute).GetConstructor(new Type[] { typeof(string) }); PropertyInfo runOnStartupProperty = typeof(TimerTriggerAttribute).GetProperty("RunOnStartup"); CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder( ctorInfo, new object[] { "00:00:02" }, new PropertyInfo[] { runOnStartupProperty }, new object[] { true }); parameter.CustomAttributes.Add(attributeBuilder); parameters.Add(parameter); // create the FunctionDefinition FunctionMetadata metadata = new FunctionMetadata(); TestInvoker invoker = new TestInvoker(); FunctionDescriptor function = new FunctionDescriptor("TimerFunction", invoker, metadata, parameters, null, null, null); Collection <FunctionDescriptor> functions = new Collection <FunctionDescriptor>(); functions.Add(function); // Get the Type Attributes (in this case, a TimeoutAttribute) ScriptJobHostOptions scriptConfig = new ScriptJobHostOptions(); scriptConfig.FunctionTimeout = TimeSpan.FromMinutes(5); Collection <CustomAttributeBuilder> typeAttributes = new Collection <CustomAttributeBuilder>(); // generate the Type Type functionType = FunctionGenerator.Generate("TestScriptHost", "TestFunctions", typeAttributes, functions); // verify the generated function MethodInfo method = functionType.GetMethod("TimerFunction"); ParameterInfo triggerParameter = method.GetParameters()[0]; TimerTriggerAttribute triggerAttribute = triggerParameter.GetCustomAttribute <TimerTriggerAttribute>(); Assert.NotNull(triggerAttribute); // start the JobHost which will start running the timer function var builder = new HostBuilder() .ConfigureWebJobs(b => { b.AddTimers() .AddAzureStorageCoreServices(); }) .ConfigureServices(s => { s.AddSingleton <ITypeLocator>(new TestTypeLocator(functionType)); s.AddSingleton <ILoggerFactory>(new LoggerFactory()); TestHelpers.AddTestAzureBlobStorageProvider(s, TestHelpers.GetTestConfiguration()); TestHostBuilderExtensions.AddMockedSingleton <IScriptHostManager>(s); }); using (var host = builder.Build()) { await host.StartAsync(); await Task.Delay(3000); await host.StopAsync(); } // verify our custom invoker was called Assert.True(invoker.InvokeCount >= 2); }