using EphemeralMongo; using Microsoft.Extensions.Logging.Abstractions; using MongoDB.Driver; using Notesnook.API.Accessors; using Notesnook.API.Models; using Notesnook.API.Services; using Streetwriters.Data; using Streetwriters.Data.DbContexts; using Streetwriters.Data.Repositories; namespace Notesnook.API.Tests; /// /// A throwaway database on an ephemeral single-node MongoDB replica set /// (transactions don't work on a standalone server). /// public sealed class TestDatabase : IAsyncLifetime { // one mongod for the whole test run, stopped when the test process exits private static readonly Lazy Runner = new(() => { var runner = MongoRunner.Run(new MongoRunnerOptions { UseSingleNodeReplicaSet = true, Version = MongoVersion.V8 }); AppDomain.CurrentDomain.ProcessExit += (_, _) => runner.Dispose(); return runner; }); public IMongoClient Client { get; } public string Name { get; } = "notesnook_test_" + Guid.NewGuid().ToString("N"); public TestDatabase() { Client = MongoDbContext.CreateMongoDbClient(new TestDbSettings { ConnectionString = Runner.Value.ConnectionString }); } public IMongoCollection Collection(string name) => MongoDbContext.GetMongoCollection(Client, Name, name); /// /// The services of a single request scope, wired the same way as in Startup. /// public Scope CreateScope() => new(this); public async Task InitializeAsync() { // collections can't be created implicitly inside a transaction on older servers foreach (var name in new[] { Collections.NotesKey, Collections.SyncDevicesKey, Collections.DeviceIdsChunksKey }) await Client.GetDatabase(Name).CreateCollectionAsync(name); } public Task DisposeAsync() => Client.DropDatabaseAsync(Name); public sealed class Scope { public MongoDbContext DbContext { get; } public UnitOfWork Unit { get; } public SyncItemsRepositoryAccessor Repositories { get; } public SyncDeviceService Devices { get; } public Scope(TestDatabase db) { DbContext = new MongoDbContext(db.Client); Unit = new UnitOfWork(DbContext); IMongoCollection items(string name) => db.Collection(name); Repositories = new SyncItemsRepositoryAccessor(DbContext, items(Collections.NotebooksKey), items(Collections.NotesKey), items(Collections.ContentKey), items(Collections.SettingsKey), items(Collections.LegacySettingsKey), items(Collections.AttachmentsKey), items(Collections.ShortcutsKey), items(Collections.RemindersKey), items(Collections.RelationsKey), items(Collections.ColorsKey), items(Collections.VaultsKey), items(Collections.TagsKey), items(Collections.InboxItemsHistoryKey), new Repository(DbContext, db.Collection("user_settings")), new Repository(DbContext, db.Collection("monographs")), new Repository(DbContext, db.Collection(Collections.InboxApiKeysKey)), new Repository(DbContext, db.Collection(Collections.InboxItemsKey)), new Repository(DbContext, db.Collection(Collections.SyncDevicesKey)), new Repository(DbContext, db.Collection(Collections.DeviceIdsChunksKey)), NullLogger.Instance); Devices = new SyncDeviceService(Repositories, DbContext, NullLogger.Instance); } } private sealed class TestDbSettings : Streetwriters.Data.Interfaces.IDbSettings { public string DatabaseName { get; set; } = ""; public string ConnectionString { get; set; } = ""; } }