1
0

SaveLoadSaveTest.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. using System.IO;
  2. using System.Linq;
  3. using Content.Shared.CCVar;
  4. using Robust.Shared.Configuration;
  5. using Robust.Shared.ContentPack;
  6. using Robust.Shared.EntitySerialization.Systems;
  7. using Robust.Shared.GameObjects;
  8. using Robust.Shared.Map;
  9. using Robust.Shared.Map.Events;
  10. using Robust.Shared.Serialization.Markdown.Mapping;
  11. using Robust.Shared.Utility;
  12. namespace Content.IntegrationTests.Tests
  13. {
  14. /// <summary>
  15. /// Tests that a grid's yaml does not change when saved consecutively.
  16. /// </summary>
  17. [TestFixture]
  18. public sealed class SaveLoadSaveTest
  19. {
  20. [Test]
  21. public async Task CreateSaveLoadSaveGrid()
  22. {
  23. await using var pair = await PoolManager.GetServerClient();
  24. var server = pair.Server;
  25. var entManager = server.ResolveDependency<IEntityManager>();
  26. var mapLoader = entManager.System<MapLoaderSystem>();
  27. var mapSystem = entManager.System<SharedMapSystem>();
  28. var mapManager = server.ResolveDependency<IMapManager>();
  29. var cfg = server.ResolveDependency<IConfigurationManager>();
  30. Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
  31. var testSystem = server.System<SaveLoadSaveTestSystem>();
  32. testSystem.Enabled = true;
  33. var rp1 = new ResPath("/save load save 1.yml");
  34. var rp2 = new ResPath("/save load save 2.yml");
  35. await server.WaitPost(() =>
  36. {
  37. mapSystem.CreateMap(out var mapId0);
  38. var grid0 = mapManager.CreateGridEntity(mapId0);
  39. entManager.RunMapInit(grid0.Owner, entManager.GetComponent<MetaDataComponent>(grid0));
  40. Assert.That(mapLoader.TrySaveGrid(grid0.Owner, rp1));
  41. mapSystem.CreateMap(out var mapId1);
  42. Assert.That(mapLoader.TryLoadGrid(mapId1, rp1, out var grid1));
  43. Assert.That(mapLoader.TrySaveGrid(grid1!.Value, rp2));
  44. });
  45. await server.WaitIdleAsync();
  46. var userData = server.ResolveDependency<IResourceManager>().UserData;
  47. string one;
  48. string two;
  49. await using (var stream = userData.Open(rp1, FileMode.Open))
  50. using (var reader = new StreamReader(stream))
  51. {
  52. one = await reader.ReadToEndAsync();
  53. }
  54. await using (var stream = userData.Open(rp2, FileMode.Open))
  55. using (var reader = new StreamReader(stream))
  56. {
  57. two = await reader.ReadToEndAsync();
  58. }
  59. Assert.Multiple(() =>
  60. {
  61. Assert.That(two, Is.EqualTo(one));
  62. var failed = TestContext.CurrentContext.Result.Assertions.FirstOrDefault();
  63. if (failed != null)
  64. {
  65. var oneTmp = Path.GetTempFileName();
  66. var twoTmp = Path.GetTempFileName();
  67. File.WriteAllText(oneTmp, one);
  68. File.WriteAllText(twoTmp, two);
  69. TestContext.AddTestAttachment(oneTmp, "First save file");
  70. TestContext.AddTestAttachment(twoTmp, "Second save file");
  71. TestContext.Error.WriteLine("Complete output:");
  72. TestContext.Error.WriteLine(oneTmp);
  73. TestContext.Error.WriteLine(twoTmp);
  74. }
  75. });
  76. testSystem.Enabled = false;
  77. await pair.CleanReturnAsync();
  78. }
  79. private const string TestMap = "Maps/civ/nomads.yml";
  80. /// <summary>
  81. /// Loads the default map, runs it for 5 ticks, then assert that it did not change.
  82. /// </summary>
  83. [Test]
  84. public async Task LoadSaveTicksSaveBagel()
  85. {
  86. await using var pair = await PoolManager.GetServerClient();
  87. var server = pair.Server;
  88. var mapLoader = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<MapLoaderSystem>();
  89. var mapSys = server.System<SharedMapSystem>();
  90. var testSystem = server.System<SaveLoadSaveTestSystem>();
  91. testSystem.Enabled = true;
  92. var rp1 = new ResPath("/load save ticks save 1.yml");
  93. var rp2 = new ResPath("/load save ticks save 2.yml");
  94. MapId mapId = default;
  95. var cfg = server.ResolveDependency<IConfigurationManager>();
  96. Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
  97. // Load bagel.yml as uninitialized map, and save it to ensure it's up to date.
  98. server.Post(() =>
  99. {
  100. var path = new ResPath(TestMap);
  101. Assert.That(mapLoader.TryLoadMap(path, out var map, out _), $"Failed to load test map {TestMap}");
  102. mapId = map!.Value.Comp.MapId;
  103. Assert.That(mapLoader.TrySaveMap(mapId, rp1));
  104. });
  105. // Run 5 ticks.
  106. server.RunTicks(5);
  107. await server.WaitPost(() =>
  108. {
  109. Assert.That(mapLoader.TrySaveMap(mapId, rp2));
  110. });
  111. await server.WaitIdleAsync();
  112. var userData = server.ResolveDependency<IResourceManager>().UserData;
  113. string one;
  114. string two;
  115. await using (var stream = userData.Open(rp1, FileMode.Open))
  116. using (var reader = new StreamReader(stream))
  117. {
  118. one = await reader.ReadToEndAsync();
  119. }
  120. await using (var stream = userData.Open(rp2, FileMode.Open))
  121. using (var reader = new StreamReader(stream))
  122. {
  123. two = await reader.ReadToEndAsync();
  124. }
  125. Assert.Multiple(() =>
  126. {
  127. Assert.That(two, Is.EqualTo(one));
  128. var failed = TestContext.CurrentContext.Result.Assertions.FirstOrDefault();
  129. if (failed != null)
  130. {
  131. var oneTmp = Path.GetTempFileName();
  132. var twoTmp = Path.GetTempFileName();
  133. File.WriteAllText(oneTmp, one);
  134. File.WriteAllText(twoTmp, two);
  135. TestContext.AddTestAttachment(oneTmp, "First save file");
  136. TestContext.AddTestAttachment(twoTmp, "Second save file");
  137. TestContext.Error.WriteLine("Complete output:");
  138. TestContext.Error.WriteLine(oneTmp);
  139. TestContext.Error.WriteLine(twoTmp);
  140. }
  141. });
  142. testSystem.Enabled = false;
  143. await server.WaitPost(() => mapSys.DeleteMap(mapId));
  144. await pair.CleanReturnAsync();
  145. }
  146. /// <summary>
  147. /// Loads the same uninitialized map at slightly different times, and then checks that they are the same
  148. /// when getting saved.
  149. /// </summary>
  150. /// <remarks>
  151. /// Should ensure that entities do not perform randomization prior to initialization and should prevents
  152. /// bugs like the one discussed in github.com/space-wizards/RobustToolbox/issues/3870. This test is somewhat
  153. /// similar to <see cref="LoadSaveTicksSaveBagel"/> and <see cref="SaveLoadSave"/>, but neither of these
  154. /// caught the mentioned bug.
  155. /// </remarks>
  156. [Test]
  157. public async Task LoadTickLoadBagel()
  158. {
  159. await using var pair = await PoolManager.GetServerClient();
  160. var server = pair.Server;
  161. var mapLoader = server.System<MapLoaderSystem>();
  162. var mapSys = server.System<SharedMapSystem>();
  163. var userData = server.ResolveDependency<IResourceManager>().UserData;
  164. var cfg = server.ResolveDependency<IConfigurationManager>();
  165. Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False);
  166. var testSystem = server.System<SaveLoadSaveTestSystem>();
  167. testSystem.Enabled = true;
  168. MapId mapId1 = default;
  169. MapId mapId2 = default;
  170. var fileA = new ResPath("/load tick load a.yml");
  171. var fileB = new ResPath("/load tick load b.yml");
  172. string yamlA;
  173. string yamlB;
  174. // Load & save the first map
  175. server.Post(() =>
  176. {
  177. var path = new ResPath(TestMap);
  178. Assert.That(mapLoader.TryLoadMap(path, out var map, out _), $"Failed to load test map {TestMap}");
  179. mapId1 = map!.Value.Comp.MapId;
  180. Assert.That(mapLoader.TrySaveMap(mapId1, fileA));
  181. });
  182. await server.WaitIdleAsync();
  183. await using (var stream = userData.Open(fileA, FileMode.Open))
  184. using (var reader = new StreamReader(stream))
  185. {
  186. yamlA = await reader.ReadToEndAsync();
  187. }
  188. server.RunTicks(5);
  189. // Load & save the second map
  190. server.Post(() =>
  191. {
  192. var path = new ResPath(TestMap);
  193. Assert.That(mapLoader.TryLoadMap(path, out var map, out _), $"Failed to load test map {TestMap}");
  194. mapId2 = map!.Value.Comp.MapId;
  195. Assert.That(mapLoader.TrySaveMap(mapId2, fileB));
  196. });
  197. await server.WaitIdleAsync();
  198. await using (var stream = userData.Open(fileB, FileMode.Open))
  199. using (var reader = new StreamReader(stream))
  200. {
  201. yamlB = await reader.ReadToEndAsync();
  202. }
  203. Assert.That(yamlA, Is.EqualTo(yamlB));
  204. testSystem.Enabled = false;
  205. await server.WaitPost(() => mapSys.DeleteMap(mapId1));
  206. await server.WaitPost(() => mapSys.DeleteMap(mapId2));
  207. await pair.CleanReturnAsync();
  208. }
  209. /// <summary>
  210. /// Simple system that modifies the data saved to a yaml file by removing the timestamp.
  211. /// Required by some tests that validate that re-saving a map does not modify it.
  212. /// </summary>
  213. private sealed class SaveLoadSaveTestSystem : EntitySystem
  214. {
  215. public bool Enabled;
  216. public override void Initialize()
  217. {
  218. SubscribeLocalEvent<AfterSerializationEvent>(OnAfterSave);
  219. }
  220. private void OnAfterSave(AfterSerializationEvent ev)
  221. {
  222. if (!Enabled)
  223. return;
  224. // Remove timestamp.
  225. ((MappingDataNode)ev.Node["meta"]).Remove("time");
  226. }
  227. }
  228. }
  229. }