Ejemplo n.º 1
0
        private async Task TestSyncAgentDeleteWithForeignKeys(
            BlogDbContext localDb,
            ISyncProvider localSyncProvider,
            BlogDbContext remoteDb,
            ISyncProvider remoteSyncProvider)
        {
            var syncAgent = new SyncAgent(localSyncProvider, remoteSyncProvider);
            await syncAgent.SynchronizeAsync();

            //create a user on remote store
            User remoteUser;

            remoteDb.Users.Add(remoteUser = new User()
            {
                Email = "*****@*****.**", Name = "User", Created = DateTime.Now
            });
            remoteUser.Posts.Add(new Post()
            {
                Content = $"Content",
                Title   = $"Post",
                Claps   = 1,
                Stars   = 10
            });

            await remoteDb.SaveChangesAsync();

            await syncAgent.SynchronizeAsync();

            var localUser = await localDb.Users.FirstOrDefaultAsync(_ => _.Email == "*****@*****.**");

            localUser.ShouldNotBeNull();

            //delete user on remotedb
            remoteDb = remoteDb.Refresh();

            remoteDb.Users.Remove(await remoteDb.Users.FirstAsync(_ => _.Email == "*****@*****.**"));
            remoteDb.Posts.RemoveRange(await remoteDb.Posts.ToListAsync());
            await remoteDb.SaveChangesAsync();

            await syncAgent.SynchronizeAsync();

            localDb   = localDb.Refresh();
            localUser = await localDb.Users.FirstOrDefaultAsync(_ => _.Email == "*****@*****.**");

            localUser.ShouldBeNull();

            (await localDb.Posts.AnyAsync()).ShouldBeFalse();
        }
Ejemplo n.º 2
0
        private async Task TestSyncAgent(
            BlogDbContext localDb,
            ISyncProvider localSyncProvider,
            BlogDbContext remoteDb,
            ISyncProvider remoteSyncProvider)
        {
            var syncAgent = new SyncAgent(localSyncProvider, remoteSyncProvider);
            await syncAgent.SynchronizeAsync();

            //create a user on server
            var remoteUser = new User()
            {
                Email = "*****@*****.**", Name = "user", Created = new DateTime(2018, 1, 1)
            };

            remoteDb.Users.Add(remoteUser);
            await remoteDb.SaveChangesAsync();

            //sync with remote server
            await syncAgent.SynchronizeAsync();

            remoteDb = remoteDb.Refresh(); //discard any cache data in ef

            //verify that new user is stored now locally too
            var localUser = await localDb.Users.FirstAsync(_ => _.Email == "*****@*****.**");

            Assert.AreEqual("user", localUser.Name);
            Assert.AreEqual(new DateTime(2018, 1, 1), localUser.Created);

            //create an article for user locally
            var localPost = new Post()
            {
                Content = "this is my first post", Title = "First Post", Updated = DateTime.Now.Date
            };

            localUser.Posts.Add(localPost);
            await localDb.SaveChangesAsync();

            //sync with remote server
            await syncAgent.SynchronizeAsync();

            remoteDb = remoteDb.Refresh(); //discard any cache data in ef

            //verify that user on server and locally have the same post
            remoteUser = await remoteDb.Users.Include(_ => _.Posts).FirstOrDefaultAsync(_ => _.Email == "*****@*****.**");

            Assert.AreEqual("user", remoteUser.Name);
            Assert.AreEqual(new DateTime(2018, 1, 1), remoteUser.Created);
            Assert.AreEqual(1, remoteUser.Posts.Count);
            var remotePost = remoteUser.Posts[0];

            Assert.AreEqual(localPost.Author.Name, remotePost.Author.Name);
            Assert.AreEqual(localPost.Content, remotePost.Content);
            Assert.AreEqual(localPost.Title, remotePost.Title);

            //now make a change to post content while claps it on server
            localPost.Content = "this is my my first post edited";
            await localDb.SaveChangesAsync();

            remotePost.Claps += 1;
            await remoteDb.SaveChangesAsync();

            //then sync
            await syncAgent.SynchronizeAsync(conflictResolutionOnLocalStore : ConflictResolution.ForceWrite);

            remoteDb = remoteDb.Refresh(); //discard any cache data in ef

            //verify that claps is 1 on both server and local stores
            //content is not changed because we set conflictResolutionOnLocalStore to ConflictResolution.ForceWrite
            //so server skipped our try to update content while local store forcely write data coming from server
            remoteUser = await remoteDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**");

            remotePost = remoteUser.Posts[0];
            Assert.AreEqual("user", remotePost.Author.Name);
            Assert.AreEqual("this is my first post", remotePost.Content);
            Assert.AreEqual(1, remotePost.Claps);

            localUser = await localDb.Users.FirstAsync(_ => _.Email == "*****@*****.**");

            localPost = localUser.Posts[0];
            Assert.AreEqual("user", remotePost.Author.Name);
            Assert.AreEqual("this is my first post", remotePost.Content);
            Assert.AreEqual(1, remotePost.Claps);

            //so to handle this scenario (when a record is often edited on multiple devices)
            //we should take care of restoring any pending records (posts) locally
            //for example using a PendingPosts table (not synched)
        }
Ejemplo n.º 3
0
        private async Task TestSyncAgentWithDataRetention(
            BlogDbContext localDb,
            ISyncProvider localSyncProvider,
            BlogDbContext remoteDb,
            ISyncProvider remoteSyncProvider)
        {
            //setup change tracking
            await remoteSyncProvider.ApplyProvisionAsync();

            //create remote data
            User remoteUser;

            remoteDb.Users.Add(remoteUser = new User()
            {
                Email = "*****@*****.**", Name = "User created before sync", Created = DateTime.Now
            });

            for (int i = 1; i <= 10; i++)
            {
                remoteUser.Posts.Add(new Post()
                {
                    Content = $"Content of Post {i}",
                    Title   = $"Post {i}",
                    Claps   = 1,
                    Stars   = 10
                });
            }

            await remoteDb.SaveChangesAsync();


            //set data retention -> remove first records in the change tracking table
            var remoteSyncVersion = await remoteSyncProvider.GetSyncVersionAsync();

            remoteSyncVersion.Minimum.ShouldBe(1);
            remoteSyncVersion.Current.ShouldBe(11);//1 users + 10 posts

            remoteSyncVersion = await remoteSyncProvider.ApplyRetentionPolicyAsync(4);

            remoteSyncVersion.Minimum.ShouldBe(4);
            remoteSyncVersion.Current.ShouldBe(11);// 11 - 4 = 7 posts

            //local provider is still not synched
            var localSyncVersion = await localSyncProvider.GetSyncVersionAsync();

            localSyncVersion.Minimum.ShouldBe(0);
            localSyncVersion.Current.ShouldBe(0);

            //now let's sync
            var syncAgent = new SyncAgent(localSyncProvider, remoteSyncProvider);
            await syncAgent.SynchronizeAsync();

            localSyncVersion = await localSyncProvider.GetSyncVersionAsync();

            localSyncVersion.Minimum.ShouldBe(0);
            localSyncVersion.Current.ShouldBe(0);

            (await localDb.Users.ToListAsync()).Count.ShouldBe(1);
            (await localDb.Posts.ToListAsync()).Count.ShouldBe(10);

            //now add a new post on server, one on local db than sync
            remoteDb   = remoteDb.Refresh();
            remoteUser = await remoteDb.Users.FirstAsync(_ => _.Email == "*****@*****.**");

            remoteUser.Posts.Add(new Post()
            {
                Content = $"Another post on server",
                Title   = $"New post on server",
                Claps   = 1,
                Stars   = 10
            });

            await remoteDb.SaveChangesAsync();

            var localUser = await localDb.Users.FirstAsync(_ => _.Email == "*****@*****.**");

            localUser.Posts.Add(new Post()
            {
                Content = $"A post from client",
                Title   = $"New post on client",
                Claps   = 1,
                Stars   = 10
            });

            await localDb.SaveChangesAsync();

            await syncAgent.SynchronizeAsync();

            remoteDb = remoteDb.Refresh();
            localDb  = localDb.Refresh();

            (await remoteDb.Users.SingleAsync()).Email.ShouldBe("*****@*****.**");
            (await localDb.Users.SingleAsync()).Email.ShouldBe("*****@*****.**");

            (await remoteDb.Posts.ToListAsync()).Count.ShouldBe(12);
            (await localDb.Posts.ToListAsync()).Count.ShouldBe(12);


            remoteSyncVersion = await remoteSyncProvider.ApplyRetentionPolicyAsync(4);

            remoteSyncVersion.Minimum.ShouldBe(4);
            remoteSyncVersion.Current.ShouldBe(13);// +2 posts

            localSyncVersion = await localSyncProvider.GetSyncVersionAsync();

            localSyncVersion.Minimum.ShouldBe(1);
            localSyncVersion.Current.ShouldBe(2); // +2 posts
        }
Ejemplo n.º 4
0
        private async Task TestSyncAgentWithUpdatedRemoteDeletedLocal(
            BlogDbContext localDb,
            ISyncProvider localSyncProvider,
            BlogDbContext remoteDb,
            ISyncProvider remoteSyncProvider)
        {
            #region Initialize remote data, sync local and verify

            User remoteUser;
            remoteDb.Users.Add(remoteUser = new User()
            {
                Email = "*****@*****.**", Name = "User created before sync", Created = DateTime.Now
            });

            remoteUser.Posts.Add(new Post()
            {
                Content = "This is a post created before sync of the client",
                Title   = "Initial post of user 1",
                Claps   = 1,
                Stars   = 10
            });

            remoteUser.Posts.Add(new Post()
            {
                Content = "This is a second post created before sync of the client",
                Title   = "Initial post 2 of user 1",
                Claps   = 2,
                Stars   = 1
            });

            remoteUser.Posts.Add(new Post()
            {
                Content = "This is a third post created before sync of the client",
                Title   = "Initial post 3 of user 1",
                Claps   = 3,
                Stars   = 1
            });

            await remoteDb.SaveChangesAsync();

            var syncAgent = new SyncAgent(localSyncProvider, remoteSyncProvider);
            await syncAgent.SynchronizeAsync();

            var localUser = await localDb.Users.Include(_ => _.Posts).FirstOrDefaultAsync(_ => _.Email == "*****@*****.**");

            localUser.ShouldNotBeNull();
            localUser.Email.ShouldBe("*****@*****.**");
            localUser.Name.ShouldBe("User created before sync");

            var localUserPosts = localUser.Posts.OrderBy(_ => _.Claps).ToList();
            localUserPosts.Count().ShouldBe(3);
            localUserPosts[0].Content.ShouldBe("This is a post created before sync of the client");
            localUserPosts[0].Title.ShouldBe("Initial post of user 1");
            localUserPosts[0].Claps.ShouldBe(1);
            localUserPosts[0].Stars.ShouldBe(10);

            localUserPosts[1].Content.ShouldBe("This is a second post created before sync of the client");
            localUserPosts[1].Title.ShouldBe("Initial post 2 of user 1");
            localUserPosts[1].Claps.ShouldBe(2);
            localUserPosts[1].Stars.ShouldBe(1);

            localUserPosts[2].Content.ShouldBe("This is a third post created before sync of the client");
            localUserPosts[2].Title.ShouldBe("Initial post 3 of user 1");
            localUserPosts[2].Claps.ShouldBe(3);
            localUserPosts[2].Stars.ShouldBe(1);

            await syncAgent.SynchronizeAsync();

            remoteDb = remoteDb.Refresh();

            var remoteUserPosts = remoteDb.Posts.OrderBy(_ => _.Claps).ToList();
            remoteUserPosts.Count().ShouldBe(3);
            remoteUserPosts[0].Content.ShouldBe("This is a post created before sync of the client");
            //even if edited on localdb post that was synched as initial snapshot can't be modified on server
            remoteUserPosts[0].Title.ShouldBe("Initial post of user 1");
            remoteUserPosts[0].Claps.ShouldBe(1);
            remoteUserPosts[0].Stars.ShouldBe(10);

            remoteUserPosts[1].Content.ShouldBe("This is a second post created before sync of the client");
            remoteUserPosts[1].Title.ShouldBe("Initial post 2 of user 1");
            remoteUserPosts[1].Claps.ShouldBe(2);
            remoteUserPosts[1].Stars.ShouldBe(1);

            remoteUserPosts[2].Content.ShouldBe("This is a third post created before sync of the client");
            remoteUserPosts[2].Title.ShouldBe("Initial post 3 of user 1");
            remoteUserPosts[2].Claps.ShouldBe(3);
            remoteUserPosts[2].Stars.ShouldBe(1);

            #endregion

            #region Remove a local record and verify

            var postToRemove = localUser.Posts[2];

            localDb.Posts.Remove(localUser.Posts[2]);
            await localDb.SaveChangesAsync();

            localUser = await localDb.Users.Include(_ => _.Posts).FirstOrDefaultAsync(_ => _.Email == "*****@*****.**");

            Assert.AreEqual(2, localUser.Posts.Count);

            #endregion

            #region Update a remote record

            var remotePost = remoteUser.Posts.First(p => p.Id == postToRemove.Id);
            remotePost.Content = "Updated remote for test.";

            remoteDb = remoteDb.Refresh();
            remoteDb.Posts.Update(remotePost);

            await remoteDb.SaveChangesAsync();

            remoteUser = await remoteDb.Users.Include(_ => _.Posts).FirstOrDefaultAsync(_ => _.Email == "*****@*****.**");

            Assert.AreEqual("Updated remote for test.", remoteUser.Posts.First(p => p.Id == postToRemove.Id).Content);

            #endregion

            #region Syncronize and verify the local database has the deleted record
            //I've delete a post on local database AND updated the same posts on rempte database
            //SynchronizeAsync() accepts 2 args remoteConflictResolutionFunc and localConflictResolutionFunc
            //that describe how agent should deal with conflits:
            //1) remoteConflictResolutionFunc: (itemInConflict) => ConflictResolution.Skip or simply remoteConflictResolution: ConflictResolution.Skip
            //   means that remote database should not apply the delete operation on post coming from local database
            //2) localConflictResolutionFunc: (itemInConflict) => ConflictResolution.ForceWrite or simply localConflictResolutionFunc: ConflictResolution.ForceWrite
            //   means that local datase should update the local post that was updated from remote db and since the record doesn't exist anymore it actually means insert
            //   the post record again with data coming from server

            await syncAgent.SynchronizeAsync();

            //this above call is the same as this:
            // await syncAgent.SynchronizeAsync(conflictResolutionOnRemoteStore: ConflictResolution.Skip, conflictResolutionOnLocalStore: ConflictResolution.ForceWrite);
            //Thanks to Mike Perrenoud I've found that by default await syncAgent.SynchronizeAsync() was instead defaulted to
            // await syncAgent.SynchronizeAsync(conflictResolutionOnRemoteStore: ConflictResolution.Skip, conflictResolutionOnLocalStore: ConflictResolution.Skip);
            // causing this test to fail

            // following code allows to enumerate any item in conflict and take appropriate action for each of them:
            //await syncAgent.SynchronizeAsync(
            //    remoteConflictResolutionFunc: (itemInConflict) =>
            //    {
            //        itemInConflict.ChangeType.ShouldBe(ChangeType.Delete);
            //        itemInConflict.TableName.ShouldBe("Posts");
            //        itemInConflict.Values["Id"].Value = postToRemove.Id;
            //        return ConflictResolution.Skip;
            //    },
            //    localConflictResolutionFunc: (itemInConflict) =>
            //    {
            //        return ConflictResolution.ForceWrite;
            //    });

            localDb = localDb.Refresh();

            localUser = await localDb.Users.Include(_ => _.Posts).FirstOrDefaultAsync(_ => _.Email == "*****@*****.**");

            Assert.AreEqual(3, localUser.Posts.Count);
            Assert.AreEqual("Updated remote for test.", localUser.Posts.First(p => p.Id == postToRemove.Id).Content);

            #endregion
        }
Ejemplo n.º 5
0
        private async Task TestSyncAgentWithInitialData(
            BlogDbContext localDb,
            ISyncProvider localSyncProvider,
            BlogDbContext remoteDb,
            ISyncProvider remoteSyncProvider)
        {
            User remoteUser;

            remoteDb.Users.Add(remoteUser = new User()
            {
                Email = "*****@*****.**", Name = "User created before sync", Created = DateTime.Now
            });

            remoteUser.Posts.Add(new Post()
            {
                Content = "This is a post created before sync of the client", Title = "Initial post of user 1", Claps = 1, Stars = 10
            });
            remoteUser.Posts.Add(new Post()
            {
                Content = "This is a second post created before sync of the client", Title = "Initial post 2 of user 1", Claps = 2, Stars = 1
            });

            await remoteDb.SaveChangesAsync();

            await remoteSyncProvider.ApplyProvisionAsync();

            remoteUser.Posts.Add(new Post()
            {
                Content = "This is a third post created before sync of the client but after applying provision to remote db", Title = "Initial post 3 of user 1", Claps = 3, Stars = 1
            });

            await remoteDb.SaveChangesAsync();

            var syncAgent = new SyncAgent(localSyncProvider, remoteSyncProvider);
            await syncAgent.SynchronizeAsync();

            var localUser = await localDb.Users.Include(_ => _.Posts).FirstOrDefaultAsync(_ => _.Email == "*****@*****.**");

            localUser.ShouldNotBeNull();
            localUser.Email.ShouldBe("*****@*****.**");
            localUser.Name.ShouldBe("User created before sync");

            var localUserPosts = localUser.Posts.OrderBy(_ => _.Claps).ToList();

            localUserPosts.Count().ShouldBe(3);
            localUserPosts[0].Content.ShouldBe("This is a post created before sync of the client");
            localUserPosts[0].Title.ShouldBe("Initial post of user 1");
            localUserPosts[0].Claps.ShouldBe(1);
            localUserPosts[0].Stars.ShouldBe(10);

            localUserPosts[1].Content.ShouldBe("This is a second post created before sync of the client");
            localUserPosts[1].Title.ShouldBe("Initial post 2 of user 1");
            localUserPosts[1].Claps.ShouldBe(2);
            localUserPosts[1].Stars.ShouldBe(1);

            localUserPosts[2].Content.ShouldBe("This is a third post created before sync of the client but after applying provision to remote db");
            localUserPosts[2].Title.ShouldBe("Initial post 3 of user 1");
            localUserPosts[2].Claps.ShouldBe(3);
            localUserPosts[2].Stars.ShouldBe(1);

            await syncAgent.SynchronizeAsync();

            localUser.Posts.Add(new Post()
            {
                Content = "Post created on local db after first sync", Title = "Post created on local db", Claps = 4
            });
            localUserPosts[0].Title = "Post edited on local db";

            await localDb.SaveChangesAsync();

            await syncAgent.SynchronizeAsync();

            remoteDb = remoteDb.Refresh();

            var remoteUserPosts = remoteDb.Posts.OrderBy(_ => _.Claps).ToList();

            remoteUserPosts.Count().ShouldBe(4);
            remoteUserPosts[0].Content.ShouldBe("This is a post created before sync of the client");
            //even if edited on localdb post that was synched as initial snapshot can't be modified on server
            remoteUserPosts[0].Title.ShouldBe("Initial post of user 1");
            remoteUserPosts[0].Claps.ShouldBe(1);
            remoteUserPosts[0].Stars.ShouldBe(10);

            remoteUserPosts[1].Content.ShouldBe("This is a second post created before sync of the client");
            remoteUserPosts[1].Title.ShouldBe("Initial post 2 of user 1");
            remoteUserPosts[1].Claps.ShouldBe(2);
            remoteUserPosts[1].Stars.ShouldBe(1);

            remoteUserPosts[2].Content.ShouldBe("This is a third post created before sync of the client but after applying provision to remote db");
            remoteUserPosts[2].Title.ShouldBe("Initial post 3 of user 1");
            remoteUserPosts[2].Claps.ShouldBe(3);
            remoteUserPosts[2].Stars.ShouldBe(1);

            remoteUserPosts[3].Content.ShouldBe("Post created on local db after first sync");
            remoteUserPosts[3].Title.ShouldBe("Post created on local db");
            remoteUserPosts[3].Claps.ShouldBe(4);
            remoteUserPosts[3].Stars.ShouldBe(0);
        }
Ejemplo n.º 6
0
        private async Task TestSyncAgentMultipleRecordsOnSameTable(
            BlogDbContext localDb,
            ISyncProvider localSyncProvider,
            BlogDbContext remoteDb,
            ISyncProvider remoteSyncProvider)
        {
            var syncAgent = new SyncAgent(localSyncProvider, remoteSyncProvider);
            //await syncAgent.InitializeAsync();
            await syncAgent.SynchronizeAsync();

            //create a user on server
            var remoteUser = new User()
            {
                Email = "*****@*****.**", Name = "user", Created = new DateTime(2018, 1, 1)
            };

            remoteDb.Users.Add(remoteUser);
            await remoteDb.SaveChangesAsync();

            //create a second user on server
            var remoteUser2 = new User()
            {
                Email = "*****@*****.**", Name = "user2", Created = new DateTime(2019, 1, 1)
            };

            remoteDb.Users.Add(remoteUser2);
            await remoteDb.SaveChangesAsync();

            //sync with remote server
            await syncAgent.SynchronizeAsync();

            //verify that new user is stored now locally too
            var localUser = await localDb.Users.FirstAsync(_ => _.Email == "*****@*****.**");

            Assert.AreEqual("user", localUser.Name);
            Assert.AreEqual(new DateTime(2018, 1, 1), localUser.Created);

            //verify that new second user is stored now locally too
            var localUser2 = await localDb.Users.FirstAsync(_ => _.Email == "*****@*****.**");

            Assert.AreEqual("user2", localUser2.Name);
            Assert.AreEqual(new DateTime(2019, 1, 1), localUser2.Created);

            localUser.Posts.Add(new Post()
            {
                Content = "This is first post from user 1",
                Updated = new DateTime(2019, 1, 1)
            });

            localUser.Posts.Add(new Post()
            {
                Content = "This is second post from user 1",
                Updated = new DateTime(2019, 1, 2)
            });

            localUser2.Posts.Add(new Post()
            {
                Content = "This is first post from user 2",
                Updated = DateTime.Now
            });
            await localDb.SaveChangesAsync();


            //create a third user on server
            var remoteUser3 = new User()
            {
                Email = "*****@*****.**", Name = "user3", Created = new DateTime(2019, 1, 1)
            };

            remoteDb.Users.Add(remoteUser3);
            await remoteDb.SaveChangesAsync();

            await syncAgent.SynchronizeAsync();

            localDb = localDb.Refresh();

            //verify that first user is still stored locally
            localUser = await localDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**");

            Assert.AreEqual("user", localUser.Name);
            Assert.AreEqual(new DateTime(2018, 1, 1), localUser.Created);

            //verify that second user is still stored locally
            localUser2 = await localDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**");

            Assert.AreEqual("user2", localUser2.Name);
            Assert.AreEqual(new DateTime(2019, 1, 1), localUser2.Created);

            //verify that new third user is stored locally now
            var localUser3 = await localDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**");

            Assert.AreEqual("user3", localUser3.Name);
            Assert.AreEqual(new DateTime(2019, 1, 1), localUser3.Created);

            //verify that user posts are still stored locally
            Assert.AreEqual("This is first post from user 1", localUser.Posts.OrderBy(_ => _.Updated).ToArray()[0].Content);
            Assert.AreEqual("This is second post from user 1", localUser.Posts.OrderBy(_ => _.Updated).ToArray()[1].Content);
            Assert.AreEqual("This is first post from user 2", localUser2.Posts.OrderBy(_ => _.Updated).ToArray()[0].Content);

            remoteDb = remoteDb.Refresh();

            //verify that first user is still stored remotely
            remoteUser = await remoteDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**");

            Assert.AreEqual("user", remoteUser.Name);
            Assert.AreEqual(new DateTime(2018, 1, 1), remoteUser.Created);

            //verify that second user is still stored remotely
            remoteUser2 = await remoteDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**");

            Assert.AreEqual("user2", remoteUser2.Name);
            Assert.AreEqual(new DateTime(2019, 1, 1), remoteUser2.Created);

            //verify that new third user still stored remotely
            remoteUser3 = await remoteDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**");

            Assert.AreEqual("user3", remoteUser3.Name);
            Assert.AreEqual(new DateTime(2019, 1, 1), remoteUser3.Created);

            //verify that user posts are still stored remotely
            Assert.AreEqual("This is first post from user 1", remoteUser.Posts.OrderBy(_ => _.Updated).ToArray()[0].Content);
            Assert.AreEqual("This is second post from user 1", remoteUser.Posts.OrderBy(_ => _.Updated).ToArray()[1].Content);
            Assert.AreEqual(1, remoteUser2.Posts.Count);
            Assert.AreEqual("This is first post from user 2", remoteUser2.Posts.OrderBy(_ => _.Updated).ToArray()[0].Content);

            //now delete a post locally
            localDb.Posts.Remove(localUser2.Posts.First());
            await localDb.SaveChangesAsync();

            await syncAgent.SynchronizeAsync();

            remoteDb = remoteDb.Refresh();

            remoteUser2 = await remoteDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**");

            Assert.AreEqual(0, remoteUser2.Posts.Count);

            //now delete a post on server
            remoteDb.Posts.Remove(remoteUser.Posts[0]);
            await remoteDb.SaveChangesAsync();

            await syncAgent.SynchronizeAsync();

            localDb = localDb.Refresh();

            localUser = await localDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**");

            Assert.AreEqual(1, localUser.Posts.Count);


            remoteUser2.Posts.Add(new Post()
            {
                Content = "Post add to remote user while user is delete on local db",
                Updated = DateTime.Now
            });
            remoteUser2.Name = "edited name";
            await remoteDb.SaveChangesAsync();

            localDb.Users.Remove(localUser2);
            await localDb.SaveChangesAsync();

            await syncAgent.SynchronizeAsync(conflictResolutionOnLocalStore : ConflictResolution.ForceWrite);

            remoteDb = remoteDb.Refresh();
            localDb  = localDb.Refresh();

            //ensure that local db updated (local user 2 is present)
            localUser2 = await localDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**");

            localUser2.Posts.Count.ShouldBe(1);
            localUser2.Posts[0].Content.ShouldBe("Post add to remote user while user is delete on local db");

            //ensure that remote db is updated
            remoteUser2 = await remoteDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**");

            remoteUser2.Posts.Count.ShouldBe(1);
            remoteUser2.Posts[0].Content.ShouldBe("Post add to remote user while user is delete on local db");
        }