Ensure profile loading only returns valid species (#42842)

* Ensure profile loading only returns valid species

* punt conversion logic outside of the database
This commit is contained in:
pathetic meowmeow
2026-06-29 12:43:50 +02:00
committed by Coryler
parent 84bf9e4e87
commit 63fea071c5
6 changed files with 241 additions and 180 deletions
@@ -1,8 +1,11 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Content.Server.Database;
using Content.Server.Preferences.Managers;
using Content.Shared.GameTicking;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Preferences;
using Content.Shared.Preferences.Loadouts;
using Content.Shared.Preferences.Loadouts.Effects;
@@ -14,6 +17,7 @@ using Robust.Shared.Enums;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;
using Robust.UnitTesting;
@@ -58,13 +62,12 @@ namespace Content.IntegrationTests.Tests.Preferences
{
var cfg = server.ResolveDependency<IConfigurationManager>();
var serialization = server.ResolveDependency<ISerializationManager>();
var task = server.ResolveDependency<ITaskManager>();
var opsLog = server.ResolveDependency<ILogManager>().GetSawmill("db.ops");
var builder = new DbContextOptionsBuilder<SqliteServerDbContext>();
var conn = new SqliteConnection("Data Source=:memory:");
conn.Open();
builder.UseSqlite(conn);
return new ServerDbSqlite(() => builder.Options, true, cfg, true, opsLog, task, serialization);
return new ServerDbSqlite(() => builder.Options, true, cfg, true, opsLog, serialization);
}
[Test]
@@ -83,12 +86,14 @@ namespace Content.IntegrationTests.Tests.Preferences
{
var pair = await PoolManager.GetServerClient();
var db = GetDb(pair.Server);
var preferences = (ServerPreferencesManager)pair.Server.ResolveDependency<IServerPreferencesManager>();
var username = new NetUserId(new Guid("640bd619-fc8d-4fe2-bf3c-4a5fb17d6ddd"));
const int slot = 0;
var originalProfile = CharlieCharlieson();
await db.InitPrefsAsync(username, originalProfile);
var prefs = await db.GetPlayerPreferencesAsync(username);
Assert.That(prefs.Characters.Single(p => p.Key == slot).Value.MemberwiseEquals(originalProfile));
var profile = preferences.ConvertProfiles(prefs!.Profiles.Find(p => p.Slot == slot));
Assert.That(profile.MemberwiseEquals(originalProfile));
await pair.CleanReturnAsync();
}
@@ -104,7 +109,7 @@ namespace Content.IntegrationTests.Tests.Preferences
await db.SaveSelectedCharacterIndexAsync(username, 1);
await db.SaveCharacterSlotAsync(username, null, 1);
var prefs = await db.GetPlayerPreferencesAsync(username);
Assert.That(!prefs.Characters.Any(p => p.Key != 0));
Assert.That(prefs!.Profiles, Has.Count.EqualTo(1));
await pair.CleanReturnAsync();
}
@@ -123,5 +128,49 @@ namespace Content.IntegrationTests.Tests.Preferences
{
return new(Guid.NewGuid());
}
private const string InvalidSpecies = "WingusDingus";
private static bool[] _trueFalse = [true, false];
[Test]
[TestCaseSource(nameof(_trueFalse))]
public async Task InvalidSpeciesConversion(bool legacy)
{
var pair = await PoolManager.GetServerClient();
var server = pair.Server;
var db = GetDb(pair.Server);
var preferences = (ServerPreferencesManager)pair.Server.ResolveDependency<IServerPreferencesManager>();
var proto = server.ResolveDependency<IPrototypeManager>();
Assert.That(!proto.HasIndex<SpeciesPrototype>(InvalidSpecies), "You should not have added a species called WingusDingus, but change it in this test to something else I guess");
var bogus = new HumanoidCharacterProfile()
{
Species = InvalidSpecies,
};
var username = new NetUserId(new Guid("640bd619-fc8d-4fe2-bf3c-4a5fb17d6ddd"));
await db.InitPrefsAsync(username, new HumanoidCharacterProfile());
await db.SaveCharacterSlotAsync(username, bogus, 0);
await db.SaveSelectedCharacterIndexAsync(username, 0);
if (legacy)
await db.MakeCharacterSlotLegacyAsync(username, 0);
var prefs = await db.GetPlayerPreferencesAsync(username, CancellationToken.None);
Assert.That(prefs, Is.Not.Null);
await server.WaitAssertion(() =>
{
var converted = preferences.ConvertPreferences(prefs);
Assert.That(converted.Characters, Has.Count.EqualTo(1));
Assert.That(converted.Characters[0].Species, Is.Not.EqualTo(InvalidSpecies));
Assert.That(converted.Characters[0].Species, Is.EqualTo(HumanoidCharacterProfile.DefaultSpecies));
});
await pair.CleanReturnAsync();
}
}
}