Files
Playa/tests/Volcanic.AgenticCore.Extensions.Tests/GoogleCalendar/GoogleCalendarExtensionTests.cs
EugeneTes 881e7f0be9 fix(google-calendar): address review findings
- 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_*
2026-09-26 20:30:56 +02:00

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);
}
}