Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ObserveAll tests and benchmarks #89

Merged
merged 6 commits into from
Aug 15, 2024
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
@@ -0,0 +1,57 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Engines;
using NexusMods.MnemonicDB.Abstractions.TxFunctions;
using NexusMods.MnemonicDB.TestModel;

namespace NexusMods.MnemonicDB.Benchmarks.Benchmarks;

[MemoryDiagnoser]
[SimpleJob(runStrategy: RunStrategy.Monitoring, warmupCount: 1)]
public class ObserveAllBenchmarks : ABenchmark
{
private string[] _names = [];

[Params(100, 1_000, 10_000)]
public int N { get; set; }

[GlobalSetup]
public async ValueTask GlobalSetup()
{
await InitializeAsync();
_names = Enumerable.Range(start: 0, count: N).Select(i => $"Loadout {i}").ToArray();
}

[IterationCleanup]
public void IterationCleanup()
{
using var tx = Connection.BeginTransaction();

foreach (var entity in Loadout.All(Connection.Db))
{
tx.Delete(entity, recursive: false);
}

tx.Commit().GetAwaiter().GetResult();
}

[Benchmark]
public async ValueTask ObserveAll()
{
using var disposable = Loadout.ObserveAll(Connection).Subscribe(_ => { });

using var tx = Connection.BeginTransaction();

foreach (var name in _names)
{
_ = new Loadout.New(tx)
{
Name = name,
};
}

await tx.Commit();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
+ | 0200000000000001 | (0015) Hash | 0x00000000DEADBEEF | 0100000000000002
+ | 0200000000000003 | (0018) Name | Test Mod 1 | 0100000000000002
+ | 0200000000000005 | (0018) Name | Test Mod 2 | 0100000000000002
+ | 0200000000000004 | (001A) Name | Test Loadout 1 | 0100000000000002
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
+ | 0200000000000001 | (0015) Hash | 0x00000000DEADBEEF | 0100000000000002
+ | 0200000000000003 | (0018) Name | Test Mod 1 | 0100000000000002
+ | 0200000000000005 | (0018) Name | Test Mod 2 | 0100000000000002
+ | 0200000000000004 | (001A) Name | Test Loadout 1 | 0100000000000002
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
+ | 0200000000000001 | (0015) Hash | 0x00000000DEADBEEF | 0100000000000002
+ | 0200000000000003 | (0018) Name | Test Mod 1 | 0100000000000002
+ | 0200000000000005 | (0018) Name | Test Mod 2 | 0100000000000002
+ | 0200000000000004 | (001A) Name | Test Loadout 1 | 0100000000000002
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
+ | 0200000000000001 | (0015) Hash | 0x00000000DEADBEEF | 0100000000000002
+ | 0200000000000003 | (0018) Name | Test Mod 1 | 0100000000000002
+ | 0200000000000005 | (0018) Name | Test Mod 2 | 0100000000000002
+ | 0200000000000004 | (001A) Name | Test Loadout 1 | 0100000000000002
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
+ | 0200000000000001 | (0015) Hash | 0x00000000DEADBEEF | 0100000000000002
+ | 0200000000000003 | (0018) Name | Test Mod 1 | 0100000000000002
+ | 0200000000000005 | (0018) Name | Test Mod 2 | 0100000000000002
+ | 0200000000000004 | (001A) Name | Test Loadout 1 | 0100000000000002
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
+ | 0200000000000001 | (0015) Hash | 0x00000000DEADBEEF | 0100000000000002
+ | 0200000000000003 | (0018) Name | Test Mod 1 | 0100000000000002
+ | 0200000000000005 | (0018) Name | Test Mod 2 | 0100000000000002
+ | 0200000000000004 | (001A) Name | Test Loadout 1 | 0100000000000002
5 changes: 2 additions & 3 deletions tests/NexusMods.MnemonicDB.TestModel/Loadout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ namespace NexusMods.MnemonicDB.TestModel;
public partial class Loadout : IModelDefinition
{
private const string Namespace = "NexusMods.MnemonicDB.TestModel.Loadout";
public static readonly StringAttribute Name = new(Namespace, nameof(Name));
public static readonly StringAttribute Name = new(Namespace, nameof(Name)) { IsIndexed = true };
public static readonly BackReferenceAttribute<Mod> Mods = new(Mod.Loadout);
public static readonly BackReferenceAttribute<Collection> Collections = new(Collection.Loadout);
public static readonly AbsolutePathAttribute GamePath = new(Namespace, nameof(GamePath))
{ IsOptional = true };
public static readonly AbsolutePathAttribute GamePath = new(Namespace, nameof(GamePath)) { IsOptional = true };
}
97 changes: 97 additions & 0 deletions tests/NexusMods.MnemonicDB.Tests/ObservableTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using DynamicData;
using NexusMods.MnemonicDB.Abstractions.TxFunctions;
using NexusMods.MnemonicDB.TestModel;

namespace NexusMods.MnemonicDB.Tests;

public class ObservableTests : AMnemonicDBTest
{
public ObservableTests(IServiceProvider provider) : base(provider) { }

[Fact]
public async Task TestObserveAll()
{
using var disposable = Loadout
.ObserveAll(Connection)
.Transform(loadout => loadout.Name)
.Bind(out var list)
.Subscribe();

list.Should().BeEmpty();

await Add("Loadout 1");

list.Should().ContainSingle(static name => name.Equals("Loadout 1"));

await Add("Loadout 2");

list.Should().HaveCount(2).And.ContainInOrder(["Loadout 1", "Loadout 2"]);

await Add("Loadout 3", "Loadout 4");

list.Should().HaveCount(4).And.ContainInOrder(["Loadout 1", "Loadout 2", "Loadout 3", "Loadout 4"]);

await Delete("Loadout 2");

list.Should().HaveCount(3).And.ContainInOrder(["Loadout 1", "Loadout 3", "Loadout 4"]);

await Delete("Loadout 1", "Loadout 4");

list.Should().ContainSingle(static name => name.Equals("Loadout 3"));

await Delete("Loadout 3");

list.Should().BeEmpty();
}

[Fact]
public async Task StressTest()
{
using var disposable = Loadout
.ObserveAll(Connection)
.Transform(loadout => loadout.Name)
.Bind(out var list)
.Subscribe();

var stress = Enumerable.Range(start: 0, count: 100).Select(i => $"Loadout {i}").ToArray();
await Add(stress);

list.Should().ContainInOrder(stress);

await Delete(stress);

list.Should().BeEmpty();
}

private async ValueTask Add(params string[] names)
{
using var tx = Connection.BeginTransaction();

foreach (var name in names)
{
_ = new Loadout.New(tx)
{
Name = name,
};
}


await tx.Commit();
}

private async ValueTask Delete(params string[] names)
{
var db = Connection.Db;
using var tx = Connection.BeginTransaction();

foreach (var name in names)
{
var entities = Loadout.FindByName(db, name);
entities.Should().ContainSingle();

tx.Delete(entities.First(), recursive: false);
}

await tx.Commit();
}
}
Loading