public async Task CanExportAndImportAttachmentsAndRevisionAttachments()
        {
            var file = Path.GetTempFileName();

            try
            {
                using (var store1 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store1"
                }))
                {
                    await SetDatabaseId(store1, new Guid("00000000-48c4-421e-9466-000000000000"));

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, false, 4);

                    AttachmentsRevisions.CreateDocumentWithAttachments(store1);
                    using (var bigStream = new MemoryStream(Enumerable.Range(1, 999 * 1024).Select(x => (byte)x).ToArray()))
                        store1.Operations.Send(new PutAttachmentOperation("users/1", "big-file", bigStream, "image/png"));

                    /*var result = */
                    await store1.Smuggler.ExportAsync(new DatabaseSmugglerExportOptions(), file);

                    // TODO: RavenDB-6936 store.Smuggler.Export and Import method should return the SmugglerResult

                    var stats = await store1.Maintenance.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(1, stats.CountOfDocuments);
                    Assert.Equal(4, stats.CountOfRevisionDocuments);
                    Assert.Equal(14, stats.CountOfAttachments);
                    Assert.Equal(4, stats.CountOfUniqueAttachments);
                }

                using (var store2 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store2"
                }))
                {
                    var dbId = new Guid("00000000-48c4-421e-9466-000000000000");
                    await SetDatabaseId(store2, dbId);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database);

                    for (var i = 0; i < 2; i++) // Make sure that we can import attachments twice and it will overwrite
                    {
                        await store2.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions(), file);

                        var stats = await store2.Maintenance.SendAsync(new GetStatisticsOperation());

                        Assert.Equal(1, stats.CountOfDocuments);
                        Assert.Equal(5, stats.CountOfRevisionDocuments);
                        Assert.Equal(14, stats.CountOfAttachments);
                        Assert.Equal(4, stats.CountOfUniqueAttachments);

                        using (var session = store2.OpenSession())
                        {
                            var readBuffer = new byte[1024 * 1024];
                            using (var attachmentStream = new MemoryStream(readBuffer))
                                using (var attachment = session.Advanced.Attachments.Get("users/1", "big-file"))
                                {
                                    attachment.Stream.CopyTo(attachmentStream);
                                    Assert.Contains("A:" + (2 + 20 * i), attachment.Details.ChangeVector);
                                    Assert.Equal("big-file", attachment.Details.Name);
                                    Assert.Equal("zKHiLyLNRBZti9DYbzuqZ/EDWAFMgOXB+SwKvjPAINk=", attachment.Details.Hash);
                                    Assert.Equal(999 * 1024, attachmentStream.Position);
                                    Assert.Equal(Enumerable.Range(1, 999 * 1024).Select(x => (byte)x), readBuffer.Take((int)attachmentStream.Position));
                                }
                        }
                    }
                }
            }
            finally
            {
                File.Delete(file);
            }
        }
        public async Task RevertResolvedConflictByLocalToDeleted()
        {
            // deleted was at 8:50
            // conflict at 9:10
            // resolved at 9:15
            // will revert to 9:00

            using (var store1 = GetDocumentStore())
                using (var store2 = GetDocumentStore())
                {
                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database);

                    DateTime last = default;

                    using (var session = store2.OpenAsyncSession())
                    {
                        var company = new Person
                        {
                            Name = "Name2"
                        };
                        await session.StoreAsync(company, "foo/bar");

                        await session.SaveChangesAsync();


                        await session.StoreAsync(new Company(), "marker");

                        await session.SaveChangesAsync();
                    }

                    using (var session = store1.OpenAsyncSession())
                    {
                        var company = new Person
                        {
                            Name = "Name1"
                        };
                        await session.StoreAsync(company, "foo/bar");

                        await session.SaveChangesAsync();

                        session.Delete("foo/bar");
                        await session.SaveChangesAsync();

                        var companiesRevisions = await session.Advanced.Revisions.GetForAsync <Person>("foo/bar");

                        Assert.Equal(2, companiesRevisions.Count);

                        last = DateTime.UtcNow;
                    }

                    await SetupReplicationAsync(store2, store1);

                    WaitForDocument(store1, "marker");

                    using (var session = store1.OpenAsyncSession())
                    {
                        var companiesRevisions = await session.Advanced.Revisions.GetForAsync <Person>("foo/bar");

                        Assert.Equal(4, companiesRevisions.Count);
                    }

                    var db = await GetDocumentDatabaseInstanceFor(store1);

                    RevertResult result;
                    using (var token = new OperationCancelToken(db.Configuration.Databases.OperationTimeout.AsTimeSpan, db.DatabaseShutdown, CancellationToken.None))
                    {
                        result = (RevertResult)await db.DocumentsStorage.RevisionsStorage.RevertRevisions(last, TimeSpan.FromMinutes(60), onProgress : null,
                                                                                                          token : token);
                    }

                    Assert.Equal(5, result.ScannedRevisions);
                    Assert.Equal(2, result.ScannedDocuments);
                    Assert.Equal(1, result.RevertedDocuments);

                    using (var session = store1.OpenAsyncSession())
                    {
                        var persons = await session.Advanced.Revisions.GetForAsync <Person>("foo/bar");

                        Assert.Equal(5, persons.Count);

                        Assert.Equal(null, persons[0].Name);
                        var metadata = session.Advanced.GetMetadataFor(persons[0]);
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.DeleteRevision | DocumentFlags.Reverted).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));

                        Assert.Equal(null, persons[1].Name);
                        metadata = session.Advanced.GetMetadataFor(persons[1]);
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.DeleteRevision | DocumentFlags.Resolved).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));

                        Assert.Equal(null, persons[2].Name);
                        metadata = session.Advanced.GetMetadataFor(persons[2]);
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.DeleteRevision | DocumentFlags.Conflicted).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));

                        Assert.Equal("Name2", persons[3].Name);
                        metadata = session.Advanced.GetMetadataFor(persons[3]);
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.Revision | DocumentFlags.FromReplication | DocumentFlags.Conflicted).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));

                        Assert.Equal("Name1", persons[4].Name);
                        metadata = session.Advanced.GetMetadataFor(persons[4]);
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.Revision).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));
                    }
                }
        }
        public async Task ExportEmptyStream()
        {
            var file = Path.GetTempFileName();

            try
            {
                var dbId2 = new Guid("99999999-48c4-421e-9466-999999999999");
                var dbId  = new Guid("00000000-48c4-421e-9466-000000000000");

                using (var store1 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store1"
                }))
                {
                    await SetDatabaseId(store1, dbId);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, false, 4);

                    using (var session = store1.OpenSession())
                    {
                        session.Store(new User {
                            Name = "Fitzchak"
                        }, "users/1");
                        session.SaveChanges();
                    }
                    using (var emptyStream = new MemoryStream(new byte[0]))
                    {
                        var result = store1.Operations.Send(new PutAttachmentOperation("users/1", "empty-file", emptyStream, "image/png"));
                        Assert.Equal("A:3", result.ChangeVector.Substring(0, 3));
                        Assert.Equal("empty-file", result.Name);
                        Assert.Equal("users/1", result.DocumentId);
                        Assert.Equal("image/png", result.ContentType);
                        Assert.Equal("DldRwCblQ7Loqy6wYJnaodHl30d3j3eH+qtFzfEv46g=", result.Hash);
                        Assert.Equal(0, result.Size);
                    }

                    await store1.Smuggler.ExportAsync(new DatabaseSmugglerExportOptions(), file);

                    var stats = await store1.Maintenance.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(1, stats.CountOfDocuments);
                    Assert.Equal(2, stats.CountOfRevisionDocuments);
                    Assert.Equal(2, stats.CountOfAttachments);
                    Assert.Equal(1, stats.CountOfUniqueAttachments);
                }

                using (var store2 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store2"
                }))
                {
                    await SetDatabaseId(store2, dbId2);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database);

                    await store2.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions(), file);

                    var stats = await store2.Maintenance.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(1, stats.CountOfDocuments);
                    Assert.Equal(3, stats.CountOfRevisionDocuments);
                    Assert.Equal(2, stats.CountOfAttachments);
                    Assert.Equal(1, stats.CountOfUniqueAttachments);

                    using (var session = store2.OpenSession())
                    {
                        var readBuffer = new byte[1024 * 1024];
                        using (var attachmentStream = new MemoryStream(readBuffer))
                            using (var attachment = session.Advanced.Attachments.Get("users/1", "empty-file"))
                            {
                                attachment.Stream.CopyTo(attachmentStream);
                                Assert.Contains("A:1", attachment.Details.ChangeVector);
                                Assert.Equal("empty-file", attachment.Details.Name);
                                Assert.Equal(0, attachment.Details.Size);
                                Assert.Equal("DldRwCblQ7Loqy6wYJnaodHl30d3j3eH+qtFzfEv46g=", attachment.Details.Hash);
                                Assert.Equal(0, attachmentStream.Position);
                                Assert.Equal(new byte[0], readBuffer.Take((int)attachmentStream.Position));
                            }
                    }
                }
            }
            finally
            {
                File.Delete(file);
            }
        }
        public async Task RevertRevisionOutsideTheWindow()
        {
            var company = new Company {
                Name = "Company Name"
            };

            using (var store = GetDocumentStore())
            {
                await RevisionsHelper.SetupRevisions(Server.ServerStore, store.Database);

                using (var session = store.OpenAsyncSession())
                {
                    await session.StoreAsync(company);

                    await session.SaveChangesAsync();
                }

                await Task.Delay(2000);

                using (var session = store.OpenAsyncSession())
                {
                    company.Name = "Hibernating Rhinos";
                    await session.StoreAsync(company);

                    await session.SaveChangesAsync();
                }

                await Task.Delay(5000);

                DateTime last = DateTime.UtcNow;
                last = last.AddSeconds(-3);

                using (var session = store.OpenAsyncSession())
                {
                    company.Name = "Hibernating Rhinos 2";
                    await session.StoreAsync(company);

                    await session.SaveChangesAsync();
                }

                await Task.Delay(2000);

                var db = await GetDocumentDatabaseInstanceFor(store);

                RevertResult result;
                using (var token = new OperationCancelToken(db.Configuration.Databases.OperationTimeout.AsTimeSpan, db.DatabaseShutdown, CancellationToken.None))
                {
                    result = (RevertResult)await db.DocumentsStorage.RevisionsStorage.RevertRevisions(last, TimeSpan.FromSeconds(1), onProgress : null,
                                                                                                      token : token);
                }

                Assert.Equal(3, result.ScannedRevisions);
                Assert.Equal(1, result.ScannedDocuments);
                Assert.Equal(1, result.RevertedDocuments);

                using (var session = store.OpenAsyncSession())
                {
                    var companiesRevisions = await session.Advanced.Revisions.GetForAsync <Company>(company.Id);

                    Assert.Equal(4, companiesRevisions.Count);

                    Assert.Equal("Hibernating Rhinos", companiesRevisions[0].Name);
                    Assert.Equal("Hibernating Rhinos 2", companiesRevisions[1].Name);
                    Assert.Equal("Hibernating Rhinos", companiesRevisions[2].Name);
                    Assert.Equal("Company Name", companiesRevisions[3].Name);
                }
            }
        }
        public async Task DontRevertToConflicted()
        {
            // put at 8:30
            // conflicted at 8:50
            // resolved at 9:10
            // will revert to 9:00

            using (var store1 = GetDocumentStore(options: new Options
            {
                ModifyDatabaseRecord = record =>
                {
                    record.ConflictSolverConfig = new ConflictSolver
                    {
                        ResolveToLatest = false,
                        ResolveByCollection = new Dictionary <string, ScriptResolver>()
                    };
                }
            }))
                using (var store2 = GetDocumentStore())
                {
                    DateTime last = default;
                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database);

                    using (var session = store2.OpenAsyncSession())
                    {
                        await session.StoreAsync(new Company(), "keep-conflicted-revision-insert-order");

                        await session.SaveChangesAsync();

                        var company = new Company
                        {
                            Name = "Name2"
                        };
                        await session.StoreAsync(company, "foo/bar");

                        await session.SaveChangesAsync();
                    }

                    using (var session = store1.OpenAsyncSession())
                    {
                        var company = new Company
                        {
                            Name = "Name1"
                        };
                        await session.StoreAsync(company, "foo/bar");

                        await session.SaveChangesAsync();

                        var companiesRevisions = await session.Advanced.Revisions.GetForAsync <Company>("foo/bar");

                        Assert.Equal(1, companiesRevisions.Count);
                    }

                    await SetupReplicationAsync(store2, store1);

                    WaitUntilHasConflict(store1, "foo/bar");

                    last = DateTime.UtcNow;

                    using (var session = store1.OpenAsyncSession())
                    {
                        var company = new Company
                        {
                            Name = "Resolver"
                        };
                        await session.StoreAsync(company, "foo/bar");

                        await session.SaveChangesAsync();
                    }

                    var db = await GetDocumentDatabaseInstanceFor(store1);

                    RevertResult result;
                    using (var token = new OperationCancelToken(db.Configuration.Databases.OperationTimeout.AsTimeSpan, db.DatabaseShutdown, CancellationToken.None))
                    {
                        result = (RevertResult)await db.DocumentsStorage.RevisionsStorage.RevertRevisions(last.Add(TimeSpan.FromMinutes(1)), TimeSpan.FromMinutes(60),
                                                                                                          onProgress : null, token : token);
                    }

                    Assert.Equal(4, result.ScannedRevisions);
                    Assert.Equal(2, result.ScannedDocuments);
                    Assert.Equal(0, result.RevertedDocuments);

                    using (var session = store1.OpenAsyncSession())
                    {
                        var companiesRevisions = await session.Advanced.Revisions.GetForAsync <Company>("foo/bar");

                        Assert.Equal(3, companiesRevisions.Count);
                    }
                }
        }
        public async Task UpdateTheSameRevisionWhenGettingExistingRevision()
        {
            using (var storeA = GetDocumentStore(options: new Options
            {
                ModifyDatabaseRecord = record =>
                {
                    record.ConflictSolverConfig = new ConflictSolver
                    {
                        ResolveToLatest = false,
                        ResolveByCollection = new Dictionary <string, ScriptResolver>()
                    };
                }
            }))
                using (var storeB = GetDocumentStore(options: new Options
                {
                    ModifyDatabaseRecord = record =>
                    {
                        record.ConflictSolverConfig = new ConflictSolver
                        {
                            ResolveToLatest = false,
                            ResolveByCollection = new Dictionary <string, ScriptResolver>()
                        };
                    }
                }))
                    using (var storeC = GetDocumentStore(options: new Options
                    {
                        ModifyDatabaseRecord = record =>
                        {
                            record.ConflictSolverConfig = new ConflictSolver
                            {
                                ResolveToLatest = false,
                                ResolveByCollection = new Dictionary <string, ScriptResolver>()
                            };
                        }
                    }))
                    {
                        await RevisionsHelper.SetupRevisions(Server.ServerStore, storeA.Database);

                        await RevisionsHelper.SetupRevisions(Server.ServerStore, storeB.Database);

                        await RevisionsHelper.SetupRevisions(Server.ServerStore, storeC.Database);

                        await SetupReplicationAsync(storeA, storeB);

                        using (var session = storeA.OpenAsyncSession())
                        {
                            await session.StoreAsync(new User { Name = "Fitzchak" }, "users/1");

                            await session.SaveChangesAsync();
                        }
                        using (var session = storeA.OpenSession())
                        {
                            Assert.Equal(1, WaitForValue(() => session.Advanced.Revisions.GetMetadataFor("users/1").Count, 1));
                        }
                        using (var session = storeB.OpenSession())
                        {
                            Assert.Equal(1, WaitForValue(() => session.Advanced.Revisions.GetMetadataFor("users/1").Count, 1));
                        }
                        Assert.True(WaitForDocument(storeB, "users/1"));

                        await SetupReplicationAsync(storeA, storeC);
                        await SetupReplicationAsync(storeB, storeC);

                        using (var session = storeA.OpenAsyncSession())
                        {
                            await session.StoreAsync(new User { Name = "Marker" }, "marker");

                            await session.SaveChangesAsync();
                        }
                        Assert.True(WaitForDocument(storeC, "marker"));
                        using (var session = storeB.OpenAsyncSession())
                        {
                            await session.StoreAsync(new User { Name = "Marker" }, "marker");

                            await session.SaveChangesAsync();
                        }
                        Assert.True(WaitForDocument(storeB, "marker"));

                        using (var session = storeC.OpenSession())
                        {
                            Assert.Equal(1, WaitForValue(() => session.Advanced.Revisions.GetMetadataFor("users/1").Count, 1));
                        }
                    }
        }
Exemple #7
0
        public async Task GetRevisionsBinEntries(bool useSession)
        {
            using (var store1 = GetDocumentStore())
                using (var store2 = GetDocumentStore())
                {
                    var database = await GetDocumentDatabaseInstanceFor(store1);

                    var database2 = await GetDocumentDatabaseInstanceFor(store2);

                    database.DocumentTombstoneCleaner.Subscribe(this);
                    database2.DocumentTombstoneCleaner.Subscribe(this);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, false);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database, false);
                    await SetupReplicationAsync(store1, store2);

                    var deletedRevisions = await store1.Commands().GetRevisionsBinEntriesAsync(long.MaxValue);

                    Assert.Equal(0, deletedRevisions.Count);

                    var id = "users/1";
                    if (useSession)
                    {
                        var user = new User {
                            Name = "Fitzchak"
                        };
                        for (var i = 0; i < 2; i++)
                        {
                            using (var session = store1.OpenAsyncSession())
                            {
                                await session.StoreAsync(user);

                                await session.SaveChangesAsync();
                            }
                            using (var session = store1.OpenAsyncSession())
                            {
                                session.Delete(user.Id);
                                await session.SaveChangesAsync();
                            }
                        }
                        id += "-A";
                    }
                    else
                    {
                        await store1.Commands().PutAsync(id, null, new User {
                            Name = "Fitzchak"
                        });

                        await store1.Commands().DeleteAsync(id, null);

                        await store1.Commands().PutAsync(id, null, new User {
                            Name = "Fitzchak"
                        });

                        await store1.Commands().DeleteAsync(id, null);
                    }

                    WaitForMarker(store1, store2);
                    var statistics = store2.Maintenance.Send(new GetStatisticsOperation());
                    Assert.Equal(useSession ? 2 : 1, statistics.CountOfDocuments);
                    Assert.Equal(4, statistics.CountOfRevisionDocuments);

                    //sanity
                    deletedRevisions = await store1.Commands().GetRevisionsBinEntriesAsync(long.MaxValue);

                    Assert.Equal(1, deletedRevisions.Count);

                    deletedRevisions = await store2.Commands().GetRevisionsBinEntriesAsync(long.MaxValue);

                    Assert.Equal(1, deletedRevisions.Count);

                    using (var session = store2.OpenAsyncSession())
                    {
                        var users = await session.Advanced.Revisions.GetForAsync <User>(id);

                        Assert.Equal(4, users.Count);
                        Assert.Equal(null, users[0].Name);
                        Assert.Equal("Fitzchak", users[1].Name);
                        Assert.Equal(null, users[2].Name);
                        Assert.Equal("Fitzchak", users[3].Name);

                        // Can get metadata only
                        var revisionsMetadata = await session.Advanced.Revisions.GetMetadataForAsync(id);

                        Assert.Equal(4, revisionsMetadata.Count);
                        Assert.Equal((DocumentFlags.DeleteRevision | DocumentFlags.HasRevisions | DocumentFlags.FromReplication).ToString(), revisionsMetadata[0].GetString(Constants.Documents.Metadata.Flags));
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.Revision | DocumentFlags.FromReplication).ToString(), revisionsMetadata[1].GetString(Constants.Documents.Metadata.Flags));
                        Assert.Equal((DocumentFlags.DeleteRevision | DocumentFlags.HasRevisions | DocumentFlags.FromReplication).ToString(), revisionsMetadata[2].GetString(Constants.Documents.Metadata.Flags));
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.Revision | DocumentFlags.FromReplication).ToString(), revisionsMetadata[3].GetString(Constants.Documents.Metadata.Flags));
                    }

                    await store1.Maintenance.SendAsync(new RevisionsTests.DeleteRevisionsOperation(new AdminRevisionsHandler.Parameters
                    {
                        DocumentIds = new[] { id, "users/not/exists" }
                    }));

                    WaitForMarker(store1, store2);

                    statistics = store2.Maintenance.Send(new GetStatisticsOperation());
                    Assert.Equal(useSession ? 3 : 2, statistics.CountOfDocuments);

                    Assert.Equal(0, statistics.CountOfRevisionDocuments);
                }
        }
        public async Task ReplicateRevisionTombstones()
        {
            var revisionsAgeLimit = TimeSpan.FromSeconds(10);

            Action <RevisionsConfiguration> modifyConfiguration = configuration =>
                                                                  configuration.Collections["Users"] = new RevisionsCollectionConfiguration
            {
                Disabled = false,
                MinimumRevisionAgeToKeep = revisionsAgeLimit
            };

            using (var store1 = GetDocumentStore())
                using (var store2 = GetDocumentStore())
                {
                    //setup revisions on both stores and setup replication
                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, modifyConfiguration);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database, modifyConfiguration);

                    await SetupReplicationAsync(store1, store2);

                    // create some revisions on store1
                    using (var session = store1.OpenAsyncSession())
                    {
                        await session.StoreAsync(new User
                        {
                            Name = "Aviv"
                        }, "users/1-A");

                        await session.SaveChangesAsync();
                    }

                    for (int i = 2; i <= 10; i++)
                    {
                        using (var session = store1.OpenAsyncSession())
                        {
                            var user = await session.LoadAsync <User>("users/1-A");

                            user.Name = "Aviv" + i;
                            await session.SaveChangesAsync();
                        }
                    }

                    // wait for replication
                    WaitForMarker(store1, store2);

                    // wait until revisions are expired
                    await Task.Delay(revisionsAgeLimit);

                    // modify document
                    using (var session = store1.OpenAsyncSession())
                    {
                        var user = await session.LoadAsync <User>("users/1-A");

                        user.Name = "Grisha";
                        await session.SaveChangesAsync();
                    }

                    WaitForMarker(store1, store2);

                    // expired revisions should be deleted
                    // assert that both stores have 10 revision tombstones

                    foreach (var store in new [] { store1, store2 })
                    {
                        var documentDatabase = await GetDocumentDatabaseInstanceFor(store);

                        using (documentDatabase.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext ctx))
                            using (ctx.OpenReadTransaction())
                            {
                                var tombstones = documentDatabase.DocumentsStorage.GetTombstonesFrom(ctx, 0, 0, int.MaxValue).ToList();
                                Assert.Equal(10, tombstones.Count);

                                foreach (var tombstone in tombstones)
                                {
                                    Assert.Equal(Tombstone.TombstoneType.Revision, tombstone.Type);
                                }
                            }
                    }
                }
        }
        public async Task CanDeleteFromDifferentCollections()
        {
            using (var store = GetDocumentStore())
            {
                var storage = await Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database);

                await RevisionsHelper.SetupRevisions(Server.ServerStore, store.Database);

                using (var session = store.OpenSession())
                    using (var ms = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }))
                    {
                        session.Store(new User {
                            Name = "Karmel"
                        }, "foo/bar");
                        session.Advanced.Attachments.Store("foo/bar", "dummy", ms);
                        session.SaveChanges();
                    }

                using (var session = store.OpenSession())
                {
                    session.Delete("foo/bar");
                    session.SaveChanges();
                }

                using (var session = store.OpenSession())
                {
                    session.Store(new Company {
                        Name = "Karmel"
                    }, "foo/bar");
                    session.SaveChanges();
                }

                using (var session = store.OpenSession())
                {
                    session.Delete("foo/bar");
                    session.SaveChanges();
                }

                using (var session = store.OpenSession())
                    using (var ms = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }))
                    {
                        session.Store(new User {
                            Name = "Karmel"
                        }, "foo/bar");
                        session.Advanced.Attachments.Store("foo/bar", "dummy", ms);
                        session.SaveChanges();
                    }

                using (var session = store.OpenSession())
                {
                    session.Delete("foo/bar");
                    session.SaveChanges();
                }

                using (var session = store.OpenSession())
                {
                    session.Store(new Employee {
                        FirstName = "Karmel"
                    }, "foo/bar");
                    session.SaveChanges();
                }

                using (var session = store.OpenSession())
                {
                    session.Delete("foo/bar");
                    session.SaveChanges();
                }

                await storage.TombstoneCleaner.ExecuteCleanup();

                using (storage.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext ctx))
                    using (ctx.OpenReadTransaction())
                    {
                        Assert.Equal(0, storage.DocumentsStorage.GetNumberOfTombstones(ctx));
                    }
            }
        }
        public async Task ReplicateExpiredRevisions()
        {
            var revisionsAgeLimit = TimeSpan.FromSeconds(10);

            Action <RevisionsConfiguration> modifyConfiguration = configuration =>
                                                                  configuration.Collections["Users"] = new RevisionsCollectionConfiguration
            {
                Disabled = false,
                MinimumRevisionAgeToKeep = revisionsAgeLimit
            };

            using (var store1 = GetDocumentStore())
                using (var store2 = GetDocumentStore())
                {
                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, modifyConfiguration);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database, modifyConfiguration);

                    using (var session = store1.OpenAsyncSession())
                    {
                        await session.StoreAsync(new User
                        {
                            Name = "Aviv"
                        }, "users/1-A");

                        await session.SaveChangesAsync();
                    }

                    for (int i = 2; i <= 10; i++)
                    {
                        using (var session = store1.OpenAsyncSession())
                        {
                            var user = await session.LoadAsync <User>("users/1-A");

                            user.Name = "Aviv" + i;
                            await session.SaveChangesAsync();
                        }
                    }

                    using (var session = store1.OpenAsyncSession())
                    {
                        var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1-A");

                        Assert.Equal(10, revisions.Count);
                    }


                    // wait until revisions are expired
                    await Task.Delay(revisionsAgeLimit);

                    // setup replication
                    await SetupReplicationAsync(store1, store2);

                    WaitForMarker(store1, store2);

                    // store1 should still have 10 revisions
                    // store2 should have no revisions
                    using (var session = store1.OpenAsyncSession())
                    {
                        var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1-A");

                        Assert.Equal(10, revisions.Count);
                    }
                    using (var session = store2.OpenAsyncSession())
                    {
                        var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1-A");

                        Assert.Equal(0, revisions.Count);
                    }

/*
 *              // TODO : RavenDB-13359
 *              using (var session = store2.OpenAsyncSession())
 *              {
 *                  var doc = await session.LoadAsync<User>("users/1-A");
 *                  var md = session.Advanced.GetMetadataFor(doc);
 *                  md.TryGetValue(Constants.Documents.Metadata.Flags, out var flags);
 *
 *                  Assert.DoesNotContain(nameof(DocumentFlags.HasRevisions), flags);
 *              }
 */

                    // modify doc on store1 to create another revision
                    using (var session = store1.OpenAsyncSession())
                    {
                        var user = await session.LoadAsync <User>("users/1-A");

                        user.Name = "Grisha";
                        await session.SaveChangesAsync();
                    }

                    WaitForMarker(store1, store2);

                    // assert that both stores have just one revision
                    using (var session = store1.OpenAsyncSession())
                    {
                        var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1-A");

                        Assert.Equal(1, revisions.Count);
                        Assert.Equal("Grisha", revisions[0].Name);
                    }
                    using (var session = store2.OpenAsyncSession())
                    {
                        var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1-A");

                        Assert.Equal(1, revisions.Count);
                        Assert.Equal("Grisha", revisions[0].Name);
                    }
                }
        }
        public async Task ReplicateExpiredAndDeletedRevisions()
        {
            var revisionsAgeLimit = TimeSpan.FromSeconds(10);

            Action <RevisionsConfiguration> modifyConfiguration = configuration =>
                                                                  configuration.Collections["Users"] = new RevisionsCollectionConfiguration
            {
                Disabled = false,
                MinimumRevisionAgeToKeep = revisionsAgeLimit
            };

            using (var store1 = GetDocumentStore())
                using (var store2 = GetDocumentStore())
                {
                    //setup revisions on both stores and setup replication
                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, modifyConfiguration);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database, modifyConfiguration);
                    await SetupReplicationAsync(store1, store2);

                    // create some revisions on store1
                    using (var session = store1.OpenAsyncSession())
                    {
                        await session.StoreAsync(new User
                        {
                            Name = "Aviv"
                        }, "users/1-A");

                        await session.SaveChangesAsync();
                    }

                    for (int i = 2; i <= 10; i++)
                    {
                        using (var session = store1.OpenAsyncSession())
                        {
                            var user = await session.LoadAsync <User>("users/1-A");

                            user.Name = "Aviv" + i;
                            await session.SaveChangesAsync();
                        }
                    }

                    // wait for replication
                    WaitForMarker(store1, store2);

                    using (var session = store2.OpenAsyncSession())
                    {
                        var doc = await session.LoadAsync <User>("users/1-A");

                        Assert.Equal("Aviv10", doc.Name);
                    }

                    // wait until revisions are expired
                    await Task.Delay(revisionsAgeLimit);

                    // modify document
                    using (var session = store1.OpenAsyncSession())
                    {
                        var user = await session.LoadAsync <User>("users/1-A");

                        user.Name = "Grisha";
                        await session.SaveChangesAsync();
                    }

                    WaitForMarker(store1, store2);

                    // expired revisions should be deleted
                    // assert that both stores have just one revision now
                    using (var session = store1.OpenAsyncSession())
                    {
                        var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1-A");

                        Assert.Equal(1, revisions.Count);
                        Assert.Equal("Grisha", revisions[0].Name);
                    }
                    using (var session = store2.OpenAsyncSession())
                    {
                        var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1-A");

                        Assert.Equal(1, revisions.Count);
                        Assert.Equal("Grisha", revisions[0].Name);
                    }
                }
        }
Exemple #12
0
        public async Task CanGetRevisionsByDate()
        {
            using (var store = GetDocumentStore())
            {
                var id = "users/1";
                await RevisionsHelper.SetupRevisions(Server.ServerStore, store.Database,
                                                     modifyConfiguration : conf => conf.Default.MinimumRevisionsToKeep = 1000);

                using (var session = store.OpenAsyncSession())
                {
                    await session.StoreAsync(new Company { Name = "Fitzchak" }, id);

                    await session.SaveChangesAsync();
                }

                var db = await GetDocumentDatabaseInstanceFor(store);

                var fst = db.Time.GetUtcNow();

                db.Time.UtcDateTime = () => DateTime.UtcNow.AddMinutes(5);

                for (int i = 0; i < 3; i++)
                {
                    using (var session = store.OpenAsyncSession())
                    {
                        var user = await session.LoadAsync <Company>(id);

                        user.Name = "Fitzchak " + i;
                        await session.SaveChangesAsync();
                    }
                }

                var snd = db.Time.GetUtcNow();

                db.Time.UtcDateTime = () => DateTime.UtcNow.AddMinutes(15);

                for (int i = 0; i < 3; i++)
                {
                    using (var session = store.OpenAsyncSession())
                    {
                        var user = await session.LoadAsync <Company>(id);

                        user.Name = "Oren " + i;
                        await session.SaveChangesAsync();
                    }
                }


                using (var session = store.OpenAsyncSession())
                {
                    var rev1 = await session.Advanced.Revisions.GetAsync <Company>(id, fst);

                    Assert.Equal("Fitzchak", rev1.Name);

                    var rev2 = await session.Advanced.Revisions.GetAsync <Company>(id, snd);

                    Assert.Equal("Fitzchak 2", rev2.Name);

                    var rev3 = await session.Advanced.Revisions.GetAsync <Company>(id, db.Time.GetUtcNow());

                    Assert.Equal("Oren 2", rev3.Name);
                }
            }
        }
        public async Task ClusterTransactionRequestWithRevisions()
        {
            var leader = await CreateRaftClusterAndGetLeader(5, shouldRunInMemory : false, leaderIndex : 0);

            using (var leaderStore = GetDocumentStore(new Options
            {
                DeleteDatabaseOnDispose = false,
                Server = leader,
                ReplicationFactor = 5,
                ModifyDocumentStore = (store) => store.Conventions.DisableTopologyUpdates = true
            }))
            {
                var user1 = new User()
                {
                    Name = "Karmel"
                };
                var user3 = new User()
                {
                    Name = "Indych"
                };
                var index = await RevisionsHelper.SetupRevisions(leader.ServerStore, leaderStore.Database, configuration => configuration.Collections["Users"].PurgeOnDelete = false);
                await WaitForRaftIndexToBeAppliedInCluster(index, TimeSpan.FromSeconds(15));

                // bring our SUT node down, but we still have a cluster and can execute cluster transaction.
                var server  = Servers[1];
                var url     = server.WebUrl;
                var dataDir = Servers[1].Configuration.Core.DataDirectory.FullPath.Split('/').Last();

                await DisposeServerAndWaitForFinishOfDisposalAsync(server);

                using (var session = leaderStore.OpenAsyncSession(new SessionOptions
                {
                    TransactionMode = TransactionMode.ClusterWide
                }))
                {
                    Assert.Equal(1, session.Advanced.RequestExecutor.TopologyNodes.Count);
                    Assert.Equal(leader.WebUrl, session.Advanced.RequestExecutor.Url);
                    session.Advanced.ClusterTransaction.CreateCompareExchangeValue("usernames/ayende", user1);
                    await session.StoreAsync(user3, "foo/bar");

                    await session.SaveChangesAsync();

                    var user = (await session.Advanced.ClusterTransaction.GetCompareExchangeValueAsync <User>("usernames/ayende")).Value;
                    Assert.Equal(user1.Name, user.Name);
                    user = await session.LoadAsync <User>("foo/bar");

                    Assert.Equal(user3.Name, user.Name);

                    var list = await session.Advanced.Revisions.GetForAsync <User>(user.Id);

                    Assert.Equal(1, list.Count);
                    var changeVector = session.Advanced.GetChangeVectorFor(user);
                    Assert.NotNull(await session.Advanced.Revisions.GetAsync <User>(changeVector));
                }
                // bring more nodes down, so only one node is left
                var dataDir2 = Servers[2].Configuration.Core.DataDirectory.FullPath.Split('/').Last();
                var url2     = Servers[2].WebUrl;
                var task1    = DisposeServerAndWaitForFinishOfDisposalAsync(Servers[2]);
                var task2    = DisposeServerAndWaitForFinishOfDisposalAsync(Servers[3]);
                var task3    = DisposeServerAndWaitForFinishOfDisposalAsync(Servers[4]);
                await Task.WhenAll(task1, task2, task3);

                using (var session = leaderStore.OpenAsyncSession())
                {
                    Assert.Equal(leader.WebUrl, session.Advanced.RequestExecutor.Url);
                    await session.StoreAsync(user1, "foo/bar");

                    await session.SaveChangesAsync();

                    var list = await session.Advanced.Revisions.GetForAsync <User>(user1.Id);

                    Assert.Equal(2, list.Count);
                }

                long lastRaftIndex;
                using (leader.ServerStore.Engine.ContextPool.AllocateOperationContext(out TransactionOperationContext ctx))
                    using (ctx.OpenReadTransaction())
                    {
                        lastRaftIndex = leader.ServerStore.Engine.GetLastCommitIndex(ctx);
                    }

                // revive the SUT node
                var revived = Servers[1] = GetNewServer(new Dictionary <string, string>
                {
                    [RavenConfiguration.GetKey(x => x.Core.ServerUrls)]         = url,
                    [RavenConfiguration.GetKey(x => x.Cluster.ElectionTimeout)] = "400"
                }, runInMemory: false, deletePrevious: false, partialPath: dataDir);
                using (var revivedStore = new DocumentStore()
                {
                    Urls = new[] { revived.WebUrl },
                    Database = leaderStore.Database,
                    Conventions = new DocumentConventions
                    {
                        DisableTopologyUpdates = true
                    }
                }.Initialize())
                {
                    // let the document with the revision to replicate
                    Assert.True(WaitForDocument(revivedStore, "foo/bar"));
                    using (var session = revivedStore.OpenAsyncSession())
                    {
                        var user = await session.LoadAsync <User>("foo/bar");

                        var changeVector = session.Advanced.GetChangeVectorFor(user);
                        Assert.NotNull(await session.Advanced.Revisions.GetAsync <User>(changeVector));
                        var count = await WaitForValueAsync((async() =>
                        {
                            var list = await session.Advanced.Revisions.GetForAsync <User>("foo/bar");
                            return(list.Count);
                        }), 2);

                        Assert.Equal(2, count);

                        // revive another node so we should have a functional cluster now
                        Servers[2] = GetNewServer(new Dictionary <string, string>
                        {
                            [RavenConfiguration.GetKey(x => x.Core.ServerUrls)]         = url2,
                            [RavenConfiguration.GetKey(x => x.Cluster.ElectionTimeout)] = "400"
                        }, runInMemory: false, deletePrevious: false, partialPath: dataDir2);

                        // wait for the log to apply on the SUT node
                        using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15)))
                        {
                            await leader.ServerStore.Engine.WaitForLeaveState(RachisState.Candidate, cts.Token);
                        }
                        var database = await Servers[1].ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(leaderStore.Database);
                        await database.RachisLogIndexNotifications.WaitForIndexNotification(lastRaftIndex, TimeSpan.FromSeconds(15));

                        count = await WaitForValueAsync((async() =>
                        {
                            var list = await session.Advanced.Revisions.GetForAsync <User>("foo/bar");
                            return(list.Count);
                        }), 2);

                        Assert.Equal(2, count);
                    }
                }
            }
        }
        public async Task CreateRevisionsAndReplicateThemAll()
        {
            var company = new Company {
                Name = "Company Name"
            };
            var company2 = new Company {
                Name = "Company Name2"
            };
            var company3 = new Company {
                Name = "Company Name3"
            };
            var company4 = new Company {
                Name = "Company Name4"
            };

            using (var master = GetDocumentStore(options: new Options
            {
                ModifyDatabaseRecord = record =>
                {
                    record.ConflictSolverConfig = new ConflictSolver
                    {
                        ResolveToLatest = false,
                        ResolveByCollection = new Dictionary <string, ScriptResolver>()
                    };
                }
            }))
                using (var slave = GetDocumentStore(options: new Options
                {
                    ModifyDatabaseRecord = record =>
                    {
                        record.ConflictSolverConfig = new ConflictSolver
                        {
                            ResolveToLatest = false,
                            ResolveByCollection = new Dictionary <string, ScriptResolver>()
                        };
                    }
                }))
                {
                    await RevisionsHelper.SetupRevisions(Server.ServerStore, master.Database);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, slave.Database);

                    using (var session = master.OpenAsyncSession())
                    {
                        await session.StoreAsync(company, "foo/bar");

                        await session.SaveChangesAsync();
                    }

                    using (var session = master.OpenAsyncSession())
                    {
                        await session.StoreAsync(company2, "foo/bar");

                        await session.SaveChangesAsync();
                    }

                    using (var session = master.OpenAsyncSession())
                    {
                        await session.StoreAsync(company3, "foo/bar");

                        await session.SaveChangesAsync();
                    }

                    using (var session = master.OpenAsyncSession())
                    {
                        await session.StoreAsync(company4, "foo/bar");

                        await session.SaveChangesAsync();
                    }

                    await SetupReplicationAsync(master, slave);

                    using (var session = slave.OpenSession())
                    {
                        Assert.True(WaitForDocument(slave, "foo/bar"));
                        Assert.Equal(4, WaitForValue(() => session.Advanced.Revisions.GetMetadataFor("foo/bar").Count, 4));
                    }
                }
        }
Exemple #15
0
        public async Task WillNotCreateMoreRevisionsAfterImport()
        {
            var file = Path.GetTempFileName();

            try
            {
                using (var store1 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store1"
                }))
                {
                    using (var session = store1.OpenAsyncSession())
                    {
                        await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database);

                        await session.StoreAsync(new Person { Name = "Name1" });

                        await session.StoreAsync(new Person { Name = "Name2" });

                        await session.StoreAsync(new Company { Name = "Hibernating Rhinos " });

                        await session.SaveChangesAsync();
                    }

                    for (int i = 0; i < 2; i++)
                    {
                        using (var session = store1.OpenAsyncSession())
                        {
                            var company = await session.LoadAsync <Company>("companies/1-A");

                            var person = await session.LoadAsync <Person>("people/1-A");

                            company.Name += " update " + i;
                            person.Name  += " update " + i;
                            await session.StoreAsync(company);

                            await session.StoreAsync(person);

                            await session.SaveChangesAsync();
                        }
                    }

                    using (var session = store1.OpenAsyncSession())
                    {
                        var person = await session.LoadAsync <Person>("people/2-A");

                        Assert.NotNull(person);
                        session.Delete(person);
                        await session.SaveChangesAsync();
                    }

                    await store1.Smuggler.ExportAsync(new DatabaseSmugglerExportOptions(), file);

                    var stats = await store1.Admin.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(4, stats.CountOfDocuments);
                    Assert.Equal(8, stats.CountOfRevisionDocuments);

                    await store1.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions(), file);

                    stats = await store1.Admin.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(4, stats.CountOfDocuments);
                    Assert.Equal(8, stats.CountOfRevisionDocuments);
                }
            }
            finally
            {
                File.Delete(file);
            }
        }
Exemple #16
0
        public async Task CanExportAndImportAttachmentsAndRevisionAttachments()
        {
            var file = Path.GetTempFileName();

            try
            {
                using (var store1 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store1"
                }))
                {
                    await SetDatabaseId(store1, new Guid("00000000-48c4-421e-9466-000000000000"));

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, configuration =>
                    {
                        configuration.Collections["Users"].PurgeOnDelete          = false;
                        configuration.Collections["Users"].MinimumRevisionsToKeep = 4;
                    });

                    AttachmentsRevisions.CreateDocumentWithAttachments(store1);
                    using (var bigStream = new MemoryStream(Enumerable.Range(1, 999 * 1024).Select(x => (byte)x).ToArray()))
                        store1.Operations.Send(new PutAttachmentOperation("users/1", "big-file", bigStream, "image/png"));

                    var exportOperation = await store1.Smuggler.ExportAsync(new DatabaseSmugglerExportOptions(), file);

                    var exportResult = (SmugglerResult)exportOperation.WaitForCompletion();

                    Assert.Equal(1, exportResult.Documents.ReadCount);
                    Assert.Equal(4, exportResult.RevisionDocuments.ReadCount);
                    Assert.Equal(4, exportResult.Documents.Attachments.ReadCount);
                    Assert.Equal(10, exportResult.RevisionDocuments.Attachments.ReadCount);

                    var stats = await store1.Maintenance.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(1, stats.CountOfDocuments);
                    Assert.Equal(4, stats.CountOfRevisionDocuments);
                    Assert.Equal(14, stats.CountOfAttachments);
                    Assert.Equal(4, stats.CountOfUniqueAttachments);
                }

                using (var store2 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store2"
                }))
                {
                    var dbId = new Guid("00000000-48c4-421e-9466-000000000000");
                    await SetDatabaseId(store2, dbId);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database);

                    for (var i = 0; i < 2; i++) // Make sure that we can import attachments twice and it will overwrite
                    {
                        var importOperation = await store2.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions(), file);

                        var importResult = (SmugglerResult)importOperation.WaitForCompletion();

                        Assert.Equal(1, importResult.Documents.ReadCount);
                        Assert.Equal(4, importResult.RevisionDocuments.ReadCount);
                        Assert.Equal(4, importResult.Documents.Attachments.ReadCount);
                        Assert.Equal(4, importResult.RevisionDocuments.Attachments.ReadCount);

                        var stats = await store2.Maintenance.SendAsync(new GetStatisticsOperation());

                        Assert.Equal(1, stats.CountOfDocuments);
                        Assert.Equal(5, stats.CountOfRevisionDocuments);
                        Assert.Equal(14 + 4, stats.CountOfAttachments); // the imported document will create 1 additional revision with 4 attachments
                        Assert.Equal(4, stats.CountOfUniqueAttachments);

                        using (var session = store2.OpenSession())
                        {
                            var readBuffer = new byte[1024 * 1024];
                            using (var attachmentStream = new MemoryStream(readBuffer))
                                using (var attachment = session.Advanced.Attachments.Get("users/1", "big-file"))
                                {
                                    attachment.Stream.CopyTo(attachmentStream);
                                    Assert.Equal("big-file", attachment.Details.Name);
                                    Assert.Equal("zKHiLyLNRBZti9DYbzuqZ/EDWAFMgOXB+SwKvjPAINk=", attachment.Details.Hash);
                                    Assert.Equal(999 * 1024, attachmentStream.Position);
                                    Assert.Equal(Enumerable.Range(1, 999 * 1024).Select(x => (byte)x), readBuffer.Take((int)attachmentStream.Position));
                                }
                        }
                    }
                }
            }
            finally
            {
                File.Delete(file);
            }
        }
        public async Task CanImportRevisions1(string file)
        {
            using (var stream = GetType().Assembly.GetManifestResourceStream(file))
                using (var store = GetDocumentStore())
                {
                    Assert.NotNull(stream);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store.Database);

                    var operation = await store.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions(), stream);

                    await operation.WaitForCompletionAsync(TimeSpan.FromMinutes(1));

                    var stats = await store.Maintenance.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(2, stats.CountOfDocuments);
                    Assert.Equal(5, stats.CountOfRevisionDocuments);
                    Assert.Equal(10, stats.LastDocEtag);

                    var collectionStats = await store.Maintenance.SendAsync(new GetCollectionStatisticsOperation());

                    Assert.Equal(2, collectionStats.CountOfDocuments);
                    Assert.Equal(2, collectionStats.Collections.Count);
                    Assert.Equal(1, collectionStats.Collections["@empty"]);
                    Assert.Equal(1, collectionStats.Collections["Users"]);

                    using (var session = store.OpenSession())
                    {
                        var user = session.Load <Order>("users/1");
                        Assert.NotNull(user);

                        var metadata = session.Advanced.GetMetadataFor(user);
                        Assert.Equal(5, metadata.Count);
                        Assert.Equal("Users", metadata.GetString(Constants.Documents.Metadata.Collection));
                        Assert.Equal($"{DocumentFlags.HasRevisions}", metadata.GetString(Constants.Documents.Metadata.Flags));
                        Assert.Equal("users/1", metadata.GetString(Constants.Documents.Metadata.Id));
                        Assert.NotEqual(DateTime.MinValue.ToString(DefaultFormat.DateTimeOffsetFormatsToWrite), metadata.GetString(Constants.Documents.Metadata.LastModified));

                        var changeVector = session.Advanced.GetChangeVectorFor(user);
                        Assert.StartsWith("RV:", changeVector);

                        var revisions = session.Advanced.Revisions.GetFor <User>("users/1");
                        Assert.Equal(4, revisions.Count);

                        for (int i = 0; i <= 3; i++)
                        {
                            metadata = session.Advanced.GetMetadataFor(revisions[i]);
                            Assert.Equal(5, metadata.Count);
                            Assert.Equal("Users", metadata.GetString(Constants.Documents.Metadata.Collection));
                            Assert.Equal($"{DocumentFlags.HasRevisions}, {DocumentFlags.Revision}", metadata.GetString(Constants.Documents.Metadata.Flags));
                            Assert.Equal("users/1", metadata.GetString(Constants.Documents.Metadata.Id));
                            Assert.NotEqual(DateTime.MinValue.ToString(DefaultFormat.DateTimeOffsetFormatsToWrite), metadata.GetString(Constants.Documents.Metadata.LastModified));

                            var revisionChangeVector = metadata.GetString(Constants.Documents.Metadata.ChangeVector);
                            Assert.Equal($"RV:{4 - i}-AAAAAQAAAQAAAAAAAAAAAw", revisionChangeVector);

                            if (i == 0)
                            {
                                Assert.Equal(changeVector, revisionChangeVector);
                            }
                        }
                    }
                }
        }
        public async Task RevisionsAreReplicatedBackWithTombstone(bool configureVersioning)
        {
            using (var storeA = GetDocumentStore())
                using (var storeB = GetDocumentStore())
                {
                    var expectedRevisionsCount = 3;
                    if (configureVersioning)
                    {
                        await RevisionsHelper.SetupRevisions(Server.ServerStore, storeA.Database);

                        await RevisionsHelper.SetupRevisions(Server.ServerStore, storeB.Database);

                        expectedRevisionsCount = 4;
                    }

                    var company = new Company {
                        Name = "Name"
                    };
                    var company2 = new Company {
                        Name = "Name2"
                    };

                    using (var session = storeA.OpenAsyncSession())
                    {
                        await session.StoreAsync(new Company(), "keep-conflicted-revision-insert-order");

                        await session.SaveChangesAsync();

                        await session.StoreAsync(company, "foo/bar");

                        await session.SaveChangesAsync();

                        session.Delete("foo/bar");
                        await session.SaveChangesAsync();
                    }

                    using (var session = storeB.OpenAsyncSession())
                    {
                        await session.StoreAsync(company2, "foo/bar");

                        await session.SaveChangesAsync();
                    }

                    await SetupReplicationAsync(storeA, storeB);

                    using (var session = storeB.OpenSession())
                    {
                        Assert.Equal(expectedRevisionsCount, WaitForValue(() => session.Advanced.Revisions.GetMetadataFor("foo/bar").Count, expectedRevisionsCount));

                        var metadata = session.Advanced.Revisions.GetMetadataFor("foo/bar");
                        var flags    = metadata[0]["@flags"];
                        Assert.Equal((DocumentFlags.Revision | DocumentFlags.HasRevisions | DocumentFlags.Resolved).ToString(), flags);
                        flags = metadata[1]["@flags"];
                        Assert.Equal((DocumentFlags.Revision | DocumentFlags.HasRevisions | DocumentFlags.Conflicted).ToString(), flags);
                        flags = metadata[2]["@flags"];
                        Assert.Equal((DocumentFlags.DeleteRevision | DocumentFlags.HasRevisions | DocumentFlags.FromReplication | DocumentFlags.Conflicted).ToString(), flags);

                        if (configureVersioning)
                        {
                            flags = metadata[3]["@flags"];
                            Assert.Equal((DocumentFlags.Revision | DocumentFlags.HasRevisions | DocumentFlags.FromReplication).ToString(), flags);
                        }
                    }

                    await SetupReplicationAsync(storeB, storeA);

                    using (var session = storeA.OpenSession())
                    {
                        Assert.Equal(expectedRevisionsCount, WaitForValue(() => session.Advanced.Revisions.GetMetadataFor("foo/bar").Count, expectedRevisionsCount));

                        var metadata = session.Advanced.Revisions.GetMetadataFor("foo/bar");
                        var flags    = metadata[0]["@flags"];
                        Assert.Equal((DocumentFlags.Revision | DocumentFlags.HasRevisions | DocumentFlags.FromReplication | DocumentFlags.Resolved).ToString(), flags);
                        flags = metadata[1]["@flags"];
                        Assert.Equal((DocumentFlags.Revision | DocumentFlags.HasRevisions | DocumentFlags.FromReplication | DocumentFlags.Conflicted).ToString(), flags);
                        flags = metadata[2]["@flags"];

                        if (configureVersioning)
                        {
                            Assert.Equal((DocumentFlags.DeleteRevision | DocumentFlags.HasRevisions | DocumentFlags.Conflicted).ToString(), flags);
                            flags = metadata[3]["@flags"];
                            Assert.Equal((DocumentFlags.Revision | DocumentFlags.HasRevisions).ToString(), flags);
                        }
                        else
                        {
                            Assert.Equal((DocumentFlags.DeleteRevision | DocumentFlags.HasRevisions | DocumentFlags.FromReplication | DocumentFlags.Conflicted).ToString(), flags);
                        }
                    }
                }
        }