2025-02-20 16:48:31 +08:00
|
|
|
|
using Falcon.SugarApi.TimedBackgroundTask;
|
2025-02-24 16:55:32 +08:00
|
|
|
|
using Microsoft.AspNetCore.Mvc.TagHelpers;
|
2025-02-20 16:48:31 +08:00
|
|
|
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
2025-02-19 15:57:11 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
|
|
|
|
namespace Falcon.SugarApi.Test
|
|
|
|
|
{
|
|
|
|
|
[TestClass()]
|
|
|
|
|
public class CronExpressionTests
|
|
|
|
|
{
|
|
|
|
|
[TestMethod]
|
|
|
|
|
public void CronExpressionTest() {
|
|
|
|
|
var now20250213102512 = new DateTime(2025,2,13,10,25,12);
|
|
|
|
|
|
|
|
|
|
var cron = new CronExpression("0 30 3 * * 1-5"); // 工作日凌晨3:30:00
|
|
|
|
|
var nextTime = cron.GetNextOccurrence(now20250213102512);
|
2025-02-20 16:48:31 +08:00
|
|
|
|
|
2025-02-19 15:57:11 +08:00
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250214033000");
|
|
|
|
|
cron = new CronExpression("");//下一秒触发
|
|
|
|
|
nextTime = cron.GetNextOccurrence(now20250213102512);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250213102513");
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250213102514",nextTime.ToString());
|
|
|
|
|
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250213102515",nextTime.ToString());
|
|
|
|
|
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250213102516",nextTime.ToString());
|
|
|
|
|
|
|
|
|
|
cron = new CronExpression("10");//每分钟10秒时触发
|
|
|
|
|
nextTime = cron.GetNextOccurrence(now20250213102512);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250213102610");
|
|
|
|
|
|
|
|
|
|
cron = new CronExpression("10 25");//每个小时的25分10秒触发
|
|
|
|
|
nextTime = cron.GetNextOccurrence(now20250213102512);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250213112510");
|
|
|
|
|
|
|
|
|
|
cron = new CronExpression("10 25");//每个小时的25分10秒触发
|
|
|
|
|
nextTime = cron.GetNextOccurrence(now20250213102512);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250213112510");
|
|
|
|
|
|
|
|
|
|
cron = new CronExpression("10/10 25");//每个小时的25分10秒触发,只有每10秒触发一次
|
|
|
|
|
nextTime = cron.GetNextOccurrence(now20250213102512);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250213102520");
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250213102530");
|
|
|
|
|
|
|
|
|
|
cron = new CronExpression("0 0 3-5");//每天凌晨3点到5点每小时触发一次
|
|
|
|
|
nextTime = cron.GetNextOccurrence(now20250213102512);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250214030000");
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250214040000");
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250214050000");
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250215030000");
|
|
|
|
|
|
|
|
|
|
cron = new CronExpression("0 0 3-5 * * 1-5");//每个工作日凌晨3点到5点每小时触发一次
|
|
|
|
|
nextTime = cron.GetNextOccurrence(now20250213102512);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250214030000");
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250214040000");
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250214050000");
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250217030000",DateToString(nextTime));
|
|
|
|
|
|
|
|
|
|
cron = new CronExpression("0 0/30 3-5 * * 1-5");//每个工作日凌晨3点到5点每小时触发两次,平均每半小时一次
|
|
|
|
|
nextTime = cron.GetNextOccurrence(now20250213102512);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250214030000",nextTime.ToString());
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250214033000");
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250214040000");
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250214043000");
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250214050000");
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250214053000");
|
|
|
|
|
nextTime = cron.GetNextOccurrence(nextTime);
|
|
|
|
|
Assert.IsTrue(DateToString(nextTime) == "20250217030000");
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string? DateToString(DateTime? date) => date?.ToString("yyyyMMddHHmmss");
|
2025-02-24 16:55:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------
|
|
|
|
|
// 基础语法解析测试
|
|
|
|
|
//-----------------------------
|
|
|
|
|
[TestMethod]
|
|
|
|
|
public void TestBasicWildcard() {
|
|
|
|
|
var cron = new CronExpression("* * * * * * *");
|
|
|
|
|
Assert.AreEqual(60,cron.Seconds.Count,"秒字段应包含0-59");
|
|
|
|
|
Assert.AreEqual(12,cron.Months.Count,"月字段应包含1-12");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[TestMethod]
|
|
|
|
|
public void TestFixedValue() {
|
|
|
|
|
var cron = new CronExpression("5 10 3 15 6 2 2026");
|
|
|
|
|
Assert.IsTrue(cron.Seconds.Contains(5));
|
|
|
|
|
Assert.IsTrue(cron.Minutes.Contains(10));
|
|
|
|
|
Assert.IsTrue(cron.Hours.Contains(3));
|
|
|
|
|
Assert.IsTrue(cron.DaysOfMonth.Contains(15));
|
|
|
|
|
Assert.IsTrue(cron.Months.Contains(6));
|
|
|
|
|
Assert.IsTrue(cron.DaysOfWeek.Contains(2));
|
|
|
|
|
Assert.IsTrue(cron.Years.Contains(2026));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------
|
|
|
|
|
// 复杂语法测试
|
|
|
|
|
//-----------------------------
|
|
|
|
|
[TestMethod]
|
|
|
|
|
public void TestRangeAndStep() {
|
|
|
|
|
//var cron = new CronExpression("0-30/15 10,20,30 * 1-5 */3 * *");
|
|
|
|
|
//CollectionAssert.AreEqual(new[] { 0,15,30 },cron.Seconds);
|
|
|
|
|
//CollectionAssert.AreEqual(new[] { 10,20,30 },cron.Minutes);
|
|
|
|
|
//CollectionAssert.AreEqual(new[] { 1,2,3,4,5 },cron.DaysOfMonth);
|
|
|
|
|
//CollectionAssert.AreEqual(new[] { 1,4,7,10 },cron.Months);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------
|
|
|
|
|
// 字段省略测试
|
|
|
|
|
//-----------------------------
|
|
|
|
|
[TestMethod]
|
|
|
|
|
public void TestPartialExpression() {
|
|
|
|
|
var cron = new CronExpression("30 15 4");
|
|
|
|
|
Assert.AreEqual(1,cron.Seconds.Count);
|
|
|
|
|
Assert.AreEqual(1,cron.Minutes.Count);
|
|
|
|
|
Assert.AreEqual(1,cron.Hours.Count);
|
|
|
|
|
Assert.AreEqual(31,cron.DaysOfMonth.Count); // 默认1-31
|
|
|
|
|
Assert.AreEqual(12,cron.Months.Count); // 默认1-12
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------
|
|
|
|
|
// 边界值测试
|
|
|
|
|
//-----------------------------
|
|
|
|
|
[TestMethod]
|
|
|
|
|
public void TestBoundaryValues() {
|
|
|
|
|
// 最大最小值测试
|
|
|
|
|
var cron = new CronExpression("59 59 23 31 12 6 2026");
|
|
|
|
|
Assert.IsTrue(cron.Seconds.Contains(59));
|
|
|
|
|
Assert.IsTrue(cron.DaysOfMonth.Contains(31));
|
|
|
|
|
Assert.IsTrue(cron.Months.Contains(12));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------
|
|
|
|
|
// 错误处理测试
|
|
|
|
|
//-----------------------------
|
|
|
|
|
[TestMethod]
|
|
|
|
|
public void TestInvalidCharacter() {
|
|
|
|
|
try {
|
|
|
|
|
var _ = new CronExpression("5a * * * * *");
|
|
|
|
|
}
|
|
|
|
|
catch(CronAdjustNullException) { }
|
|
|
|
|
catch(CronException) { }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[TestMethod]
|
|
|
|
|
public void TestOutOfRangeValue() {
|
|
|
|
|
try {
|
|
|
|
|
var _ = new CronExpression("70 * * * * *");
|
|
|
|
|
}
|
|
|
|
|
catch(CronAdjustNullException) { }
|
|
|
|
|
catch(CronException) { }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------
|
|
|
|
|
// 下次执行时间计算测试
|
|
|
|
|
//-----------------------------
|
|
|
|
|
[TestMethod]
|
|
|
|
|
public void TestNextOccurrence_Basic() {
|
|
|
|
|
var baseTime = new DateTime(2025,10,1,12,30,15);
|
|
|
|
|
var cron = new CronExpression("30 * * * * * *");
|
|
|
|
|
|
|
|
|
|
// 下一个30秒
|
|
|
|
|
var expected = new DateTime(2025,10,1,12,30,30);
|
|
|
|
|
var actual = cron.GetNextOccurrence(baseTime);
|
|
|
|
|
Assert.AreEqual(expected,actual);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[TestMethod]
|
|
|
|
|
public void TestNextOccurrence_MonthRollover() {
|
|
|
|
|
var baseTime = new DateTime(2024,12,31,23,59,59);
|
|
|
|
|
var cron = new CronExpression("* * * 1 * * *"); // 每月1号
|
|
|
|
|
|
|
|
|
|
var expected = new DateTime(2025,1,1,0,0,0);
|
|
|
|
|
var actual = cron.GetNextOccurrence(baseTime);
|
|
|
|
|
Assert.AreEqual(expected,actual);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------
|
|
|
|
|
// 特殊日期处理测试
|
|
|
|
|
//-----------------------------
|
|
|
|
|
[TestMethod]
|
|
|
|
|
public void TestFebruaryHandling() {
|
|
|
|
|
// 测试闰年2月29日
|
|
|
|
|
var cron = new CronExpression("0 0 0 29 2 * 2028");
|
|
|
|
|
Assert.IsTrue(cron.DaysOfMonth.Contains(29));
|
|
|
|
|
|
|
|
|
|
var nextTime = cron.GetNextOccurrence(new DateTime(2028,2,28));
|
|
|
|
|
Assert.AreEqual(new DateTime(2028,2,29),nextTime.Date);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------
|
|
|
|
|
// 日期与星期冲突测试
|
|
|
|
|
//-----------------------------
|
|
|
|
|
[TestMethod]
|
|
|
|
|
public void TestDayOfWeekConflict() {
|
|
|
|
|
// 每月15号且为星期一(2023-10-15是星期日)
|
|
|
|
|
var cron = new CronExpression("* * * 15 * 1 *");
|
|
|
|
|
var baseTime = new DateTime(2023,10,1);
|
|
|
|
|
|
|
|
|
|
var nextTime = cron.GetNextOccurrence(baseTime);
|
|
|
|
|
Assert.AreEqual(2025,nextTime.Year,nextTime.ToString());
|
|
|
|
|
Assert.AreEqual(9,nextTime.Month,nextTime.ToString());
|
|
|
|
|
Assert.AreEqual(15,nextTime.Day,nextTime.ToString());
|
|
|
|
|
Assert.AreEqual(DayOfWeek.Monday,nextTime.DayOfWeek);
|
|
|
|
|
}
|
2025-02-19 15:57:11 +08:00
|
|
|
|
}
|
|
|
|
|
}
|