forked from admin/VolcanicAgenticCore
- log an unknown stored zone once even when the tool description reads it first - serialise the flow's token write with /calendar_disconnect under the flow gate - a cancelled or expired pending flow is cleared, not re-sent or shown - chat keys anchor with \z so a trailing newline is hashed - a timeMax date includes that whole day (spec updated) - dispose the flow's CancellationTokenSource, drop ConnectFlow.Token, Begin is a plain write - GoogleCalendarOptions.IsConfigured replaces the host's copy of the rule; StoredToken is internal - test BotSetupService's menu through DI, tokens absent from tool results - Telegram.Tests csproj reference placed as in telegram-message-context; ChatHost passes calendar by name - docs: per-event timeZone, both config sources for /calendar_*
91 lines
4.1 KiB
C#
91 lines
4.1 KiB
C#
using Microsoft.Extensions.Logging;
|
|
using Volcanic.AgenticCore.Abstractions.Extensions.Events;
|
|
using Volcanic.AgenticCore.Extensions.GoogleCalendar;
|
|
|
|
namespace Volcanic.AgenticCore.Extensions.Tests.GoogleCalendar;
|
|
|
|
public class GoogleCalendarExtensionTests
|
|
{
|
|
[Fact]
|
|
public async Task Without_a_client_it_registers_nothing_and_logs_one_info_line()
|
|
{
|
|
var logger = new ListLogger();
|
|
var api = new CalendarFakeApi(logger);
|
|
var extension = new GoogleCalendarExtension(new GoogleCalendarOptions { GetEnv = _ => null });
|
|
Assert.Equal("google-calendar", extension.Name);
|
|
await extension.ActivateAsync(api, CancellationToken.None);
|
|
Assert.Empty(api.Tools);
|
|
Assert.Empty(api.Commands);
|
|
var entry = Assert.Single(logger.Entries);
|
|
Assert.Equal((LogLevel.Information, "google-calendar disabled: set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET"), entry);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("cid", null, "GOOGLE_CLIENT_SECRET")]
|
|
[InlineData(null, "csecret", "GOOGLE_CLIENT_ID")]
|
|
public async Task With_only_one_of_id_and_secret_it_logs_a_warning(string? id, string? secret, string missing)
|
|
{
|
|
var logger = new ListLogger();
|
|
var api = new CalendarFakeApi(logger);
|
|
await new GoogleCalendarExtension(new GoogleCalendarOptions { ClientId = id, ClientSecret = secret, GetEnv = _ => null }).ActivateAsync(api, CancellationToken.None);
|
|
Assert.Empty(api.Tools);
|
|
var entry = Assert.Single(logger.Entries);
|
|
Assert.Equal(LogLevel.Warning, entry.Level);
|
|
Assert.Contains(missing, entry.Message);
|
|
Assert.DoesNotContain("csecret", entry.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void Configured_it_registers_the_calendar_tool_and_three_commands()
|
|
{
|
|
using var h = new ConnectHarness();
|
|
Assert.Equal("calendar", Assert.Single(h.Api.Tools).Name);
|
|
Assert.Equal(["calendar_connect", "calendar_disconnect", "calendar_status"], h.Api.Commands.Keys.Order().ToArray());
|
|
Assert.All(h.Api.Commands.Values, c => Assert.NotNull(c.Description));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task After_session_start_the_description_names_the_resolved_zone()
|
|
{
|
|
using var h = new ConnectHarness();
|
|
var tool = Assert.Single(h.Api.Tools);
|
|
Assert.Contains("the zone named in each result's header", tool.Description);
|
|
|
|
await h.Api.RaiseAsync(new SessionStartEvent(SessionStartReason.Startup), h.Context(null));
|
|
Assert.Contains("without an offset are in Europe/Berlin", tool.Description);
|
|
|
|
h.Connection().Store.Write(new StoredToken("rt-1", TimeZone: "America/New_York"));
|
|
Assert.Contains("without an offset are in America/New_York", Assert.Single(tool.PromptGuidelines));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task An_unknown_stored_zone_read_first_by_the_description_is_still_logged_exactly_once()
|
|
{
|
|
var logger = new ListLogger();
|
|
using var h = new ConnectHarness(logger);
|
|
var tool = Assert.Single(h.Api.Tools);
|
|
await h.Api.RaiseAsync(new SessionStartEvent(SessionStartReason.Startup), h.Context(null));
|
|
h.Connection().Store.Write(new StoredToken("rt-1", TimeZone: "Mars/Olympus_Mons"));
|
|
|
|
Assert.Contains("without an offset are in Europe/Berlin", tool.Description); // read before any tool call
|
|
_ = tool.PromptGuidelines;
|
|
h.Connection().ResolveTimeZone(ConnectHarness.Berlin, logger); // what the tool's execution does
|
|
|
|
var entry = Assert.Single(logger.Entries, e => e.Level == LogLevel.Warning);
|
|
Assert.Contains("Mars/Olympus_Mons", entry.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void A_logger_less_zone_lookup_does_not_use_up_the_log_once_flag()
|
|
{
|
|
using var h = new ConnectHarness();
|
|
var connection = h.Connection();
|
|
connection.Store.Write(new StoredToken("rt-1", TimeZone: "Mars/Olympus_Mons"));
|
|
connection.ResolveTimeZone(ConnectHarness.Berlin); // no logger
|
|
var logger = new ListLogger();
|
|
connection.ResolveTimeZone(ConnectHarness.Berlin, logger);
|
|
connection.ResolveTimeZone(ConnectHarness.Berlin, logger);
|
|
Assert.Single(logger.Entries);
|
|
}
|
|
}
|