forked from admin/VolcanicAgenticCore
- JobScheduler: a stored job whose zone lookup throws no longer fails StartAsync; timer re-armed under the lock; a delivery cut off by shutdown isn't recorded (one-offs fire again after restart); CancelJobAsync in one step - Schedules.ParseAt: ISO 8601 with a date only (no machine-clock date for a bare 09:00) - core: a FollowUp prompt that loses the race to a starting run joins it as a follow-up, not steering - Telegram: TimeZoneFor tolerates non-numeric targets; RunPromptAsync waits only when queued; one agent dir - ScriptRunner: bad workspace paths are Failed, not exceptions; zone id helpers share TimeZoneIds.ToIana's rule - tests: no wall-clock sleeps in scheduler tests; transcript-entry, disabled-scheduler and failing-prompt coverage - docs: spec notes for the above; README row for the scheduler
40 lines
2.3 KiB
C#
40 lines
2.3 KiB
C#
using Volcanic.AgenticCore.Extensions.Scheduler;
|
|
using Volcanic.AgenticCore.Extensions.Tests.Scheduler.Support;
|
|
|
|
namespace Volcanic.AgenticCore.Extensions.Tests.Scheduler;
|
|
|
|
public sealed class JobFormatTests
|
|
{
|
|
private static readonly DateTimeOffset Now = SchedulerHarness.Start; // Sat 26 Sep 14:03 Berlin
|
|
private static readonly TimeZoneInfo Berlin = SchedulerHarness.Berlin;
|
|
|
|
private static ScheduledJob Job(string id, string name, JobKind kind, JobSchedule schedule) => new()
|
|
{
|
|
Id = id, Target = "111", Name = name, Kind = kind, Schedule = schedule, CreatedAt = Now,
|
|
Text = kind == JobKind.Watcher ? null : name, Command = kind == JobKind.Watcher ? "check" : null,
|
|
};
|
|
|
|
[Fact]
|
|
public void Job_lines_show_kind_schedule_next_and_last_failure()
|
|
{
|
|
var once = new DateTimeOffset(2026, 9, 27, 7, 0, 0, TimeSpan.Zero);
|
|
Assert.Equal("`k7m2q` ⏰ Call the dentist · once 27 Sep 09:00",
|
|
JobFormat.Line(new JobView(Job("k7m2q", "Call the dentist", JobKind.Reminder, new JobSchedule(once, null)), once), Berlin, Now));
|
|
Assert.Equal("`p3xz9` 💬 Inbox summary · `0 8 * * 1-5` · next 28 Sep 08:00",
|
|
JobFormat.Line(new JobView(Job("p3xz9", "Inbox summary", JobKind.Prompt, new JobSchedule(null, "0 8 * * 1-5")), new DateTimeOffset(2026, 9, 28, 6, 0, 0, TimeSpan.Zero)), Berlin, Now));
|
|
var failing = Job("w8r4t", "Price check", JobKind.Watcher, new JobSchedule(null, "*/10 * * * *")) with { LastResult = new JobResult(false, 1, false, "x", Now) };
|
|
Assert.Equal("`w8r4t` 🔍 Price check · `*/10 * * * *` · next 14:10 · last: failed (exit 1)",
|
|
JobFormat.Line(new JobView(failing, new DateTimeOffset(2026, 9, 26, 12, 10, 0, TimeSpan.Zero)), Berlin, Now));
|
|
}
|
|
|
|
[Fact]
|
|
public void When_omits_the_date_today()
|
|
{
|
|
Assert.Equal("14:10", JobFormat.When(new DateTimeOffset(2026, 9, 26, 12, 10, 0, TimeSpan.Zero), Berlin, Now));
|
|
Assert.Equal("27 Sep 00:10", JobFormat.When(new DateTimeOffset(2026, 9, 26, 22, 10, 0, TimeSpan.Zero), Berlin, Now));
|
|
Assert.Equal("Sat 2026-09-26 14:03", JobFormat.Stamp(Now, Berlin));
|
|
Assert.Equal("exit 1, timed out", JobFormat.FailureReason(new JobResult(false, 1, true, null, Now)));
|
|
Assert.Equal("did not start", JobFormat.FailureReason(new JobResult(false, null, false, "failed to start", Now)));
|
|
}
|
|
}
|