1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 10:12:54 +08:00

Merge pull request #15040 from peppy/realm-test-game-host

Update realm tests to run inside a `GameHost` to allow running on update thread
This commit is contained in:
Dan Balasescu 2021-10-12 21:16:06 +09:00 committed by GitHub
commit 7bb401b974
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 30 deletions

View File

@ -4,7 +4,6 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using Nito.AsyncEx;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Framework.Platform; using osu.Framework.Platform;
@ -28,42 +27,69 @@ namespace osu.Game.Tests.Database
protected void RunTestWithRealm(Action<RealmContextFactory, Storage> testAction, [CallerMemberName] string caller = "") protected void RunTestWithRealm(Action<RealmContextFactory, Storage> testAction, [CallerMemberName] string caller = "")
{ {
AsyncContext.Run(() => using (HeadlessGameHost host = new CleanRunHeadlessGameHost(caller))
{ {
var testStorage = storage.GetStorageForDirectory(caller); host.Run(new RealmTestGame(() =>
using (var realmFactory = new RealmContextFactory(testStorage, caller))
{ {
Logger.Log($"Running test using realm file {testStorage.GetFullPath(realmFactory.Filename)}"); var testStorage = storage.GetStorageForDirectory(caller);
testAction(realmFactory, testStorage);
realmFactory.Dispose(); using (var realmFactory = new RealmContextFactory(testStorage, caller))
{
Logger.Log($"Running test using realm file {testStorage.GetFullPath(realmFactory.Filename)}");
testAction(realmFactory, testStorage);
Logger.Log($"Final database size: {getFileSize(testStorage, realmFactory)}"); realmFactory.Dispose();
realmFactory.Compact();
Logger.Log($"Final database size after compact: {getFileSize(testStorage, realmFactory)}"); Logger.Log($"Final database size: {getFileSize(testStorage, realmFactory)}");
} realmFactory.Compact();
}); Logger.Log($"Final database size after compact: {getFileSize(testStorage, realmFactory)}");
}
}));
}
} }
protected void RunTestWithRealmAsync(Func<RealmContextFactory, Storage, Task> testAction, [CallerMemberName] string caller = "") protected void RunTestWithRealmAsync(Func<RealmContextFactory, Storage, Task> testAction, [CallerMemberName] string caller = "")
{ {
AsyncContext.Run(async () => using (HeadlessGameHost host = new CleanRunHeadlessGameHost(caller))
{ {
var testStorage = storage.GetStorageForDirectory(caller); host.Run(new RealmTestGame(async () =>
using (var realmFactory = new RealmContextFactory(testStorage, caller))
{ {
Logger.Log($"Running test using realm file {testStorage.GetFullPath(realmFactory.Filename)}"); var testStorage = storage.GetStorageForDirectory(caller);
await testAction(realmFactory, testStorage);
realmFactory.Dispose(); using (var realmFactory = new RealmContextFactory(testStorage, caller))
{
Logger.Log($"Running test using realm file {testStorage.GetFullPath(realmFactory.Filename)}");
await testAction(realmFactory, testStorage);
Logger.Log($"Final database size: {getFileSize(testStorage, realmFactory)}"); realmFactory.Dispose();
realmFactory.Compact();
Logger.Log($"Final database size after compact: {getFileSize(testStorage, realmFactory)}"); Logger.Log($"Final database size: {getFileSize(testStorage, realmFactory)}");
} realmFactory.Compact();
}); }
}));
}
}
private class RealmTestGame : Framework.Game
{
public RealmTestGame(Func<Task> work)
{
// ReSharper disable once AsyncVoidLambda
Scheduler.Add(async () =>
{
await work().ConfigureAwait(true);
Exit();
});
}
public RealmTestGame(Action work)
{
Scheduler.Add(() =>
{
work();
Exit();
});
}
} }
private static long getFileSize(Storage testStorage, RealmContextFactory realmFactory) private static long getFileSize(Storage testStorage, RealmContextFactory realmFactory)

View File

@ -135,9 +135,8 @@ namespace osu.Game.Database
if (IsDisposed) if (IsDisposed)
throw new ObjectDisposedException(nameof(RealmContextFactory)); throw new ObjectDisposedException(nameof(RealmContextFactory));
// TODO: this can be added for safety once we figure how to bypass in test if (!ThreadSafety.IsUpdateThread)
// if (!ThreadSafety.IsUpdateThread) throw new InvalidOperationException($"{nameof(BlockAllOperations)} must be called from the update thread.");
// throw new InvalidOperationException($"{nameof(BlockAllOperations)} must be called from the update thread.");
Logger.Log(@"Blocking realm operations.", LoggingTarget.Database); Logger.Log(@"Blocking realm operations.", LoggingTarget.Database);

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Bindables; using osu.Framework.Bindables;
@ -410,11 +411,28 @@ namespace osu.Game
{ {
Logger.Log($@"Migrating osu! data from ""{Storage.GetFullPath(string.Empty)}"" to ""{path}""..."); Logger.Log($@"Migrating osu! data from ""{Storage.GetFullPath(string.Empty)}"" to ""{path}""...");
using (realmFactory.BlockAllOperations()) IDisposable realmBlocker = null;
try
{ {
contextFactory.FlushConnections(); ManualResetEventSlim readyToRun = new ManualResetEventSlim();
Scheduler.Add(() =>
{
realmBlocker = realmFactory.BlockAllOperations();
contextFactory.FlushConnections();
readyToRun.Set();
}, false);
readyToRun.Wait();
(Storage as OsuStorage)?.Migrate(Host.GetStorage(path)); (Storage as OsuStorage)?.Migrate(Host.GetStorage(path));
} }
finally
{
realmBlocker?.Dispose();
}
Logger.Log(@"Migration complete!"); Logger.Log(@"Migration complete!");
} }