From: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com> Date: Tue, 23 Dec 2025 09:10:36 +0000 (-0800) Subject: Fix DeltaPressureTest race condition when using LINDA (#41388) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=38d6b7a119c2e83389ba57c8d30df554bb1efa13;p=space-station-14.git Fix DeltaPressureTest race condition when using LINDA (#41388) --- diff --git a/Content.IntegrationTests/Tests/Atmos/DeltaPressureTest.cs b/Content.IntegrationTests/Tests/Atmos/DeltaPressureTest.cs index c3b3877c98..d4283568e8 100644 --- a/Content.IntegrationTests/Tests/Atmos/DeltaPressureTest.cs +++ b/Content.IntegrationTests/Tests/Atmos/DeltaPressureTest.cs @@ -1,15 +1,11 @@ -using System.Linq; using System.Numerics; using Content.Server.Atmos; using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; -using Robust.Shared.EntitySerialization; -using Robust.Shared.EntitySerialization.Systems; using Robust.Shared.GameObjects; using Robust.Shared.Map; -using Robust.Shared.Map.Components; using Robust.Shared.Utility; namespace Content.IntegrationTests.Tests.Atmos; @@ -20,7 +16,7 @@ namespace Content.IntegrationTests.Tests.Atmos; /// [TestFixture] [TestOf(typeof(DeltaPressureSystem))] -public sealed class DeltaPressureTest +public sealed class DeltaPressureTest : AtmosTest { #region Prototypes @@ -92,7 +88,7 @@ public sealed class DeltaPressureTest #endregion - private readonly ResPath _testMap = new("Maps/Test/Atmospherics/DeltaPressure/deltapressuretest.yml"); + protected override ResPath? TestMapPath => new("Maps/Test/Atmospherics/DeltaPressure/deltapressuretest.yml"); // TODO ATMOS TESTS // - Check for directional windows (partial airtight ents) properly computing pressure differences @@ -111,40 +107,15 @@ public sealed class DeltaPressureTest [Test] public async Task ProcessingListAutoJoinTest() { - await using var pair = await PoolManager.GetServerClient(); - var server = pair.Server; - - var entMan = server.EntMan; - var mapLoader = entMan.System(); - var atmosphereSystem = entMan.System(); - var deserializationOptions = DeserializationOptions.Default with { InitializeMaps = true }; - - Entity grid = default; - Entity dpEnt; - - // Load our test map in and assert that it exists. - await server.WaitPost(() => - { -#pragma warning disable NUnit2045 - Assert.That(mapLoader.TryLoadMap(_testMap, out _, out var gridSet, deserializationOptions), - $"Failed to load map {_testMap}."); - Assert.That(gridSet, Is.Not.Null, "There were no grids loaded from the map!"); -#pragma warning restore NUnit2045 - - grid = gridSet.First(); - }); - - await server.WaitAssertion(() => + await Server.WaitAssertion(() => { - var uid = entMan.SpawnAtPosition("DeltaPressureSolidTest", new EntityCoordinates(grid.Owner, Vector2.Zero)); - dpEnt = new Entity(uid, entMan.GetComponent(uid)); + var uid = SEntMan.SpawnAtPosition("DeltaPressureSolidTest", new EntityCoordinates(ProcessEnt, Vector2.Zero)); + var dpEnt = new Entity(uid, SEntMan.GetComponent(uid)); - Assert.That(atmosphereSystem.IsDeltaPressureEntityInList(grid.Owner, dpEnt), "Entity was not in processing list when it should have automatically joined!"); - entMan.DeleteEntity(uid); - Assert.That(!atmosphereSystem.IsDeltaPressureEntityInList(grid.Owner, dpEnt), "Entity was still in processing list after deletion!"); + Assert.That(SAtmos.IsDeltaPressureEntityInList(RelevantAtmos, dpEnt), "Entity was not in processing list when it should have automatically joined!"); + SEntMan.DeleteEntity(uid); + Assert.That(!SAtmos.IsDeltaPressureEntityInList(RelevantAtmos, dpEnt), "Entity was still in processing list after deletion!"); }); - - await pair.CleanReturnAsync(); } /// @@ -154,45 +125,27 @@ public sealed class DeltaPressureTest [Test] public async Task ProcessingDeltaStandbyTest() { - await using var pair = await PoolManager.GetServerClient(); - var server = pair.Server; - - var entMan = server.EntMan; - var mapLoader = entMan.System(); - var atmosphereSystem = entMan.System(); - var transformSystem = entMan.System(); - var deserializationOptions = DeserializationOptions.Default with { InitializeMaps = true }; - - Entity grid = default; Entity dpEnt = default; TileAtmosphere tile = null!; AtmosDirection direction = default; // Load our test map in and assert that it exists. - await server.WaitPost(() => + await Server.WaitPost(() => { -#pragma warning disable NUnit2045 - Assert.That(mapLoader.TryLoadMap(_testMap, out _, out var gridSet, deserializationOptions), - $"Failed to load map {_testMap}."); - Assert.That(gridSet, Is.Not.Null, "There were no grids loaded from the map!"); -#pragma warning restore NUnit2045 - - grid = gridSet.First(); - var uid = entMan.SpawnAtPosition("DeltaPressureSolidTest", new EntityCoordinates(grid.Owner, Vector2.Zero)); - dpEnt = new Entity(uid, entMan.GetComponent(uid)); - Assert.That(atmosphereSystem.IsDeltaPressureEntityInList(grid.Owner, dpEnt), "Entity was not in processing list when it should have been added!"); + var uid = SEntMan.SpawnAtPosition("DeltaPressureSolidTest", new EntityCoordinates(ProcessEnt, Vector2.Zero)); + dpEnt = new Entity(uid, SEntMan.GetComponent(uid)); + Assert.That(SAtmos.IsDeltaPressureEntityInList(ProcessEnt, dpEnt), "Entity was not in processing list when it should have been added!"); }); for (var i = 0; i < Atmospherics.Directions; i++) { - await server.WaitPost(() => + await Server.WaitPost(() => { - var indices = transformSystem.GetGridOrMapTilePosition(dpEnt); - var gridAtmosComp = entMan.GetComponent(grid); + var indices = Transform.GetGridOrMapTilePosition(dpEnt); direction = (AtmosDirection)(1 << i); var offsetIndices = indices.Offset(direction); - tile = gridAtmosComp.Tiles[offsetIndices]; + tile = RelevantAtmos.Comp.Tiles[offsetIndices]; Assert.That(tile.Air, Is.Not.Null, $"Tile at {offsetIndices} should have air!"); @@ -202,19 +155,17 @@ public sealed class DeltaPressureTest tile.Air!.AdjustMoles(Gas.Nitrogen, moles); }); - await server.WaitRunTicks(30); + await Server.WaitRunTicks(30); // Entity should exist, if it took one tick of damage then it should be instantly destroyed. - await server.WaitAssertion(() => + await Server.WaitAssertion(() => { - Assert.That(!entMan.Deleted(dpEnt), $"{dpEnt} should still exist after experiencing non-threshold pressure from {direction} side!"); + Assert.That(!SEntMan.Deleted(dpEnt), $"{dpEnt} should still exist after experiencing non-threshold pressure from {direction} side!"); tile.Air!.Clear(); }); - await server.WaitRunTicks(30); + await Server.WaitRunTicks(30); } - - await pair.CleanReturnAsync(); } /// @@ -224,47 +175,43 @@ public sealed class DeltaPressureTest [Test] public async Task ProcessingDeltaDamageTest() { - await using var pair = await PoolManager.GetServerClient(); - var server = pair.Server; - - var entMan = server.EntMan; - var mapLoader = entMan.System(); - var atmosphereSystem = entMan.System(); - var transformSystem = entMan.System(); - var deserializationOptions = DeserializationOptions.Default with { InitializeMaps = true }; - - Entity grid = default; Entity dpEnt = default; - TileAtmosphere tile = null!; AtmosDirection direction = default; // Load our test map in and assert that it exists. - await server.WaitPost(() => + await Server.WaitPost(() => { -#pragma warning disable NUnit2045 - Assert.That(mapLoader.TryLoadMap(_testMap, out _, out var gridSet, deserializationOptions), - $"Failed to load map {_testMap}."); - Assert.That(gridSet, Is.Not.Null, "There were no grids loaded from the map!"); -#pragma warning restore NUnit2045 - - grid = gridSet.First(); + SAtmos.SetAtmosphereSimulation(ProcessEnt, false); }); for (var i = 0; i < Atmospherics.Directions; i++) { - await server.WaitPost(() => + /* + RUNNING REGULAR TICKS USING WaitRunTicks AND GUESSING AS TO HOW MANY ATMOS SIMULATION TICKS ARE HAPPENING + WILL CAUSE A RACE CONDITION THAT IS A PAIN IN THE ASS TO DEBUG + + AN ENTITY MAY BE REMOVED AND ADDED BETWEEN A SUBTICK. IF LINDA PROCESSING IS ENABLED IT MIGHT CAUSE + AN EQUALIZATION TO PUT AIR IN OTHER TILES IN THE SMALL WINDOW WHERE THE TILE IS NOT AIRTIGHT + WHICH WILL THROW OFF DELTAS + */ + + await Server.WaitPost(() => + { + SAtmos.RunProcessingFull(ProcessEnt,ProcessEnt.Owner, SAtmos.AtmosTickRate); + }); + + await Server.WaitPost(() => { // Need to spawn an entity each run to ensure it works for all directions. - var uid = entMan.SpawnAtPosition("DeltaPressureSolidTest", new EntityCoordinates(grid.Owner, Vector2.Zero)); - dpEnt = new Entity(uid, entMan.GetComponent(uid)); - Assert.That(atmosphereSystem.IsDeltaPressureEntityInList(grid.Owner, dpEnt), "Entity was not in processing list when it should have been added!"); + var uid = SEntMan.SpawnAtPosition("DeltaPressureSolidTest", new EntityCoordinates(ProcessEnt.Owner, Vector2.Zero)); + dpEnt = new Entity(uid, SEntMan.GetComponent(uid)); + Assert.That(SAtmos.IsDeltaPressureEntityInList(ProcessEnt.Owner, dpEnt), "Entity was not in processing list when it should have been added!"); - var indices = transformSystem.GetGridOrMapTilePosition(dpEnt); - var gridAtmosComp = entMan.GetComponent(grid); + var indices = Transform.GetGridOrMapTilePosition(dpEnt); direction = (AtmosDirection)(1 << i); var offsetIndices = indices.Offset(direction); - tile = gridAtmosComp.Tiles[offsetIndices]; + var tile = ProcessEnt.Comp1.Tiles[offsetIndices]; Assert.That(tile.Air, Is.Not.Null, $"Tile at {offsetIndices} should have air!"); @@ -274,19 +221,29 @@ public sealed class DeltaPressureTest tile.Air!.AdjustMoles(Gas.Nitrogen, moles); }); - await server.WaitRunTicks(30); - - // Entity should exist, if it took one tick of damage then it should be instantly destroyed. - await server.WaitAssertion(() => + // get jiggy with it! hit that dance white boy! + await Server.WaitPost(() => { - Assert.That(entMan.Deleted(dpEnt), $"{dpEnt} still exists after experiencing threshold pressure from {direction} side!"); - tile.Air!.Clear(); + SAtmos.RunProcessingFull(ProcessEnt,ProcessEnt.Owner, SAtmos.AtmosTickRate); }); - await server.WaitRunTicks(30); - } + // need to run some ticks as deleted entities are queued for removal + // and not removed instantly + await Server.WaitRunTicks(30); - await pair.CleanReturnAsync(); + // Entity shouldn't exist, if it took one tick of damage then it should be instantly destroyed. + await Server.WaitAssertion(() => + { + Assert.That(SEntMan.Deleted(dpEnt), $"{dpEnt} still exists after experiencing threshold pressure from {direction} side!"); + + // Double whammy: in case any unintended gas leak occured due to a race condition, + // clear out all the tiles. + foreach (var mix in SAtmos.GetAllMixtures(ProcessEnt)) + { + mix.Clear(); + } + }); + } } /// @@ -296,39 +253,23 @@ public sealed class DeltaPressureTest [Test] public async Task ProcessingAbsoluteStandbyTest() { - await using var pair = await PoolManager.GetServerClient(); - var server = pair.Server; - - var entMan = server.EntMan; - var mapLoader = entMan.System(); - var atmosphereSystem = entMan.System(); - var transformSystem = entMan.System(); - var deserializationOptions = DeserializationOptions.Default with { InitializeMaps = true }; - - Entity grid = default; Entity dpEnt = default; TileAtmosphere tile = null!; AtmosDirection direction = default; - await server.WaitPost(() => + await Server.WaitPost(() => { -#pragma warning disable NUnit2045 - Assert.That(mapLoader.TryLoadMap(_testMap, out _, out var gridSet, deserializationOptions), - $"Failed to load map {_testMap}."); - Assert.That(gridSet, Is.Not.Null, "There were no grids loaded from the map!"); -#pragma warning restore NUnit2045 - grid = gridSet.First(); - var uid = entMan.SpawnAtPosition("DeltaPressureSolidTestAbsolute", new EntityCoordinates(grid.Owner, Vector2.Zero)); - dpEnt = new Entity(uid, entMan.GetComponent(uid)); - Assert.That(atmosphereSystem.IsDeltaPressureEntityInList(grid.Owner, dpEnt), "Entity was not in processing list when it should have been added!"); + var uid = SEntMan.SpawnAtPosition("DeltaPressureSolidTestAbsolute", new EntityCoordinates(ProcessEnt.Owner, Vector2.Zero)); + dpEnt = new Entity(uid, SEntMan.GetComponent(uid)); + Assert.That(SAtmos.IsDeltaPressureEntityInList(ProcessEnt.Owner, dpEnt), "Entity was not in processing list when it should have been added!"); }); for (var i = 0; i < Atmospherics.Directions; i++) { - await server.WaitPost(() => + await Server.WaitPost(() => { - var indices = transformSystem.GetGridOrMapTilePosition(dpEnt); - var gridAtmosComp = entMan.GetComponent(grid); + var indices = Transform.GetGridOrMapTilePosition(dpEnt); + var gridAtmosComp = SEntMan.GetComponent(ProcessEnt); direction = (AtmosDirection)(1 << i); var offsetIndices = indices.Offset(direction); @@ -340,18 +281,16 @@ public sealed class DeltaPressureTest tile.Air!.AdjustMoles(Gas.Nitrogen, moles); }); - await server.WaitRunTicks(30); + await Server.WaitRunTicks(30); - await server.WaitAssertion(() => + await Server.WaitAssertion(() => { - Assert.That(!entMan.Deleted(dpEnt), $"{dpEnt} should still exist after experiencing non-threshold absolute pressure from {direction} side!"); + Assert.That(!SEntMan.Deleted(dpEnt), $"{dpEnt} should still exist after experiencing non-threshold absolute pressure from {direction} side!"); tile.Air!.Clear(); }); - await server.WaitRunTicks(30); + await Server.WaitRunTicks(30); } - - await pair.CleanReturnAsync(); } /// @@ -361,41 +300,21 @@ public sealed class DeltaPressureTest [Test] public async Task ProcessingAbsoluteDamageTest() { - await using var pair = await PoolManager.GetServerClient(); - var server = pair.Server; - - var entMan = server.EntMan; - var mapLoader = entMan.System(); - var atmosphereSystem = entMan.System(); - var transformSystem = entMan.System(); - var deserializationOptions = DeserializationOptions.Default with { InitializeMaps = true }; - - Entity grid = default; Entity dpEnt = default; TileAtmosphere tile = null!; AtmosDirection direction = default; - await server.WaitPost(() => - { -#pragma warning disable NUnit2045 - Assert.That(mapLoader.TryLoadMap(_testMap, out _, out var gridSet, deserializationOptions), - $"Failed to load map {_testMap}."); - Assert.That(gridSet, Is.Not.Null, "There were no grids loaded from the map!"); -#pragma warning restore NUnit2045 - grid = gridSet.First(); - }); - for (var i = 0; i < Atmospherics.Directions; i++) { - await server.WaitPost(() => + await Server.WaitPost(() => { // Spawn fresh entity each iteration to verify all directions work - var uid = entMan.SpawnAtPosition("DeltaPressureSolidTestAbsolute", new EntityCoordinates(grid.Owner, Vector2.Zero)); - dpEnt = new Entity(uid, entMan.GetComponent(uid)); - Assert.That(atmosphereSystem.IsDeltaPressureEntityInList(grid.Owner, dpEnt), "Entity was not in processing list when it should have been added!"); + var uid = SEntMan.SpawnAtPosition("DeltaPressureSolidTestAbsolute", new EntityCoordinates(ProcessEnt.Owner, Vector2.Zero)); + dpEnt = new Entity(uid, SEntMan.GetComponent(uid)); + Assert.That(SAtmos.IsDeltaPressureEntityInList(ProcessEnt.Owner, dpEnt), "Entity was not in processing list when it should have been added!"); - var indices = transformSystem.GetGridOrMapTilePosition(dpEnt); - var gridAtmosComp = entMan.GetComponent(grid); + var indices = Transform.GetGridOrMapTilePosition(dpEnt); + var gridAtmosComp = SEntMan.GetComponent(ProcessEnt); direction = (AtmosDirection)(1 << i); var offsetIndices = indices.Offset(direction); @@ -408,17 +327,15 @@ public sealed class DeltaPressureTest tile.Air!.AdjustMoles(Gas.Nitrogen, moles); }); - await server.WaitRunTicks(30); + await Server.WaitRunTicks(30); - await server.WaitAssertion(() => + await Server.WaitAssertion(() => { - Assert.That(entMan.Deleted(dpEnt), $"{dpEnt} still exists after experiencing threshold absolute pressure from {direction} side!"); + Assert.That(SEntMan.Deleted(dpEnt), $"{dpEnt} still exists after experiencing threshold absolute pressure from {direction} side!"); tile.Air!.Clear(); }); - await server.WaitRunTicks(30); + await Server.WaitRunTicks(30); } - - await pair.CleanReturnAsync(); } }