1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 18:27:26 +08:00

Merge pull request #15753 from peppy/osu-test-scene-isolation-clean-up

Restructure how the headless storage is used / documented to hopefully make more sense
This commit is contained in:
Dan Balasescu 2021-11-23 16:29:39 +09:00 committed by GitHub
commit b7510697c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -43,13 +43,6 @@ namespace osu.Game.Tests.Visual
protected new OsuScreenDependencies Dependencies { get; private set; } protected new OsuScreenDependencies Dependencies { get; private set; }
private DrawableRulesetDependencies rulesetDependencies;
private Lazy<Storage> localStorage;
protected Storage LocalStorage => localStorage.Value;
private Lazy<DatabaseContextFactory> contextFactory;
protected IResourceStore<byte[]> Resources; protected IResourceStore<byte[]> Resources;
protected IAPIProvider API protected IAPIProvider API
@ -65,8 +58,6 @@ namespace osu.Game.Tests.Visual
private DummyAPIAccess dummyAPI; private DummyAPIAccess dummyAPI;
protected DatabaseContextFactory ContextFactory => contextFactory.Value;
/// <summary> /// <summary>
/// Whether this test scene requires real-world API access. /// Whether this test scene requires real-world API access.
/// If true, this will bypass the local <see cref="DummyAPIAccess"/> and use the <see cref="OsuGameBase"/> provided one. /// If true, this will bypass the local <see cref="DummyAPIAccess"/> and use the <see cref="OsuGameBase"/> provided one.
@ -74,15 +65,42 @@ namespace osu.Game.Tests.Visual
protected virtual bool UseOnlineAPI => false; protected virtual bool UseOnlineAPI => false;
/// <summary> /// <summary>
/// When running headless, there is an opportunity to use the host storage rather than creating a second isolated one. /// A database context factory to be used by test runs. Can be isolated and reset by setting <see cref="UseFreshStoragePerRun"/> to <c>true</c>.
/// This is because the host is recycled per TestScene execution in headless at an nunit level.
/// </summary> /// </summary>
private Storage isolatedHostStorage; /// <remarks>
/// In interactive runs (ie. VisualTests) this will use the user's database if <see cref="UseFreshStoragePerRun"/> is not set to <c>true</c>.
/// </remarks>
protected DatabaseContextFactory ContextFactory => contextFactory.Value;
private Lazy<DatabaseContextFactory> contextFactory;
/// <summary>
/// Whether a fresh storage should be initialised per test (method) run.
/// </summary>
/// <remarks>
/// By default (ie. if not set to <c>true</c>):
/// - in interactive runs, the user's storage will be used
/// - in headless runs, a shared temporary storage will be used per test class.
/// </remarks>
protected virtual bool UseFreshStoragePerRun => false;
/// <summary>
/// A storage to be used by test runs. Can be isolated by setting <see cref="UseFreshStoragePerRun"/> to <c>true</c>.
/// </summary>
/// <remarks>
/// In interactive runs (ie. VisualTests) this will use the user's storage if <see cref="UseFreshStoragePerRun"/> is not set to <c>true</c>.
/// </remarks>
protected Storage LocalStorage => localStorage.Value;
private Lazy<Storage> localStorage;
private Storage headlessHostStorage;
private DrawableRulesetDependencies rulesetDependencies;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
if (!UseFreshStoragePerRun) headlessHostStorage = (parent.Get<GameHost>() as HeadlessGameHost)?.Storage;
isolatedHostStorage = (parent.Get<GameHost>() as HeadlessGameHost)?.Storage;
Resources = parent.Get<OsuGameBase>().Resources; Resources = parent.Get<OsuGameBase>().Resources;
@ -90,11 +108,6 @@ namespace osu.Game.Tests.Visual
{ {
var factory = new DatabaseContextFactory(LocalStorage); var factory = new DatabaseContextFactory(LocalStorage);
// only reset the database if not using the host storage.
// if we reset the host storage, it will delete global key bindings.
if (isolatedHostStorage == null)
factory.ResetDatabase();
using (var usage = factory.Get()) using (var usage = factory.Get())
usage.Migrate(); usage.Migrate();
return factory; return factory;
@ -138,8 +151,6 @@ namespace osu.Game.Tests.Visual
base.Content.Add(content = new DrawSizePreservingFillContainer()); base.Content.Add(content = new DrawSizePreservingFillContainer());
} }
protected virtual bool UseFreshStoragePerRun => false;
public virtual void RecycleLocalStorage(bool isDisposing) public virtual void RecycleLocalStorage(bool isDisposing)
{ {
if (localStorage?.IsValueCreated == true) if (localStorage?.IsValueCreated == true)
@ -154,8 +165,16 @@ namespace osu.Game.Tests.Visual
} }
} }
localStorage = localStorage = new Lazy<Storage>(() =>
new Lazy<Storage>(() => isolatedHostStorage ?? new TemporaryNativeStorage($"{GetType().Name}-{Guid.NewGuid()}")); {
// When running headless, there is an opportunity to use the host storage rather than creating a second isolated one.
// This is because the host is recycled per TestScene execution in headless at an nunit level.
// Importantly, we can't use this optimisation when `UseFreshStoragePerRun` is true, as it doesn't reset per test method.
if (!UseFreshStoragePerRun && headlessHostStorage != null)
return headlessHostStorage;
return new TemporaryNativeStorage($"{GetType().Name}-{Guid.NewGuid()}");
});
} }
[Resolved] [Resolved]