142 lines
5.2 KiB
C#
142 lines
5.2 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using GmRelay.DiscordBot.Features.Sessions;
|
|
using NetCord.Services.ApplicationCommands;
|
|
|
|
namespace GmRelay.Bot.Tests.Discord;
|
|
|
|
public sealed class DiscordStartupTests
|
|
{
|
|
private static string GetRepoRoot()
|
|
{
|
|
var dir = AppContext.BaseDirectory;
|
|
while (!string.IsNullOrEmpty(dir) && !File.Exists(Path.Combine(dir, "Directory.Build.props")))
|
|
{
|
|
dir = Directory.GetParent(dir)?.FullName;
|
|
}
|
|
|
|
return dir ?? throw new InvalidOperationException("Could not find repo root");
|
|
}
|
|
|
|
[Fact]
|
|
public void Program_ShouldValidateDiscordTokenBeforeRunning()
|
|
{
|
|
var program = ReadProgram();
|
|
|
|
Assert.Contains("GetRequiredSection(\"Discord\")", program);
|
|
Assert.Contains("DiscordOptions", program);
|
|
Assert.Contains(".Validate()", program);
|
|
}
|
|
|
|
[Fact]
|
|
public void Program_ShouldRegisterServiceDefaultsAndPostgresDataSource()
|
|
{
|
|
var program = ReadProgram();
|
|
|
|
Assert.Contains("builder.AddServiceDefaults()", program);
|
|
Assert.Contains("ConnectionStrings:gmrelaydb is required", program);
|
|
Assert.Contains("NpgsqlDataSource", program);
|
|
Assert.Contains("SecretRedactor.RedactConnectionString", program);
|
|
}
|
|
|
|
[Fact]
|
|
public void Program_ShouldRegisterNetCordGatewayApplicationCommandsAndComponents()
|
|
{
|
|
var program = ReadProgram();
|
|
|
|
Assert.Contains(".AddDiscordGateway", program);
|
|
Assert.Contains(".AddApplicationCommands", program);
|
|
Assert.Contains(".AddComponentInteractions", program);
|
|
Assert.Contains(".AddGatewayHandlers", program);
|
|
Assert.Contains("AddSlashCommand", program);
|
|
Assert.Contains("AddModules(typeof(Program).Assembly)", program);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(typeof(DiscordNewSessionCommand), "newsession")]
|
|
[InlineData(typeof(DiscordListSessionsCommand), "listsessions")]
|
|
[InlineData(typeof(DiscordRescheduleCommand), "reschedule")]
|
|
public void DiscordSessionSlashCommands_ShouldBeDeclaredOnModuleMethods(Type moduleType, string commandName)
|
|
{
|
|
var executeMethod = moduleType.GetMethod("ExecuteAsync", BindingFlags.Instance | BindingFlags.Public);
|
|
|
|
Assert.NotNull(executeMethod);
|
|
|
|
var methodAttribute = Assert.Single(executeMethod.GetCustomAttributes<SlashCommandAttribute>(inherit: false));
|
|
var nameProperty = typeof(SlashCommandAttribute).GetProperty("Name")
|
|
?? throw new InvalidOperationException("SlashCommandAttribute should expose command name.");
|
|
|
|
Assert.Equal(commandName, nameProperty.GetValue(methodAttribute));
|
|
Assert.Empty(moduleType.GetCustomAttributes<SlashCommandAttribute>(inherit: false));
|
|
}
|
|
|
|
[Fact]
|
|
public void DiscordSessionSlashCommands_ShouldBeDiscoverableByNetCordService()
|
|
{
|
|
var service = new ApplicationCommandService<SlashCommandContext>();
|
|
|
|
service.AddModules(typeof(DiscordNewSessionCommand).Assembly);
|
|
|
|
var commandNames = service.GetCommands()
|
|
.Select(command => command.Name)
|
|
.ToArray();
|
|
|
|
Assert.Contains("newsession", commandNames);
|
|
Assert.Contains("listsessions", commandNames);
|
|
Assert.Contains("reschedule", commandNames);
|
|
}
|
|
|
|
[Fact]
|
|
public void LifecycleLogger_ShouldLogGatewayLifecycleEventsWithoutTokenValues()
|
|
{
|
|
var repoRoot = GetRepoRoot();
|
|
var loggerPath = Path.Combine(
|
|
repoRoot,
|
|
"src",
|
|
"GmRelay.DiscordBot",
|
|
"Infrastructure",
|
|
"Logging",
|
|
"DiscordGatewayLifecycleLogger.cs");
|
|
|
|
Assert.True(File.Exists(loggerPath), "Discord gateway lifecycle logger should exist.");
|
|
|
|
var logger = File.ReadAllText(loggerPath);
|
|
Assert.Contains("IReadyGatewayHandler", logger);
|
|
Assert.Contains("IDisconnectGatewayHandler", logger);
|
|
Assert.Contains("IResumeGatewayHandler", logger);
|
|
Assert.Contains("LogInformation", logger);
|
|
Assert.DoesNotContain("Token", logger);
|
|
}
|
|
|
|
[Fact]
|
|
public void Program_ShouldRegisterDiscordSessionHandlers()
|
|
{
|
|
var program = ReadProgram();
|
|
Assert.Contains("DiscordListSessionsHandler", program);
|
|
Assert.Contains("DiscordNewSessionHandler", program);
|
|
Assert.Contains("JoinSessionHandler", program);
|
|
Assert.Contains("LeaveSessionHandler", program);
|
|
Assert.Contains("DiscordPermissionChecker", program);
|
|
Assert.Contains("DiscordPlatformMessenger", program);
|
|
Assert.Contains("IPlatformMessenger", program);
|
|
Assert.Contains("PlatformSchedulerOptions(PlatformKind.Discord)", program);
|
|
Assert.Contains("AddHostedService<SessionSchedulerService>", program);
|
|
Assert.Contains("HandleRsvpHandler", program);
|
|
}
|
|
|
|
[Fact]
|
|
public void Program_ShouldRegisterDiscordHealthCheckHostedService()
|
|
{
|
|
var program = ReadProgram();
|
|
Assert.Contains("DiscordHealthCheckHostedService", program);
|
|
Assert.Contains("AddHostedService<DiscordHealthCheckHostedService>", program);
|
|
}
|
|
|
|
private static string ReadProgram()
|
|
{
|
|
var repoRoot = GetRepoRoot();
|
|
return File.ReadAllText(Path.Combine(repoRoot, "src", "GmRelay.DiscordBot", "Program.cs"));
|
|
}
|
|
}
|