public static List <SnapshotTableDifferences> SortDifferences(SnapshotCollection collection, List <SnapshotTableDifferences> tableDiffs)
 {
     return(tableDiffs.Select(t => t.TableDefinition.SortColumns.Any()
         ? SortTable(t)
         : t)
            .ToList());
 }
예제 #2
0
        public static bool Match(SnapshotCollection collection, Snapshot before, Snapshot after)
        {
            foreach (var tableDefinition in collection.TablesInDefinitionOrder.Where(t => !t.ExcludeFromComparison))
            {
                //find all keys
                var beforeRows = SnapshotKeyExtractor.GetKeys(before, tableDefinition) ?? new Dictionary <SnapshotRowKey, SnapshotRow>();
                var afterRows  = SnapshotKeyExtractor.GetKeys(after, tableDefinition) ?? new Dictionary <SnapshotRowKey, SnapshotRow>();
                if (!beforeRows.Keys.SequenceEqual(afterRows.Keys))
                {
                    return(false); //snapshots have row difference
                }
                foreach (var snapshotRowKey in beforeRows.Keys)
                {
                    var beforeRow = beforeRows[snapshotRowKey];
                    var afterRow  = afterRows[snapshotRowKey];
                    var match     = RowDataComparer.Compare(tableDefinition, snapshotRowKey, beforeRow, afterRow);
                    if (!match.Matched)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
 public void SetUp()
 {
     _collection = new SnapshotCollection();
     _collection.DefineTable(TableName).PrimaryKey(IdCol).PrimaryKey(NameCol);
     _tableDef        = _collection.GetTableDefinition(TableName);
     _snapshotBuilder = _collection.NewSnapshot("Test");
 }
예제 #4
0
        public void SnapshotRowsInMissingTablesAreNull()
        {
            //Arrange
            var snapshots = new SnapshotCollection(GetType(), t => t != typeof(Snapshots.TestDefinitions.TableDef));

            snapshots.DefineTable("Customer")
            .PrimaryKey("Id")
            .CompareKey("Surname")
            .IsUnpredictable("Id");

            var builder    = snapshots.NewSnapshot("Before");
            var rowBuilder = builder.AddNewRow("Customer");

            rowBuilder["Id"]      = 1;
            rowBuilder["Surname"] = "surname";

            var snapshot = snapshots.GetSnapshot("Before");

            //Act
            var row    = snapshot.Rows("Customer").First();
            var result = snapshot.GetRow(new SnapshotRowKey(row, snapshots.GetTableDefinition("Customer")), "Wrong");

            //Assert
            result.Should().BeNull();
        }
예제 #5
0
 public void SetUp()
 {
     _collection = new SnapshotCollection();
     _collection.DefineTable("Test").CompareKey("Key");
     _snapshot = _collection.NewSnapshot("TestSnapshot");
     _row      = _snapshot.AddNewRow("Test");
 }
예제 #6
0
        public void ReportChangesThrowsWhenAfterSnapshotNotPresent()
        {
            //Arrange/Act
            var snapshots = new SnapshotCollection(GetType(), t => t != typeof(Snapshots.TestDefinitions.TableDef));

            snapshots.DefineTable("Customer")
            .PrimaryKey("Id")
            .CompareKey("Surname")
            .IsUnpredictable("Id");

            var customers = new[]
            {
                new { Id = 1, Surname = "S1", FirstName = "F1", Age = 40 },
            };
            var builder = snapshots.NewSnapshot("Before");

            customers.ToSnapshotTable(builder, "Customer");

            var output = new Output();

            //Assert
            Action action = () => snapshots.ReportChanges("Before", "After", output);

            action.Should().Throw <SnapshotNotFoundException>().Where(x => x.SnapshotName == "After");
        }
예제 #7
0
        public static void Define(SnapshotCollection collection, SchemaStructure schema)
        {
            foreach (var table in schema.Tables)
            {
                var tableDef = collection.DefineTable(table.Name);
                foreach (var column in table.Columns.Where(c => c.InPrimaryKey))
                {
                    tableDef.PrimaryKey(column.Name);
                    if (column.IsUnpredictable)
                    {
                        tableDef.IsUnpredictable(column.Name);
                    }

                    if (column.IsUtcDateTime)
                    {
                        tableDef.Utc(column.Name);
                    }

                    if (column.IsLocalDateTime)
                    {
                        tableDef.Local(column.Name);
                    }
                }

                foreach (var reference in table.References)
                {
                    tableDef.IsReference(reference.ReferencingColumnNames.First(), $"[{reference.ReferencedSchema}].[{reference.ReferencedTable}]", reference.ReferencedColumnNames.First());
                }
            }
        }
예제 #8
0
        /// <summary>
        /// Scan the differences in a set of table <see cref="SnapshotTableDifferences"/> for columns flagged as referencing rows in the snapshot. If the
        /// referenced row is present, but does not contain any differences, it will be returned as an additional reference. This method reads the differences,
        /// but will not make any changes.
        /// </summary>
        /// <param name="collection">The snapshot collection. Needed for table definitions.</param>
        /// <param name="tableDiffs">The difference set that will be analysed</param>
        /// <returns>An <see cref="AdditionalReferencedRows"/> instance containing the referenced row details. Only rows not currently in the difference set
        /// will be included.</returns>
        public static AdditionalReferencedRows GetMissingRows(SnapshotCollection collection, IReadOnlyCollection <SnapshotTableDifferences> tableDiffs)
        {
            var allKeysByReferencedTable = GeyKeysByReferencedTable(collection, tableDiffs)
                                           .Where(rk => rk.KeyValue != null)
                                           .GroupBy(rk => new { rk.ReferencedTableDefinition.TableName, rk.ColumnName })
                                           .ToList();

            var requiredTableNotPresent = allKeysByReferencedTable
                                          .Where(g => !tableDiffs.Any(td => td.TableDefinition.TableName == g.Key.TableName))
                                          .ToList();

            var missingKeys = allKeysByReferencedTable.Join(tableDiffs, kg => kg.Key.TableName, td => td.TableDefinition.TableName,
                                                            (kg, td) => new
            {
                TableDefinition = kg.Key.TableName,
                KeyField        = kg.Key.ColumnName,
                MissingRows     = kg.Where(k => !td.RowDifferences.Any(row => IsMatchByKeyValue(row, k)))
                                  .Select(k => k.KeyValue).ToList()
            })
                              .Concat(requiredTableNotPresent.Select(r => new
            {
                TableDefinition = r.Key.TableName,
                KeyField        = r.Key.ColumnName,
                MissingRows     = allKeysByReferencedTable.Where(g => g.Key.TableName == r.Key.TableName)
                                  .SelectMany(g => g.Select(k => k.KeyValue))
                                  .ToList()
            }))
                              .GroupBy(req => req.TableDefinition)
                              .Select(g => new AdditionalReferencedRows.RequiredTableRows(collection.GetTableDefinition(g.Key), g.SelectMany(r => r.MissingRows.Select(mr => new AdditionalReferencedRows.RowRequest(r.KeyField, mr))).ToList()))
                              .ToList();

            return(new AdditionalReferencedRows(missingKeys));
        }
 internal TestData()
 {
     _collection = new SnapshotCollection();
     Definer     = _collection.DefineTable(TableName);
     Builder     = _collection.NewSnapshot("Test");
     Snapshot    = _collection.GetSnapshot("Test");
     NewRow();
 }
예제 #10
0
        internal static SnapshotDifferences ExtractDifferences(SnapshotCollection collection, Snapshot before, Snapshot after, ChangeReportOptions changeReportOptions = ChangeReportOptions.Default)
        {
            var tableDiffs = SnapshotDifferenceCalculator.GetDifferences(collection, before, after);

            tableDiffs = SnapshotDifferenceSorter.SortDifferences(collection, tableDiffs);
            tableDiffs = DifferenceRegulator.CleanDifferences(collection, tableDiffs, before, (changeReportOptions & ChangeReportOptions.NoSubs) == 0);
            return(new SnapshotDifferences(tableDiffs));
        }
예제 #11
0
 public static List <SnapshotTableDifferences> GetDifferences(SnapshotCollection collection, Snapshot before, Snapshot after)
 {
     return(collection
            .TablesInDefinitionOrder
            .Select(t => GetTableDifferences(t, before, after))
            .Where(t => t != null)
            .ToList());
 }
예제 #12
0
        public void InitTimeIsSet()
        {
            //Arrange/Act
            var start     = DateTime.UtcNow;
            var snapshots = new SnapshotCollection();

            //Assert
            snapshots.InitialisationTime.Ticks.Should().BeGreaterOrEqualTo(start.Ticks);
        }
예제 #13
0
 public static List <ISubstitutableValueTracker> Make(ColumnValueSet columnValueSet,
                                                      SnapshotCollection snapshotCollection)
 {
     return(new List <ISubstitutableValueTracker>
     {
         new DateTimeValueTracker(columnValueSet.Column, TimeRangeExtractor.Extract(snapshotCollection)),
         new DefaultValueTracker(columnValueSet.Column.Name)
     });
 }
        public void DateDiagnosticsAreReported()
        {
            //Arrange
            var collection = new SnapshotCollection();

            var beforeDates = new[]
            {
                DateTime.Parse("2020-10-11 10:35"),
                DateTime.Parse("2020-10-11 10:36"),
                DateTime.Parse("2020-10-11 10:37"),
                DateTime.Parse("2020-10-11 10:38"),
            };

            var afterDates = new[]
            {
                DateTime.Parse("2020-10-11 10:35"),
                DateTime.Parse("2020-10-11 10:36"),
                DateTime.Parse("2020-10-11 10:39"),
                DateTime.Parse("2020-10-11 10:40"),
                DateTime.Parse("2020-10-11 10:41"),
            };

            var beforeBuilder = collection.NewSnapshot("before");

            collection.DefineTable("Dates").PrimaryKey("Key").IsUnpredictable("Date");

            beforeDates.Select((bd, ix) => new { Key = ix, Date = bd, Other = "o", OtherDate = DateTime.MinValue }).ToSnapshotTable(beforeBuilder, "Dates");
            var deleteRow = beforeBuilder.AddNewRow("Dates");

            deleteRow["Key"]       = 100;
            deleteRow["Date"]      = DateTime.Parse("2020-10-18 11:19");
            deleteRow["Other"]     = "o";
            deleteRow["OtherDate"] = DateTime.MinValue;

            var afterBuilder = collection.NewSnapshot("after");

            afterDates.Select((bd, ix) => new { Key = ix, Date = bd, Other = "a", OtherDate = DateTime.MaxValue }).ToSnapshotTable(afterBuilder, "Dates");

            var before      = collection.GetSnapshot("before");
            var after       = collection.GetSnapshot("after");
            var differences = SnapshotDifferenceAnalyser.ExtractDifferences(collection, before, after);

            var output = new Output();

            //Act
            var ranges = new List <NamedTimeRange>
            {
                new NamedTimeRange(beforeDates[0], beforeDates[3], "before"),
                new NamedTimeRange(afterDates[2], afterDates[3], "after"),
            };

            DateDiagnosticReporter.Report(output, ranges, before, after, differences);

            //Assert
            output.Report.Verify();
        }
예제 #15
0
        public void TableDefinitionsAreFilteredLoadedFromAssembly()
        {
            //Arrange/Act
            var snapshots = new SnapshotCollection(GetType().Assembly, t => t != typeof(Snapshots.TestDefinitions.TableDef));

            //Assert
            var output = new Output();

            snapshots.GetSchemaReport(output);
            output.Report.Verify();
        }
예제 #16
0
        public void TableDefinitionsAreLoadedFromType()
        {
            //Arrange/Act
            var snapshots = new SnapshotCollection(GetType());

            //Assert
            var output = new Output();

            snapshots.GetSchemaReport(output);
            output.Report.Verify();
        }
        public async Task <(object Snapshot, long Index)> GetSnapshotAsync(string actorName)
        {
            var sort = Builders <Snapshot> .Sort.Descending("snapshotIndex");

            var snapshot = await SnapshotCollection
                           .Find(s => s.ActorName == actorName)
                           .Sort(sort)
                           .FirstOrDefaultAsync();

            return(snapshot != null ? (snapshot.Data, snapshot.SnapshotIndex) : (null, 0));
        }
예제 #18
0
        public void InitTimeIsSetUsingTimeSource()
        {
            //Arrange
            var time      = DateTime.Parse("2020-09-19 19:53:01");
            var snapshots = new SnapshotCollection();

            //Act
            snapshots.SetTimeSource(new FakeTimeSource(time));

            //Assert
            snapshots.InitialisationTime.Should().Be(time);
        }
        public IEnumerable <SnapshotCollection> GetSnapshots(SourceUrl sourceUrl)
        {
            var result = new List <SnapshotCollection>();

            if (!_isConfigured)
            {
                return(result);
            }
            foreach (var item in (IEnumerable)JsonConvert.DeserializeObject(new WebClient().DownloadString(String.Format("{0}{1}{2}",
                                                                                                                         sourceUrl.Url,
                                                                                                                         "contents.php",
                                                                                                                         !String.IsNullOrEmpty(sourceUrl.GroupId) ? String.Format("?gid={0}", sourceUrl.GroupId) : String.Empty))))
            {
                var       i   = 0;
                JProperty tmp = null;
                foreach (var m in (IEnumerable)item)
                {
                    switch (i)
                    {
                    case 0:
                        tmp = (m as JProperty); i++;
                        break;

                    case 1:
                        var snapshotName = tmp != null ? (String)tmp.Value : String.Empty;
                        var s            = new SnapshotCollection(snapshotName);
                        if (m != null)
                        {
                            foreach (var property in ((IEnumerable)m).OfType <JArray>())
                            {
                                foreach (var ss in property.Select(prop => (String)prop).Where(ss => !String.IsNullOrEmpty(ss)))
                                {
                                    s.Screenshots.Add(new SnapshotItem(ss.Replace(s.Name, String.Empty), String.Format("{0}{1}/{2}/", sourceUrl.Url, s.Name, ss)));
                                }
                                break;
                            }
                        }

                        if (s.Screenshots.Any())
                        {
                            result.Add(s);
                        }
                        break;
                    }
                    if (i > 1)
                    {
                        break;                         // Next
                    }
                }
            }
            return(result);
        }
        public static List <SnapshotTableDifferences> Refine(SnapshotCollection collection, List <SnapshotTableDifferences> tableDiffs, bool performSubstitution)
        {
            var unpredictableValues = UnpredictableColumnLocator.Locate(tableDiffs.Select(td => td.TableDefinition).ToList())
                                      .SelectMany(u => UnpredictableValueScanner.Scan(u, tableDiffs))
                                      .ToList();

            if (performSubstitution)
            {
                return(ValueSubstituter.Substitute(unpredictableValues, tableDiffs, collection));
            }

            return(tableDiffs);
        }
예제 #21
0
        public void BasicTableStructureIsLoaded()
        {
            //Arrange
            var collection = new SnapshotCollection();

            //Act
            SnapshotTableDefiner.Define(collection, _schema);

            //Assert
            var output = new Output();

            collection.GetSchemaReport(output, true);
            output.Report.Verify();
        }
예제 #22
0
        internal static List <NamedTimeRange> Extract(SnapshotCollection collection)
        {
            var start = collection.InitialisationTime;

            return(collection
                   .GetSnapshots()
                   .Select(s =>
            {
                var snapshotEnd = s.SnapshotTimestamp;
                var range = new NamedTimeRange(start, snapshotEnd, s.Name);
                start = snapshotEnd;
                return range;
            }).ToList());
        }
예제 #23
0
        public void SubstitutionsCanBeDisabledInDiffReports()
        {
            //Arrange
            var snapshots = new SnapshotCollection();

            snapshots.DefineTable("Customer")
            .PrimaryKey("Id")
            .CompareKey("Surname")
            .IsUnpredictable("Id");
            snapshots.DefineTable("Address")
            .PrimaryKey("AddressId")
            .IsUnpredictable("AddressId")
            .IsReference("CustomerId", "Customer", "Id");

            var customers = new[]
            {
                new { Id = 1, Surname = "S1", FirstName = "F1", Age = 40 },
                new { Id = 2, Surname = "S2", FirstName = "F2", Age = 45 },
                new { Id = 3, Surname = "S3", FirstName = "F3", Age = 50 },
            };

            var addresses = new[]
            {
                new { AddressId = 102, CustomerId = 1, House = 15, Street = "Line 1", PostCode = "code1" },
                new { AddressId = 193, CustomerId = 2, House = 99, Street = "Line 2", PostCode = "code2" },
                new { AddressId = 6985, CustomerId = 3, House = 8000, Street = "Line 3", PostCode = "code3" }
            };

            {
                var builder = snapshots.NewSnapshot("Before");
                customers.ToSnapshotTable(builder, "Customer");
                addresses.ToSnapshotTable(builder, "Address");
            }

            customers[1] = new { Id = 2, Surname = "S2", FirstName = "F2Edited", Age = 32 };
            addresses[2] = new { AddressId = 6985, CustomerId = 2, House = 8001, Street = "Line 3", PostCode = "code3" };

            {
                var builder2 = snapshots.NewSnapshot("After");
                customers.ToSnapshotTable(builder2, "Customer");
                addresses.ToSnapshotTable(builder2, "Address");
            }

            //Act/Assert
            var output = new Output();

            snapshots.ReportChanges("Before", "After", output, ChangeReportOptions.NoSubs);
            output.Report.Verify();
        }
예제 #24
0
        internal static List <SnapshotTableDifferences> ExpandDifferences(SnapshotCollection collection, List <SnapshotTableDifferences> tableDiffs, Snapshot before)
        {
            var rows = ReferencedRowLocator.GetMissingRows(collection, tableDiffs);

            tableDiffs = DifferenceEnhancer.RequireRows(collection, tableDiffs, rows, before);
            var mandatoryFields = MandatoryColumnFinder.Find(collection, tableDiffs);

            foreach (var tableColumnRequest in mandatoryFields)
            {
                tableDiffs = DifferenceColumnAdder.RequireColumns(collection, tableDiffs, tableColumnRequest.TableDefinition,
                                                                  tableColumnRequest.Columns, before);
            }

            return(tableDiffs);
        }
        public void SetUp()
        {
            _collection = new SnapshotCollection();
            _collection.DefineTable(TestTableName).CompareKey("Id");
            _table    = _collection.GetTableDefinition(TestTableName);
            _snapshot = _collection.NewSnapshot("Test");

            //Borrow a column config so that we can test with it.
            void ExtractColumnDefForTest(ColumnConfig config)
            {
                _cc = config;
            }

            var report = new[] { "T" }.AsReport(rep => rep.AddColumn(t => t, ExtractColumnDefForTest));
        }
예제 #26
0
        public void TableDefinitionsCanBeApplied()
        {
            //Arrange
            var definitionSet = SnapshotDefinitionLoader.Load(GetType());
            var snapshots     = new SnapshotCollection();

            //Act
            snapshots.ApplyDefinitions(definitionSet);

            //Assert
            var output = new Output();

            snapshots.GetSchemaReport(output, true);
            output.Report.Verify();
        }
예제 #27
0
        public void GetSnapshotReturnsTheRequestedSnapshot()
        {
            //Arrange/Act
            var snapshots = new SnapshotCollection(GetType(), t => t != typeof(Snapshots.TestDefinitions.TableDef));

            snapshots.DefineTable("Customer")
            .PrimaryKey("Id")
            .CompareKey("Surname")
            .IsUnpredictable("Id");

            var builder = snapshots.NewSnapshot("Before");

            //Assert
            snapshots.GetSnapshot("Before").Name.Should().Be("Before");
        }
예제 #28
0
        public void TablesAreDefined()
        {
            //Arrange
            var snapshots = new SnapshotCollection();

            //Act
            snapshots.DefineTable("Customer").PrimaryKey("Id").CompareKey("Surname");
            snapshots.DefineTable("Address").PrimaryKey("AddressId");

            //Assert
            var output = new Output();

            snapshots.GetSchemaReport(output);
            output.Report.Verify();
        }
예제 #29
0
        public void SubstitutionsCanBeSuppressed()
        {
            //Arrange
            var collection = new SnapshotCollection();

            collection.DefineTable("TheTable")
            .PrimaryKey("Id")
            .IsUnpredictable("Id");

            void AddRow(SnapshotBuilder snapshot, int id, string name)
            {
                var add = snapshot.AddNewRow("TheTable");

                add["Id"]   = id;
                add["Name"] = name;
            }

            void AddData(SnapshotBuilder snapshot, string names)
            {
                var id = 1;

                foreach (var name in names.Split(','))
                {
                    AddRow(snapshot, id++, name);
                }
            }

            var beforeBuilder = collection.NewSnapshot("Before");

            AddData(beforeBuilder, "A,B,C");

            var afterBuilder = collection.NewSnapshot("After");

            AddData(afterBuilder, "D,E,F");

            var before = collection.GetSnapshot("Before");
            var after  = collection.GetSnapshot("After");
            var diffs  = SnapshotDifferenceAnalyser.ExtractDifferences(collection, before, after, ChangeReportOptions.NoSubs);

            //Act
            var result = SnapshotDifferenceSorter.SortDifferences(collection, diffs.TableDifferences.ToList());

            //Assert
            var output = new Output();

            result.Report(output);
            output.Report.Verify();
        }
예제 #30
0
        public void SnapshotThrowsWhenUndefinedTableUsed()
        {
            //Arrange/Act
            var snapshots = new SnapshotCollection(GetType(), t => t != typeof(Snapshots.TestDefinitions.TableDef));

            snapshots.DefineTable("Customer")
            .PrimaryKey("Id")
            .CompareKey("Surname")
            .IsUnpredictable("Id");

            var builder = snapshots.NewSnapshot("Before");

            //Assert
            Action action = () => builder.AddNewRow("Wrong");

            action.Should().Throw <UndefinedTableInSnapshotException>().Where(x => x.TableName == "Wrong");
        }