public void GetUnsavedItemsWithFlushTest()
        {
            const int subfolderCount = 3;

            string subFolderName = "GetUnsavedItemsTest";

            IRepositoryFolder targetFolder = FixtureRootRepoFolder.CreateSubfolder(subFolderName);

            IRepositoryWriter writer = targetFolder.GetWriter();

            IDataRouter dataRouter = new Mock.NumberedDataRouter(subfolderCount);

            writer.DataRouter = dataRouter;
            writer.AllowSubfoldersCreation = true;

            string fullPath = targetFolder.FullPath;

            Mock.TestDataItem item;

            int lastFlushCount = 0;

            for (int n = 0; n < 10000; ++n)
            {
                item = Mock.TestDataItem.GetTestItem(n);
                writer.Write(item);

                if ((n + 1) % 10 == 0)
                {
                    IDictionary <string, IList <IDataItem> > unsavedItems = writer.GetUnsavedItems();
                    Assert.IsNotNull(unsavedItems);
                    Assert.AreEqual(Math.Min(n + 1, subfolderCount), unsavedItems.Count, "Unsaved items dictionary entry count is not equal to the direct writers count");

                    Assert.AreEqual(n + 1 - lastFlushCount, unsavedItems.Values.Sum((l) => l.Count), "Total number of unsaved items incorrect");
                }
                else if ((n + 1) % 134 == 0)
                {
                    writer.Flush();
                    lastFlushCount = n + 1;

                    IDictionary <string, IList <IDataItem> > unsavedItems = writer.GetUnsavedItems();
                    Assert.IsNotNull(unsavedItems);
                    Assert.AreEqual(Math.Min(n + 1, subfolderCount), unsavedItems.Count, "Unsaved items dictionary entry count is not equal to the direct writers count");

                    Assert.AreEqual(0, unsavedItems.Values.Sum((l) => l.Count), "Total number of unsaved items after flush must be 0");
                }
            }

            writer.Close();
        }
        public void TestUnsavedItemsWithInterruption()
        {
            const string subFolderName = "TestUnsavedItemsWithInterruption";

            const int desiredFileSize = 100;

            Mock.MultiLevelDataRouter router = new Mock.MultiLevelDataRouter(3, 2);

            Repository.RootFolder.GetDescendant(FixtureRootRepoFolder.LogicalPath, false).CreateSubfolder(subFolderName);

            IRepositoryWriter writer = GetStandaloneWriter(subFolderName, desiredFileSize, router);

            const int itemCount                 = 100000;
            const int intervalMinutes           = 1;
            int       intervalSameFolderMinutes = intervalMinutes * router.SubtreeFolderCount;

            IDataItem[] data = GetTestData(itemCount, DateTime.Now, intervalMinutes);

            const int checkIntervalItemCountBase = 57;

            Assume.That(checkIntervalItemCountBase > router.SubtreeFolderCount);

            var random         = new Random();
            int nextCheckCount = checkIntervalItemCountBase;

            int stopAndRestartCounter = itemCount / 2 + random.Next(-itemCount / 5, itemCount / 5);

            for (int n = 0; n < itemCount; ++n)
            {
                writer.Write(dataItem: data[n]);

                if (n == nextCheckCount)
                {
                    nextCheckCount = nextCheckCount + checkIntervalItemCountBase + random.Next(20) - 10;

                    IDictionary <string, IList <IDataItem> > unsavedItemsDict = writer.GetUnsavedItems();
                    Assert.AreEqual(router.SubtreeFolderCount, unsavedItemsDict.Count);

                    Dictionary <string, DateTime> lastSavedTimestamps = new Dictionary <string, DateTime>();

                    foreach (KeyValuePair <string, IList <IDataItem> > pair in unsavedItemsDict)
                    {
                        string            relativePath = pair.Key.Substring(writer.Folder.LogicalPath.Length);
                        IRepositoryFolder sourceFolder = writer.Folder.GetDescendant(relativePath, false);
                        Assert.IsNotNull(sourceFolder);
                        DateTime lastFlushedTimestamp = sourceFolder.LastTimestamp;
                        if (pair.Value.Count > 0)
                        {
                            if (lastFlushedTimestamp > DateTime.MinValue)
                            {
                                Assert.AreEqual(lastFlushedTimestamp.AddMinutes(intervalSameFolderMinutes), pair.Value[0].DateTime);
                            }
                            else
                            {
                                Assert.Less(n, desiredFileSize * (router.SubtreeFolderCount + 1), "Data must have been flushed by now due to desired file size");
                            }
                            lastSavedTimestamps[relativePath] = pair.Value[pair.Value.Count - 1].DateTime;
                        }
                        else
                        {
                            Assert.AreNotEqual(DateTime.MinValue, lastFlushedTimestamp);
                            lastSavedTimestamps[relativePath] = lastFlushedTimestamp;
                        }
                    }

                    DateTime        lastSavedTimestampTotal = lastSavedTimestamps.Values.Max();
                    List <DateTime> lastSavedPerFolder      = lastSavedTimestamps.Values.ToList();
                    lastSavedPerFolder.Sort();

                    for (int j = 0; j < router.SubtreeFolderCount - 2; ++j)
                    {
                        Assert.AreEqual(lastSavedPerFolder[j].AddMinutes(intervalMinutes), lastSavedPerFolder[j + 1]);
                    }

                    Assert.AreEqual(lastSavedPerFolder[router.SubtreeFolderCount - 1], data[n].DateTime);
                }                 // if (n == nextCheckCount)

                if (n == stopAndRestartCounter)
                {
                    var unsavedItemsDict = writer.GetUnsavedItems();
                    writer = GetStandaloneWriter(subFolderName, desiredFileSize, router);

                    var unsavedList = MergeUnsavedItems(unsavedItemsDict);
                    foreach (var dataItem in unsavedList)
                    {
                        writer.Write(dataItem);
                    }
                }
            }

            IRepositoryFolder targetFolder = writer.Folder;

            writer.Close();

            CheckAllDataInFolder(targetFolder, data);
        }
        public void GetUnsavedItemsAmbientTransactionTest()
        {
            const int subfolderCount = 3;

            const string subFolderName = "GetUnsavedItemsAmbientTransactionTest";

            IRepositoryFolder targetFolder = FixtureRootRepoFolder.CreateSubfolder(subFolderName);

            IRepositoryWriter writer = targetFolder.GetWriter();

            targetFolder.Properties.DesiredItemsPerFile = 100;

            IDataRouter dataRouter = new Mock.NumberedDataRouter(subfolderCount);

            writer.DataRouter = dataRouter;
            writer.AllowSubfoldersCreation = true;

            string fullPath = targetFolder.FullPath;

            Mock.TestDataItem item;
            IDictionary <string, IList <IDataItem> > unsavedItems;

            using (TransactionScope scope = new TransactionScope())
            {
                Assert.IsNotNull(Transaction.Current);

                const int count = 10000;

                for (int n = 0; n < count; ++n)
                {
                    item = Mock.TestDataItem.GetTestItem(n);
                    writer.Write(item);

                    if ((n + 1) % 134 == 0)
                    {
                        writer.Flush();

                        unsavedItems = writer.GetUnsavedItems();

                        Assert.IsNotNull(unsavedItems);

                        Assert.AreEqual(Math.Min(n + 1, subfolderCount), unsavedItems.Count
                                        , "Unsaved items dictionary entry count is not equal to the direct writers count");

                        Assert.AreEqual(n + 1, unsavedItems.Values.Sum((l) => l.Count)
                                        , "Total number of unsaved items after flush must not change if in ambient transaction");
                    }
                }

                unsavedItems = writer.GetUnsavedItems();

                Assert.IsNotNull(unsavedItems);

                Assert.AreEqual(subfolderCount, unsavedItems.Count
                                , "Unsaved items dictionary entry count is not equal to the direct writers count");

                Assert.AreEqual(count, unsavedItems.Values.Sum((l) => l.Count)
                                , "Total number of unsaved items must equal number of added items if in ambient transaction");
                scope.Complete();
            }

            Thread.Sleep(50);

            unsavedItems = writer.GetUnsavedItems();

            Assert.IsNotNull(unsavedItems);

            Assert.AreEqual(subfolderCount, unsavedItems.Count
                            , "Unsaved items dictionary entry count is not equal to the direct writers count");

            Assert.AreEqual(0, unsavedItems.Values.Sum((l) => l.Count)
                            , "Total number of unsaved items after committing ambient transaction must be 0");

            writer.Close();
        }