PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/src/framework/Composable.CQRS.Tests/CQRS/EventRefactoring/Migrations/EventMigrationTest.cs

https://github.com/mlidbom/Composable.Monolithic
C# | 618 lines | 498 code | 114 blank | 6 comment | 0 complexity | fd736d25da605860a7a3ec798d758612 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Composable.DependencyInjection;
  5. using Composable.DependencyInjection.Testing;
  6. using Composable.GenericAbstractions.Time;
  7. using Composable.Persistence.EventStore;
  8. using Composable.Persistence.EventStore.Refactoring.Migrations;
  9. using Composable.SystemCE;
  10. using Composable.SystemCE.LinqCE;
  11. using Composable.SystemCE.TransactionsCE;
  12. using Composable.Tests.CQRS.EventRefactoring.Migrations.Events;
  13. using FluentAssertions;
  14. using JetBrains.Annotations;
  15. using NUnit.Framework;
  16. // ReSharper disable AccessToDisposedClosure
  17. // ReSharper disable AccessToModifiedClosure
  18. namespace Composable.Tests.CQRS.EventRefactoring.Migrations
  19. {
  20. //Todo: Write tests that verify that none of the persistence layers lose precision in the persisted ReadOrder when persisting refactorings.
  21. //[ConfigurationBasedDuplicateByDimensions]
  22. public class EventMigrationTest : EventMigrationTestBase
  23. {
  24. [Test]
  25. public void Base_class_method_should_detect_incorrect_type_order()
  26. {
  27. this.Invoking(
  28. _ => RunMigrationTest(
  29. new MigrationScenario(
  30. EnumerableCE.OfTypes<Ec1, E1, Ef, Ef>(),
  31. EnumerableCE.OfTypes<Ec1, Ef, E2, Ef>())))
  32. .Should().Throw<Exception>();
  33. }
  34. [Test]
  35. public void Replacing_E1_with_E2()
  36. {
  37. RunMigrationTest(new MigrationScenario(
  38. EnumerableCE.OfTypes<Ec1, E1, Ef, Ef>(),
  39. EnumerableCE.OfTypes<Ec1, E2, Ef, Ef>(),
  40. Replace<E1>.With<E2>()));
  41. }
  42. [Test]
  43. public void Replacing_E1_with_E2_at_end_of_stream()
  44. {
  45. RunMigrationTest(new MigrationScenario(
  46. EnumerableCE.OfTypes<Ec1, E1>(),
  47. EnumerableCE.OfTypes<Ec1, E2>(),
  48. Replace<E1>.With<E2>()));
  49. }
  50. [Test]
  51. public void Replacing_E1_with_E2_E3_at_end_of_stream()
  52. {
  53. RunMigrationTest(new MigrationScenario(
  54. EnumerableCE.OfTypes<Ec1, E1>(),
  55. EnumerableCE.OfTypes<Ec1, E2, E3>(),
  56. Replace<E1>.With<E2, E3>()));
  57. }
  58. [Test]
  59. public void Replacing_E1_with_E2_E3()
  60. {
  61. RunMigrationTest(new MigrationScenario(
  62. EnumerableCE.OfTypes<Ec1, E1, Ef>(),
  63. EnumerableCE.OfTypes<Ec1, E2, E3, Ef>(),
  64. Replace<E1>.With<E2, E3>()));
  65. }
  66. [Test]
  67. public void Replacing_E1_with_E2_E3_2()
  68. {
  69. RunMigrationTest(new MigrationScenario(
  70. EnumerableCE.OfTypes<Ec1, E1, Ef, Ef, Ef, Ef>(),
  71. EnumerableCE.OfTypes<Ec1, E2, E3, Ef, Ef, Ef, Ef>(),
  72. Replace<E1>.With<E2, E3>()));
  73. }
  74. [Test]
  75. public void Replacing_E1_with_E2_then_irrelevant_migration()
  76. {
  77. RunMigrationTest(new MigrationScenario(
  78. EnumerableCE.OfTypes<Ec1, E1, Ef>(),
  79. EnumerableCE.OfTypes<Ec1, E2, Ef>(),
  80. Replace<E1>.With<E2>(),
  81. Replace<E1>.With<E5>()));
  82. }
  83. [Test]
  84. public void Replacing_E1_with_E2_E3_then_an_unrelated_migration_v2()
  85. {
  86. RunMigrationTest(new MigrationScenario(
  87. EnumerableCE.OfTypes<Ec1, E1, Ef>(),
  88. EnumerableCE.OfTypes<Ec1, E2, E3, Ef>(),
  89. Replace<E1>.With<E2, E3>(),
  90. Replace<E1>.With<E5>()));
  91. }
  92. [Test]
  93. public void Replacing_E1_with_E2_E3_then_E2_with_E4()
  94. {
  95. RunMigrationTest(new MigrationScenario(
  96. EnumerableCE.OfTypes<Ec1, E1, Ef>(),
  97. EnumerableCE.OfTypes<Ec1, E4, E3, Ef>(),
  98. Replace<E1>.With<E2, E3>(),//Ec1, E2, E3, Ef
  99. Replace<E2>.With<E4>())); //Ec1, E4, E3, Ef
  100. }
  101. [Test]
  102. public void Inserting_E3_before_E1()
  103. {
  104. RunMigrationTest(new MigrationScenario(
  105. EnumerableCE.OfTypes<Ec1, E1, Ef>(),
  106. EnumerableCE.OfTypes<Ec1, E3, E1, Ef>(),
  107. Before<E1>.Insert<E3>()));
  108. }
  109. [Test]
  110. public void Inserting_E3_E4_before_E1()
  111. {
  112. RunMigrationTest(new MigrationScenario(
  113. EnumerableCE.OfTypes<Ec1, E1, Ef>(),
  114. EnumerableCE.OfTypes<Ec1, E3, E4, E1, Ef>(),
  115. Before<E1>.Insert<E3, E4>()));
  116. }
  117. [Test]
  118. public void Inserting_E2_before_E1_then_E3_before_E2()
  119. {
  120. RunMigrationTest(new MigrationScenario(
  121. EnumerableCE.OfTypes<Ec1, E1, Ef>(),
  122. EnumerableCE.OfTypes<Ec1, E3, E2, E1, Ef>(),
  123. Before<E1>.Insert<E2>(),
  124. Before<E2>.Insert<E3>()));
  125. }
  126. [Test]
  127. public void Inserting_E3_E4_before_E1_then_E5_before_E3()
  128. {
  129. RunMigrationTest(new MigrationScenario(
  130. EnumerableCE.OfTypes<Ec1, E1>(),
  131. EnumerableCE.OfTypes<Ec1, E5, E3, E4, E1>(),
  132. Before<E1>.Insert<E3, E4>(),//Ec1, E3, E4, E1
  133. Before<E3>.Insert<E5>())); //Ec1, E5, E3, E4, E1;
  134. }
  135. [Test]
  136. public void Given_Ec1_E1_Ef_Inserting_E3_E4_before_E1_then_E5_before_E4()
  137. {
  138. RunMigrationTest(new MigrationScenario(
  139. EnumerableCE.OfTypes<Ec1, E1, Ef>(),
  140. EnumerableCE.OfTypes<Ec1, E3, E5, E4, E1, Ef>(),
  141. Before<E1>.Insert<E3, E4>(), //Ec1, E3, E4, E1, Ef
  142. Before<E4>.Insert<E5>())); //Ec1, E3, E5, E4, E1, Ef
  143. }
  144. [Test]
  145. public void Given_Ec1_E1_Inserting_E2_before_E1_then_E3_before_E2()
  146. {
  147. RunMigrationTest(new MigrationScenario(
  148. EnumerableCE.OfTypes<Ec1, E1>(),
  149. EnumerableCE.OfTypes<Ec1, E3, E2, E1>(),
  150. Before<E1>.Insert<E2>(), //Ec1, E2, E1
  151. Before<E2>.Insert<E3>())); //Ec1, E3, E2, E1
  152. }
  153. [Test]
  154. public void Given_Ec1_E1_Inserting_E3_E2_before_E1_then_E4_before_E3_then_E5_before_E4()
  155. {
  156. RunMigrationTest(new MigrationScenario(
  157. EnumerableCE.OfTypes<Ec1, E1>(),
  158. EnumerableCE.OfTypes<Ec1, E5, E4, E3, E2, E1>(),
  159. Before<E1>.Insert<E3, E2>(), //Ec1, E3, E2, E1
  160. Before<E3>.Insert<E4>(), //Ec1, E4, E3, E2, E1
  161. Before<E4>.Insert<E5>())); //Ec1, E5, E4, E3, E2, E1
  162. }
  163. [Test]
  164. public void Inserting_E3_E4_before_E1_then_E5_before_E4_then_replace_E4_with_E6()
  165. {
  166. RunMigrationTest(new MigrationScenario(
  167. EnumerableCE.OfTypes<Ec1, E1, Ef>(),
  168. EnumerableCE.OfTypes<Ec1, E6, E5, E4, E1, Ef>(),
  169. Before<E1>.Insert<E3, E4>(), //Ec1, E3, E4, E1, Ef
  170. Before<E4>.Insert<E5>(), //Ec1, E3, E5, E4, E1, Ef
  171. Replace<E3>.With<E6>())); //Ec1, E6, E5, E4, E1, Ef
  172. }
  173. [Test]
  174. public void Inserting_E3_E4_before_E1_then_E5_before_E4_then_replace_E4_with_E6_then_replace_Ef_with_E7_then_insert_E8_after_E7()
  175. {
  176. RunMigrationTest(new MigrationScenario
  177. (EnumerableCE.OfTypes<Ec1, E1, Ef>(),
  178. EnumerableCE.OfTypes<Ec1, E6, E5, E4, E1, E7, E8>(),
  179. Before<E1>.Insert<E3, E4>(), //Ec1, E3, E4, E1, Ef
  180. Before<E4>.Insert<E5>(), //Ec1, E3, E5, E4, E1, Ef
  181. Replace<E3>.With<E6>(), //Ec1, E6, E5, E4, E1, Ef
  182. Replace<Ef>.With<E7>(), //Ec1, E6, E5, E4, E1, E7
  183. After<E7>.Insert<E8>())); //Ec1, E6, E5, E4, E1, E7, E8
  184. }
  185. [Test]
  186. public void Inserting_E3_E4_before_E1_then_E5_before_E3_2()
  187. {
  188. RunMigrationTest(new MigrationScenario(
  189. EnumerableCE.OfTypes<Ec1, E1, Ef, Ef>(),
  190. EnumerableCE.OfTypes<Ec1, E5, E3, E4, E1, Ef, Ef>(),
  191. Before<E1>.Insert<E3, E4>(), //Ec1, E3, E4, E1, Ef, Ef
  192. Before<E3>.Insert<E5>())); //Ec1, E5, E3, E4, E1, Ef, Ef
  193. }
  194. [Test]
  195. public void Inserting_E3_E4_before_E1_then_E5_before_E4_2()
  196. {
  197. RunMigrationTest(new MigrationScenario(
  198. EnumerableCE.OfTypes<Ec1, E1, Ef, Ef>(),
  199. EnumerableCE.OfTypes<Ec1, E3, E5, E4, E1, Ef, Ef>(),
  200. Before<E1>.Insert<E3, E4>(),//Ec1, E3, E4 E1, Ef, Ef
  201. Before<E4>.Insert<E5>())); //Ec1, E3, E5, E4, E1, Ef, Ef
  202. }
  203. [Test]
  204. public void Inserting_E2_after_E1()
  205. {
  206. RunMigrationTest(new MigrationScenario(
  207. EnumerableCE.OfTypes<Ec1, E1, Ef, Ef>(),
  208. EnumerableCE.OfTypes<Ec1, E1, E2, Ef, Ef>(),
  209. After<E1>.Insert<E2>()));
  210. }
  211. [Test]
  212. public void Inserting_E2_after_E1_at_end_of_stream()
  213. {
  214. RunMigrationTest(new MigrationScenario(
  215. EnumerableCE.OfTypes<Ec1, E1>(),
  216. EnumerableCE.OfTypes<Ec1, E1, E2>(),
  217. After<E1>.Insert<E2>()));
  218. }
  219. [Test]
  220. public void Given_Ec1_E1_before_E1_E2_after_E2_E3_throws_NonIdempotentMigrationDetectedException()
  221. {
  222. this.Invoking(
  223. me =>
  224. RunMigrationTest(
  225. new MigrationScenario(
  226. EnumerableCE.OfTypes<Ec1, E1>(),
  227. EnumerableCE.OfTypes<Ec1, E2, E3, E1>(),
  228. Before<E1>.Insert<E2>(),
  229. After<E2>.Insert<E3>())))
  230. .Should().Throw<NonIdempotentMigrationDetectedException>();
  231. }
  232. [Test]
  233. public void PersistingMigrationsOfTheSameAggregateMultipleTimes()
  234. {
  235. var emptyMigrationsArray = Array.Empty<IEventMigration>();
  236. IReadOnlyList<IEventMigration> migrations = emptyMigrationsArray;
  237. var toDispose = StrictAggregateDisposable.Create();
  238. try
  239. {
  240. var serviceLocator = CreateServiceLocatorForEventStoreType(() => migrations);
  241. toDispose.Add(serviceLocator);
  242. var id = Guid.Parse("00000000-0000-0000-0000-000000000001");
  243. serviceLocator.Resolve<TestingTimeSource>().FreezeAtUtcTime(DateTime.Parse("2001-01-01 12:00"));
  244. var aggregate = TestAggregate.FromEvents(serviceLocator.Resolve<IUtcTimeTimeSource>(), id, EnumerableCE.OfTypes<Ec1, E1, E2, E3, E4>());
  245. var initialHistory = aggregate.History;
  246. IEventStoreUpdater Session() => serviceLocator.Resolve<IEventStoreUpdater>();
  247. IEventStore EventStore() => serviceLocator.Resolve<IEventStore>();
  248. var firstSavedHistory = serviceLocator.ExecuteTransactionInIsolatedScope(
  249. () =>
  250. {
  251. Session().Save(aggregate);
  252. return Session().Get<TestAggregate>(id).History;
  253. });
  254. AssertStreamsAreIdentical(initialHistory, firstSavedHistory, "first saved history");
  255. migrations = EnumerableCE.Create(Replace<E1>.With<E5>()).ToList();
  256. ClearCache(serviceLocator);
  257. var migratedHistory = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  258. var expectedAfterReplacingE1WithE5 =
  259. TestAggregate.FromEvents(serviceLocator.Resolve<IUtcTimeTimeSource>(), id, EnumerableCE.OfTypes<Ec1, E5, E2, E3, E4>()).History;
  260. AssertStreamsAreIdentical(expected: expectedAfterReplacingE1WithE5, migratedHistory: migratedHistory, descriptionOfHistory: "migrated history");
  261. var historyAfterPersistingButBeforeReload = serviceLocator.ExecuteInIsolatedScope(
  262. () =>
  263. {
  264. EventStore().PersistMigrations();
  265. return TransactionScopeCe.Execute(() => Session().Get<TestAggregate>(id).History);
  266. });
  267. AssertStreamsAreIdentical(expected: expectedAfterReplacingE1WithE5, migratedHistory: historyAfterPersistingButBeforeReload, descriptionOfHistory: "migrated, persisted");
  268. var historyAfterPersistingAndReloading = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  269. AssertStreamsAreIdentical(expected: expectedAfterReplacingE1WithE5, migratedHistory: historyAfterPersistingAndReloading, descriptionOfHistory: "migrated, persisted, reloaded");
  270. migrations = EnumerableCE.Create(Replace<E2>.With<E6>()).ToList();
  271. toDispose.Add(serviceLocator = serviceLocator.Clone());
  272. migratedHistory = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  273. var expectedAfterReplacingE2WithE6 = TestAggregate.FromEvents(serviceLocator.Resolve<IUtcTimeTimeSource>(), id, EnumerableCE.OfTypes<Ec1, E5, E6, E3, E4>()).History;
  274. AssertStreamsAreIdentical(expected: expectedAfterReplacingE2WithE6, migratedHistory: migratedHistory, descriptionOfHistory: "migrated history");
  275. historyAfterPersistingButBeforeReload = serviceLocator.ExecuteInIsolatedScope(
  276. () =>
  277. {
  278. EventStore().PersistMigrations();
  279. return TransactionScopeCe.Execute(() => Session().Get<TestAggregate>(id).History);
  280. });
  281. AssertStreamsAreIdentical(expected: expectedAfterReplacingE2WithE6, migratedHistory: historyAfterPersistingButBeforeReload, descriptionOfHistory: "migrated, persisted");
  282. historyAfterPersistingAndReloading = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  283. AssertStreamsAreIdentical(expected: expectedAfterReplacingE2WithE6, migratedHistory: historyAfterPersistingAndReloading, descriptionOfHistory: "migrated, persisted, reloaded");
  284. }finally
  285. {
  286. toDispose.Dispose();
  287. }
  288. }
  289. [Test]
  290. public void PersistingMigrationsOfTheSameAggregateMultipleTimesWithEventsAddedInTheMiddleAndAfter()
  291. {
  292. var emptyMigrationsArray = Array.Empty<IEventMigration>();
  293. IReadOnlyList<IEventMigration> migrations = emptyMigrationsArray;
  294. var toDispose = StrictAggregateDisposable.Create();
  295. try
  296. {
  297. var serviceLocator = CreateServiceLocatorForEventStoreType(() => migrations);
  298. toDispose.Add(serviceLocator);
  299. var id = Guid.Parse("00000000-0000-0000-0000-000000000001");
  300. serviceLocator.Resolve<TestingTimeSource>().FreezeAtUtcTime(DateTime.Parse("2001-01-01 12:00"));
  301. var aggregate = TestAggregate.FromEvents(serviceLocator.Resolve<IUtcTimeTimeSource>(), id, EnumerableCE.OfTypes<Ec1, E1, E2, E3, E4>());
  302. var initialHistory = aggregate.History;
  303. IEventStoreUpdater Session() => serviceLocator.Resolve<IEventStoreUpdater>();
  304. IEventStore EventStore() => serviceLocator.Resolve<IEventStore>();
  305. var firstSavedHistory = serviceLocator.ExecuteTransactionInIsolatedScope(
  306. () =>
  307. {
  308. Session().Save(aggregate);
  309. return Session().Get<TestAggregate>(id).History;
  310. });
  311. AssertStreamsAreIdentical(initialHistory, firstSavedHistory, "first saved history");
  312. migrations = EnumerableCE.Create(Replace<E1>.With<E5>()).ToList();
  313. ClearCache(serviceLocator);
  314. var migratedHistory = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  315. var expectedAfterReplacingE1WithE5 =
  316. TestAggregate.FromEvents(serviceLocator.Resolve<IUtcTimeTimeSource>(), id, EnumerableCE.OfTypes<Ec1, E5, E2, E3, E4>()).History;
  317. AssertStreamsAreIdentical(expected: expectedAfterReplacingE1WithE5, migratedHistory: migratedHistory, descriptionOfHistory: "migrated history");
  318. var historyAfterPersistingButBeforeReload = serviceLocator.ExecuteInIsolatedScope(
  319. () =>
  320. {
  321. EventStore().PersistMigrations();
  322. return TransactionScopeCe.Execute(() => Session().Get<TestAggregate>(id).History);
  323. });
  324. AssertStreamsAreIdentical(expected: expectedAfterReplacingE1WithE5, migratedHistory: historyAfterPersistingButBeforeReload, descriptionOfHistory: "migrated, persisted");
  325. var historyAfterPersistingAndReloading = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  326. AssertStreamsAreIdentical(expected: expectedAfterReplacingE1WithE5, migratedHistory: historyAfterPersistingAndReloading, descriptionOfHistory: "migrated, persisted, reloaded");
  327. serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).Publish(new E6(), new E7()));
  328. migrations = EnumerableCE.Create(Replace<E2>.With<E6>()).ToList();
  329. toDispose.Add(serviceLocator = serviceLocator.Clone());
  330. migratedHistory = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  331. var expectedAfterReplacingE2WithE6 = TestAggregate.FromEvents(serviceLocator.Resolve<IUtcTimeTimeSource>(), id, EnumerableCE.OfTypes<Ec1, E5, E6, E3, E4, E6, E7>()).History;
  332. AssertStreamsAreIdentical(expected: expectedAfterReplacingE2WithE6, migratedHistory: migratedHistory, descriptionOfHistory: "migrated history");
  333. historyAfterPersistingButBeforeReload = serviceLocator.ExecuteInIsolatedScope(
  334. () =>
  335. {
  336. EventStore().PersistMigrations();
  337. return TransactionScopeCe.Execute(() => Session().Get<TestAggregate>(id).History);
  338. });
  339. AssertStreamsAreIdentical(expected: expectedAfterReplacingE2WithE6, migratedHistory: historyAfterPersistingButBeforeReload, descriptionOfHistory: "migrated, persisted");
  340. historyAfterPersistingAndReloading = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  341. AssertStreamsAreIdentical(expected: expectedAfterReplacingE2WithE6, migratedHistory: historyAfterPersistingAndReloading, descriptionOfHistory: "migrated, persisted, reloaded");
  342. migrations = Enumerable.Empty<IEventMigration>().ToList();
  343. serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).Publish(new E8(), new E9()));
  344. historyAfterPersistingAndReloading = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  345. var expectedAfterReplacingE2WithE6AndRaisingE8E9 = TestAggregate.FromEvents(serviceLocator.Resolve<IUtcTimeTimeSource>(), id, EnumerableCE.OfTypes<Ec1, E5, E6, E3, E4, E6, E7, E8, E9>()).History;
  346. AssertStreamsAreIdentical(expected: expectedAfterReplacingE2WithE6AndRaisingE8E9, migratedHistory: historyAfterPersistingAndReloading, descriptionOfHistory: "migrated, persisted, reloaded");
  347. }
  348. finally
  349. {
  350. toDispose.Dispose();
  351. }
  352. }
  353. [Test]
  354. public void UpdatingAnAggregateAfterPersistingMigrations()
  355. {
  356. IReadOnlyList<IEventMigration> migrations = Array.Empty<IEventMigration>();
  357. var toDispose = StrictAggregateDisposable.Create();
  358. try
  359. {
  360. var serviceLocator = CreateServiceLocatorForEventStoreType(() => migrations);
  361. toDispose.Add(serviceLocator);
  362. var id = Guid.Parse("00000000-0000-0000-0000-000000000001");
  363. serviceLocator.Resolve<TestingTimeSource>().FreezeAtUtcTime(DateTime.Parse("2001-01-01 12:00"));
  364. var initialAggregate = TestAggregate.FromEvents(serviceLocator.Resolve<IUtcTimeTimeSource>(), id, EnumerableCE.OfTypes<Ec1, E1>());
  365. IEventStoreUpdater Session() => serviceLocator.Resolve<IEventStoreUpdater>();
  366. IEventStore EventStore() => serviceLocator.Resolve<IEventStore>();
  367. serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Save(initialAggregate));
  368. migrations = EnumerableCE.Create(Replace<E1>.With<E5>()).ToList();
  369. serviceLocator.ExecuteInIsolatedScope(() => EventStore().PersistMigrations());
  370. migrations = EnumerableCE.Create<IEventMigration>().ToList();
  371. serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).Publish(new E2()));
  372. var aggregate = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id));
  373. var expected = TestAggregate.FromEvents(serviceLocator.Resolve<IUtcTimeTimeSource>(), id, EnumerableCE.OfTypes<Ec1, E5, E2>()).History;
  374. AssertStreamsAreIdentical(expected: expected, migratedHistory: aggregate.History, descriptionOfHistory: "migrated history");
  375. var completeEventHistory =serviceLocator.ExecuteInIsolatedScope(() => EventStore().ListAllEventsForTestingPurposesAbsolutelyNotUsableForARealEventStoreOfAnySize()).Cast<AggregateEvent>().ToList();
  376. AssertStreamsAreIdentical(expected: expected, migratedHistory: completeEventHistory, descriptionOfHistory: "streamed persisted history");
  377. toDispose.Add(serviceLocator = serviceLocator.Clone());
  378. completeEventHistory = serviceLocator.ExecuteInIsolatedScope(() => EventStore().ListAllEventsForTestingPurposesAbsolutelyNotUsableForARealEventStoreOfAnySize()).Cast<AggregateEvent>().ToList();
  379. AssertStreamsAreIdentical(expected: expected, migratedHistory: completeEventHistory, descriptionOfHistory: "streamed persisted history");
  380. }
  381. finally
  382. {
  383. toDispose.Dispose();
  384. }
  385. }
  386. [Test]
  387. public void Inserting_E2_Before_E1_Persisting_and_then_Inserting_E3_before_E1()
  388. {
  389. var firstMigration = EnumerableCE.Create(Before<E1>.Insert<E2>()).ToArray();
  390. var secondMigration = EnumerableCE.Create(Before<E1>.Insert<E3>()).ToArray();
  391. IReadOnlyList<IEventMigration> migrations = new List<IEventMigration>();
  392. var toDispose = StrictAggregateDisposable.Create();
  393. try
  394. {
  395. var serviceLocator = CreateServiceLocatorForEventStoreType(() => migrations);
  396. toDispose.Add(serviceLocator);
  397. serviceLocator.Resolve<TestingTimeSource>().FreezeAtUtcTime(DateTime.Parse("2001-01-01 12:00"));
  398. var id = Guid.Parse("00000000-0000-0000-0000-000000000001");
  399. var initialAggregate = TestAggregate.FromEvents(serviceLocator.Resolve<IUtcTimeTimeSource>(), id, EnumerableCE.OfTypes<Ec1, E1>());
  400. var expectedHistoryAfterFirstMigration = TestAggregate.FromEvents(serviceLocator.Resolve<IUtcTimeTimeSource>(), id, EnumerableCE.OfTypes<Ec1, E2, E1>()).History;
  401. var expectedHistoryAfterSecondMigration = TestAggregate.FromEvents(serviceLocator.Resolve<IUtcTimeTimeSource>(), id, EnumerableCE.OfTypes<Ec1, E2, E3, E1>()).History;
  402. IEventStoreUpdater Session() => serviceLocator.Resolve<IEventStoreUpdater>();
  403. IEventStore EventStore() => serviceLocator.Resolve<IEventStore>();
  404. serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Save(initialAggregate));
  405. migrations = firstMigration;
  406. ClearCache(serviceLocator);
  407. var historyWithFirstMigrationUnPersisted = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  408. serviceLocator.ExecuteInIsolatedScope(() => EventStore().PersistMigrations());
  409. var historyAfterPersistingFirstMigration = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  410. AssertStreamsAreIdentical(expectedHistoryAfterFirstMigration, historyWithFirstMigrationUnPersisted, nameof(historyWithFirstMigrationUnPersisted));
  411. AssertStreamsAreIdentical(expectedHistoryAfterFirstMigration, historyAfterPersistingFirstMigration, nameof(historyAfterPersistingFirstMigration));
  412. migrations = secondMigration;
  413. toDispose.Add(serviceLocator = serviceLocator.Clone());
  414. var historyWithSecondMigrationUnPersisted = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  415. serviceLocator.ExecuteInIsolatedScope(() => EventStore().PersistMigrations());
  416. var historyAfterPersistingSecondMigration = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  417. AssertStreamsAreIdentical(expectedHistoryAfterSecondMigration, historyWithSecondMigrationUnPersisted, nameof(historyWithSecondMigrationUnPersisted));
  418. AssertStreamsAreIdentical(expectedHistoryAfterSecondMigration, historyAfterPersistingSecondMigration, nameof(historyAfterPersistingSecondMigration));
  419. }
  420. finally
  421. {
  422. toDispose.Dispose();
  423. }
  424. }
  425. [Test]
  426. public void Inserting_E2_After_E1_Persisting_and_then_Inserting_E3_after_E1()
  427. {
  428. var firstMigration = EnumerableCE.Create(After<E1>.Insert<E2>()).ToArray();
  429. var secondMigration = EnumerableCE.Create(After<E1>.Insert<E3>()).ToArray();
  430. IReadOnlyList<IEventMigration> migrations = new List<IEventMigration>();
  431. var toDispose = StrictAggregateDisposable.Create();
  432. try
  433. {
  434. var serviceLocator = CreateServiceLocatorForEventStoreType(() => migrations);
  435. toDispose.Add(serviceLocator);
  436. serviceLocator.Resolve<TestingTimeSource>().FreezeAtUtcTime(DateTime.Parse("2001-01-01 12:00"));
  437. var id = Guid.Parse("00000000-0000-0000-0000-000000000001");
  438. var initialAggregate = TestAggregate.FromEvents(serviceLocator.Resolve<IUtcTimeTimeSource>(), id, EnumerableCE.OfTypes<Ec1, E1>());
  439. var expectedHistoryAfterFirstMigration = TestAggregate.FromEvents(serviceLocator.Resolve<IUtcTimeTimeSource>(), id, EnumerableCE.OfTypes<Ec1, E1, E2>()).History;
  440. var expectedHistoryAfterSecondMigration = TestAggregate.FromEvents(serviceLocator.Resolve<IUtcTimeTimeSource>(), id, EnumerableCE.OfTypes<Ec1, E1, E3, E2>()).History;
  441. IEventStoreUpdater Session() => serviceLocator.Resolve<IEventStoreUpdater>();
  442. IEventStore EventStore() => serviceLocator.Resolve<IEventStore>();
  443. serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Save(initialAggregate));
  444. migrations = firstMigration;
  445. ClearCache(serviceLocator);
  446. var historyWithFirstMigrationUnPersisted = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  447. serviceLocator.ExecuteInIsolatedScope(() => EventStore().PersistMigrations());
  448. var historyAfterPersistingFirstMigration = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  449. AssertStreamsAreIdentical(expectedHistoryAfterFirstMigration, historyWithFirstMigrationUnPersisted, nameof(historyWithFirstMigrationUnPersisted));
  450. AssertStreamsAreIdentical(expectedHistoryAfterFirstMigration, historyAfterPersistingFirstMigration, nameof(historyAfterPersistingFirstMigration));
  451. migrations = secondMigration;
  452. toDispose.Add(serviceLocator = serviceLocator.Clone());
  453. var historyWithSecondMigrationUnPersisted = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  454. serviceLocator.ExecuteInIsolatedScope(() => EventStore().PersistMigrations());
  455. var historyAfterPersistingSecondMigration = serviceLocator.ExecuteTransactionInIsolatedScope(() => Session().Get<TestAggregate>(id).History);
  456. AssertStreamsAreIdentical(expectedHistoryAfterSecondMigration, historyWithSecondMigrationUnPersisted, nameof(historyWithSecondMigrationUnPersisted));
  457. AssertStreamsAreIdentical(expectedHistoryAfterSecondMigration, historyAfterPersistingSecondMigration, nameof(historyAfterPersistingSecondMigration));
  458. }
  459. finally
  460. {
  461. toDispose.Dispose();
  462. }
  463. }
  464. [Test]
  465. public void Inserting_E2_Before_E1()
  466. {
  467. RunMigrationTest(
  468. new MigrationScenario(
  469. EnumerableCE.OfTypes<Ec1, E1>(),
  470. EnumerableCE.OfTypes<Ec1, E2, E1>(),
  471. Before<E1>.Insert<E2>()));
  472. }
  473. [Test]
  474. public void Persisting_migrations_and_then_updating_the_aggregate_from_another_processes_EventStore_results_in_both_processes_seeing_identical_histories()
  475. {
  476. var actualMigrations = EnumerableCE.Create(Replace<E1>.With<E2>()).ToArray();
  477. IReadOnlyList<IEventMigration> migrations = new List<IEventMigration>();
  478. // ReSharper disable once AccessToModifiedClosure this is exactly what we wish to achieve here...
  479. using var serviceLocator = CreateServiceLocatorForEventStoreType(() => migrations);
  480. IEventStore PersistingEventStore() => serviceLocator.Resolve<IEventStore>();
  481. using var otherProcessServiceLocator = serviceLocator.Clone();
  482. // ReSharper disable once AccessToDisposedClosure
  483. IEventStoreUpdater OtherEventStoreSession() => otherProcessServiceLocator.Resolve<IEventStoreUpdater>();
  484. var id = Guid.Parse("00000000-0000-0000-0000-000000000001");
  485. var aggregate = TestAggregate.FromEvents(
  486. serviceLocator.Resolve<IUtcTimeTimeSource>(),
  487. id,
  488. EnumerableCE.OfTypes<Ec1, E1, E2, E3, E4>());
  489. otherProcessServiceLocator.ExecuteTransactionInIsolatedScope(() => OtherEventStoreSession().Save(aggregate));
  490. migrations = actualMigrations;
  491. otherProcessServiceLocator.ExecuteTransactionInIsolatedScope(() => OtherEventStoreSession().Get<TestAggregate>(id));
  492. var test = serviceLocator.ExecuteTransactionInIsolatedScope(() => PersistingEventStore().GetAggregateHistory(id));
  493. test.Count.Should().BeGreaterThan(0);
  494. serviceLocator.ExecuteInIsolatedScope(() => PersistingEventStore().PersistMigrations());
  495. otherProcessServiceLocator.ExecuteTransactionInIsolatedScope(() => OtherEventStoreSession().Get<TestAggregate>(id).Publish(new E3()));
  496. var firstProcessHistory = serviceLocator.ExecuteTransactionInIsolatedScope(() => PersistingEventStore().GetAggregateHistory(id));
  497. var secondProcessHistory = otherProcessServiceLocator.ExecuteTransactionInIsolatedScope(() => otherProcessServiceLocator.Resolve<IEventStore>().GetAggregateHistory(id));
  498. EventStorageTestHelper.StripSeventhDecimalPointFromSecondFractionOnUtcUpdateTime(firstProcessHistory);
  499. EventStorageTestHelper.StripSeventhDecimalPointFromSecondFractionOnUtcUpdateTime(secondProcessHistory);
  500. EventMigrationTestBase.AssertStreamsAreIdentical(firstProcessHistory, secondProcessHistory, "Both process histories should be identical");
  501. }
  502. public EventMigrationTest([NotNull] string _) : base(_) {}
  503. }
  504. }