Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
using Microsoft.Extensions.Options;
using SimpleModule.Database;
using SimpleModule.FileStorage.Contracts;
using SimpleModule.Tests.Shared.Storage;

namespace SimpleModule.FileStorage.Tests;

public sealed class FileStorageServiceTests : IDisposable
{
private readonly FileStorageDbContext _db;
private readonly InMemoryStorageProvider _storageProvider;
private readonly InMemoryStorage _storageProvider;
private readonly FileStorageService _service;

public FileStorageServiceTests()
Expand All @@ -32,7 +33,7 @@ public FileStorageServiceTests()
_db.Database.OpenConnection();
_db.Database.EnsureCreated();

_storageProvider = new InMemoryStorageProvider();
_storageProvider = new InMemoryStorage();
_service = new FileStorageService(
_db,
_storageProvider,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System.Text.Json;
using SimpleModule.BackgroundJobs.Contracts;

namespace SimpleModule.Tests.Shared.BackgroundJobs;

/// <summary>
/// Test fake for <see cref="IJobExecutionContext"/>. Captures progress reports
/// and log messages in-memory so tests can assert on what a job did without
/// wiring up a <c>ProgressChannel</c> or the real <c>DefaultJobExecutionContext</c>.
/// </summary>
public sealed class FakeJobExecutionContext : IJobExecutionContext
{
private readonly string? _serializedData;
private readonly List<ProgressReport> _progressReports = [];
private readonly List<string> _logMessages = [];

public FakeJobExecutionContext(JobId jobId, string? serializedData = null)
{
JobId = jobId;
_serializedData = serializedData;
}

public FakeJobExecutionContext(JobId jobId, object data)
: this(jobId, JsonSerializer.Serialize(data)) { }

public FakeJobExecutionContext()
: this(JobId.From(Guid.NewGuid()), serializedData: null) { }

public JobId JobId { get; }

public IReadOnlyList<ProgressReport> ProgressReports => _progressReports;

public IReadOnlyList<string> LogMessages => _logMessages;

public T GetData<T>()
{
if (string.IsNullOrEmpty(_serializedData))
{
throw new InvalidOperationException("No data was provided for this job.");
}

return JsonSerializer.Deserialize<T>(_serializedData)
?? throw new InvalidOperationException(
$"Failed to deserialize job data as {typeof(T).Name}."
);
}

public void ReportProgress(int percentage, string? message = null) =>
_progressReports.Add(new ProgressReport(percentage, message));

public void Log(string message) => _logMessages.Add(message);

public readonly record struct ProgressReport(int Percentage, string? Message);
}
57 changes: 57 additions & 0 deletions tests/SimpleModule.Tests.Shared/Datasets/TestDatasetsDbContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using SimpleModule.Database;
using SimpleModule.Datasets;

namespace SimpleModule.Tests.Shared.Datasets;

/// <summary>
/// Test subclass of <see cref="DatasetsDbContext"/> backed by a private
/// in-memory SQLite connection. Use the static <see cref="Create"/> factory
/// to obtain a ready-to-use, self-owning context; disposing the context
/// closes the underlying connection.
/// </summary>
public sealed class TestDatasetsDbContext : DatasetsDbContext
{
private readonly SqliteConnection _connection;

private TestDatasetsDbContext(
DbContextOptions<DatasetsDbContext> options,
IOptions<DatabaseOptions> dbOptions,
SqliteConnection connection
)
: base(options, dbOptions)
{
_connection = connection;
}

/// <summary>
/// Creates a <see cref="TestDatasetsDbContext"/> with a fresh in-memory
/// SQLite database. Dispose the returned context to release the
/// connection.
/// </summary>
public static TestDatasetsDbContext Create()
{
var connection = new SqliteConnection("Data Source=:memory:");
connection.Open();

var options = new DbContextOptionsBuilder<DatasetsDbContext>()
.UseSqlite(connection)
.Options;

var dbOptions = Options.Create(
new DatabaseOptions { DefaultConnection = "Data Source=:memory:", Provider = "Sqlite" }
);

var context = new TestDatasetsDbContext(options, dbOptions, connection);
context.Database.EnsureCreated();
return context;
}

public override void Dispose()
{
base.Dispose();
_connection.Dispose();
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
using System.Collections.Concurrent;
using SimpleModule.Storage;

namespace SimpleModule.FileStorage.Tests;
namespace SimpleModule.Tests.Shared.Storage;

public sealed class InMemoryStorageProvider : IStorageProvider
/// <summary>
/// In-memory <see cref="IStorageProvider"/> for tests. Stores files in a
/// concurrent dictionary keyed by normalized path.
/// </summary>
public sealed class InMemoryStorage : IStorageProvider
{
private readonly ConcurrentDictionary<
string,
Expand Down
Loading