014b5edd31
PR Checks / test-and-build (pull_request) Successful in 15m52s
Add format and location steps to the Telegram /newsession wizard, persist offline addresses in sessions.location_address, and render online links/offline addresses in schedule messages. Bump version to 3.10.0.
148 lines
5.4 KiB
C#
148 lines
5.4 KiB
C#
using GmRelay.Shared.Domain;
|
|
using GmRelay.Shared.Features.Sessions.CreateSession;
|
|
using GmRelay.Shared.Platform;
|
|
using Npgsql;
|
|
using Testcontainers.PostgreSql;
|
|
|
|
namespace GmRelay.Bot.Tests.Features.Sessions.CreateSession;
|
|
|
|
[CollectionDefinition(Name)]
|
|
public sealed class CreateSessionHandlerPostgresCollection : ICollectionFixture<CreateSessionHandlerPostgresFixture>
|
|
{
|
|
public const string Name = "Create session handler PostgreSQL";
|
|
}
|
|
|
|
public sealed class CreateSessionHandlerPostgresFixture : IAsyncLifetime
|
|
{
|
|
private static readonly TimeSpan ContainerTimeout = TimeSpan.FromMinutes(2);
|
|
private readonly PostgreSqlContainer container = new PostgreSqlBuilder("postgres:17-alpine").Build();
|
|
|
|
public Task InitializeAsync()
|
|
{
|
|
return container.StartAsync().WaitAsync(ContainerTimeout);
|
|
}
|
|
|
|
public Task DisposeAsync()
|
|
{
|
|
return container.DisposeAsync().AsTask().WaitAsync(ContainerTimeout);
|
|
}
|
|
|
|
public async Task<string> CreateMigratedDatabaseAsync()
|
|
{
|
|
var databaseName = $"create_session_{Guid.NewGuid():N}";
|
|
|
|
await using (var adminConnection = new NpgsqlConnection(container.GetConnectionString()))
|
|
{
|
|
await adminConnection.OpenAsync().WaitAsync(ContainerTimeout);
|
|
await using var createDatabase = new NpgsqlCommand($"CREATE DATABASE \"{databaseName}\"", adminConnection);
|
|
await createDatabase.ExecuteNonQueryAsync().WaitAsync(ContainerTimeout);
|
|
}
|
|
|
|
var connectionString = new NpgsqlConnectionStringBuilder(container.GetConnectionString())
|
|
{
|
|
Database = databaseName,
|
|
Timeout = 10,
|
|
CommandTimeout = 30
|
|
}.ConnectionString;
|
|
|
|
await using var connection = new NpgsqlConnection(connectionString);
|
|
await connection.OpenAsync().WaitAsync(ContainerTimeout);
|
|
|
|
foreach (var migration in GetMigrationPaths())
|
|
{
|
|
await using var command = new NpgsqlCommand(await File.ReadAllTextAsync(migration), connection)
|
|
{
|
|
CommandTimeout = 30
|
|
};
|
|
await command.ExecuteNonQueryAsync().WaitAsync(ContainerTimeout);
|
|
}
|
|
|
|
return connectionString;
|
|
}
|
|
|
|
private static IReadOnlyList<string> GetMigrationPaths()
|
|
{
|
|
var directory = new DirectoryInfo(AppContext.BaseDirectory);
|
|
while (directory is not null)
|
|
{
|
|
var migrationsDirectory = Path.Combine(directory.FullName, "src", "GmRelay.Bot", "Migrations");
|
|
if (Directory.Exists(migrationsDirectory))
|
|
{
|
|
return Directory.GetFiles(migrationsDirectory, "V*.sql")
|
|
.OrderBy(path => Path.GetFileName(path), StringComparer.Ordinal)
|
|
.ToArray();
|
|
}
|
|
|
|
directory = directory.Parent;
|
|
}
|
|
|
|
throw new DirectoryNotFoundException("Could not locate the bot migrations directory.");
|
|
}
|
|
}
|
|
|
|
[Collection(CreateSessionHandlerPostgresCollection.Name)]
|
|
public sealed class CreateSessionHandlerIntegrationTests(CreateSessionHandlerPostgresFixture fixture)
|
|
{
|
|
[Fact]
|
|
public async Task HandleAsync_NewPlatformGroup_AddsOwnerAndPersistsSession()
|
|
{
|
|
var connectionString = await fixture.CreateMigratedDatabaseAsync();
|
|
await using var dataSource = NpgsqlDataSource.Create(connectionString);
|
|
var sut = new CreateSessionHandler(dataSource);
|
|
|
|
var result = await sut.HandleAsync(
|
|
new CreateSessionCommand(
|
|
new PlatformUser(PlatformKind.Telegram, "111111111", "Test GM", "test_gm"),
|
|
new PlatformGroup(PlatformKind.Telegram, "222222222", "Test Group"),
|
|
"Test Adventure",
|
|
"https://vtt.example/game",
|
|
[DateTimeOffset.UtcNow.AddDays(1)],
|
|
null,
|
|
null,
|
|
GameSystem.Dnd5e,
|
|
"Integration regression test",
|
|
"Online",
|
|
240,
|
|
true,
|
|
"Online room notes"),
|
|
CancellationToken.None);
|
|
|
|
Assert.True(result.Success, result.ErrorMessage);
|
|
Assert.NotNull(result.BatchId);
|
|
Assert.NotNull(result.GroupId);
|
|
|
|
await using var connection = await dataSource.OpenConnectionAsync();
|
|
await using var command = new NpgsqlCommand(
|
|
"""
|
|
SELECT count(*)
|
|
FROM group_managers gm
|
|
JOIN players p ON p.id = gm.player_id
|
|
WHERE gm.group_id = @group_id
|
|
AND gm.role = 'Owner'
|
|
AND p.platform = 'Telegram'
|
|
AND p.external_user_id = '111111111'
|
|
""",
|
|
connection);
|
|
command.Parameters.AddWithValue("group_id", result.GroupId.Value);
|
|
|
|
var ownerCount = (long)(await command.ExecuteScalarAsync() ?? 0L);
|
|
Assert.Equal(1, ownerCount);
|
|
|
|
await using var sessionCommand = new NpgsqlCommand(
|
|
"""
|
|
SELECT join_link, format, location_address
|
|
FROM sessions
|
|
WHERE batch_id = @batch_id
|
|
""",
|
|
connection);
|
|
sessionCommand.Parameters.AddWithValue("batch_id", result.BatchId.Value);
|
|
|
|
await using var reader = await sessionCommand.ExecuteReaderAsync();
|
|
Assert.True(await reader.ReadAsync());
|
|
Assert.Equal("https://vtt.example/game", reader.GetString(0));
|
|
Assert.Equal("Online", reader.GetString(1));
|
|
Assert.Equal("Online room notes", reader.GetString(2));
|
|
Assert.False(await reader.ReadAsync());
|
|
}
|
|
}
|