public void InsertMultipleItems() { using (var container = new RhetosTestContainer()) { DeleteOldData(container); var repository = container.Resolve <Common.DomRepository>(); var tests = new ListOfTuples <string, string> { { "+", "10" }, // Exactly specified values are considered before generated values, therefore this item is handled after core "9". { "+", "11" }, { "+", "12" }, { "9", "9" }, { "+", "13" }, { "+", "14" }, { "AB+", "AB1000" }, { "X", "X" }, { "X+", "X1" }, { "AB007", "AB007" }, { "AB+", "AB1001" }, { "AB999", "AB999" }, { "AB+", "AB1002" }, }; repository.TestAutoCode.Simple.Insert( tests.Select((test, index) => new TestAutoCode.Simple { ID = new Guid(index + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), Code = test.Item1 })); IEnumerable <string> generatedCodes = repository.TestAutoCode.Simple.Load() .OrderBy(item => item.ID) .Select(item => item.Code); IEnumerable <string> expectedCodes = tests.Select(test => test.Item2); Assert.AreEqual(TestUtility.Dump(expectedCodes), TestUtility.Dump(generatedCodes)); } }
public void OptimizeParallelInsertsForDifferentGroups() { var tests = new ListOfTuples <string, string, bool> // Format: // 1. Records to insert (Grouping1-Grouping2) to entity MultipleGroups, with parallel requests. // 2. Expected generated codes (Code1-Code2) for each record. // 3. Whether the inserts should be executed in parallel. { { "A-B, A-B", "1-1, 2-2", false }, // Same Grouping1 and Grouping2: codes should be generated sequentially. { "A-B, A-C", "1-1, 2-1", false }, // Same Grouping1: Code1 should be generated sequentially. { "A-B, C-B", "1-1, 1-2", false }, // Same Grouping2: Code2 should be generated sequentially. { "A-B, C-D", "1-1, 1-1", true }, { "A-B, B-A", "1-1, 1-1", true }, }; var results = new ListOfTuples <string, string, bool>(); var report = new List <string>(); const int testPause = 100; const int retries = 4; foreach (var test in tests) { for (int retry = 0; retry < retries; retry++) { var items = test.Item1.Split(',').Select(item => item.Trim()).Select(item => item.Split('-')) .Select(item => new TestAutoCode.MultipleGroups { Grouping1 = item[0], Grouping2 = item[1] }) .ToArray(); var insertDurations = new double[items.Length]; var parallelInsertRequests = items.Select((item, x) => (Action <Common.ExecutionContext>) (context => { var sw = Stopwatch.StartNew(); context.Repository.TestAutoCode.MultipleGroups.Insert(item); insertDurations[x] = sw.Elapsed.TotalMilliseconds; Thread.Sleep(testPause); })) .ToArray(); var exceptions = ExecuteParallel(parallelInsertRequests, context => context.Repository.TestAutoCode.MultipleGroups.Insert(new TestAutoCode.MultipleGroups { }), context => Assert.AreEqual(1, context.Repository.TestAutoCode.MultipleGroups.Query().Count(), $"({test.Item1}) Test initialization failed.")); Assert.IsTrue(exceptions.All(e => e == null), $"({test.Item1}) Test initialization threw exception. See the test output for details"); // Check the generated codes: string generatedCodes; using (var container = new RhetosTestContainer(false)) { var repository = container.Resolve <Common.DomRepository>(); generatedCodes = TestUtility.DumpSorted( repository.TestAutoCode.MultipleGroups.Load(items.Select(item => item.ID)), x => $"{x.Code1}-{x.Code2}"); } // Check if the inserts were executed in parallel: bool startedImmediately = insertDurations.Any(t => t < testPause); bool executedInParallel = insertDurations.All(t => t < testPause); // It the parallelism check did not pass, try again to reduce false negatives when the test machine is under load. if (!startedImmediately || executedInParallel != test.Item3) { Console.WriteLine("Retry"); continue; } Assert.IsTrue(startedImmediately, $"({test.Item1}) At lease one item should be inserted without waiting. The test machine was probably under load during the parallelism test."); report.Add($"Test '{test.Item1}' insert durations: '{TestUtility.Dump(insertDurations)}'."); results.Add(test.Item1, generatedCodes, executedInParallel); break; } } Assert.AreEqual( string.Concat(tests.Select(test => $"{test.Item1} => {test.Item2} {(test.Item3 ? "parallel" : "sequential")}\r\n")), string.Concat(results.Select(test => $"{test.Item1} => {test.Item2} {(test.Item3 ? "parallel" : "sequential")}\r\n")), "Report: " + string.Concat(report.Select(line => "\r\n" + line))); }