public void TestSmartContext_DeleteEntity_DeleteShouldBeBackedUp()
        {
            using (SmartContext sCtx = new SmartContext())
            {
                User userToDelete = sCtx.GetSingle<User>();

                int userToDeleteId = userToDelete.UserId;

                sCtx.Delete(userToDelete);
                sCtx.SaveChanges();

                User deletedUsserFromOffline = this.offlineContext.Users.FirstOrDefault(usr => usr.UserId == userToDelete.UserId);

                object deleteOperation = this.offlineContext.GetAll(DeleteOperationDefinition.DeleteOperationFullTypeName)
                    .Cast<object>()
                    .FirstOrDefault(o => o.FieldValue<int>(DeleteOperationDefinition.EntityToDeleteId) == userToDeleteId);

                int deletedEntityId = deleteOperation.FieldValue<int>(DeleteOperationDefinition.EntityToDeleteId);
                string deletedEntityType = deleteOperation.FieldValue<string>((DeleteOperationDefinition.EntityToDeleteType));

                Assert.IsNull(deletedUsserFromOffline);
                Assert.AreEqual(userToDeleteId, deletedEntityId);
                Assert.AreEqual("Model.User", deletedEntityType);
            }
        }
        public void TestAutoSwitchSmartContext_BackupDeletes_SwitchBackToOnlineMode_SyncDeletes_ObjectsShouldBeDeletedFromOnlineStorage()
        {
            using (SmartContext sCtx = new SmartContext())
            {
                int usersInOnlineCountBefore = this.onlineContext.Users.Count();

                int usrToDeleteId = 1;
                User usrToDelete = sCtx.GetSingle<User>(usr => usr.UserId == usrToDeleteId);
                sCtx.Delete(usrToDelete);

                this.LockDbTable("Users");
                sCtx.SaveChanges();

                this.ReleaseLock();
                Thread.Sleep(20000);

                User usrToDeleteFromOnline = this.onlineContext.Users.FirstOrDefault(usr => usr.UserId == usrToDeleteId);
                int usersInOnlineCountAfter = this.onlineContext.Users.Count();
                Assert.AreNotEqual(usersInOnlineCountBefore, usersInOnlineCountAfter);
                Assert.AreEqual(usersInOnlineCountBefore - 1, usersInOnlineCountAfter);
                Assert.IsNull(usrToDeleteFromOnline);
            }
        }
        public void TestAutoSwitchSmartContext_SwitchBackToOnlineMode_ObjectShouldBeRetrievedFromTheOnlineStorage()
        {
            using (SmartContext sCtx = new SmartContext())
            {
                //this is a user which is only available in the online storage
                User onlineSpecificUser = new User()
                {
                    UserId = 8888,
                    Name = "Special Guy",
                    Email = "*****@*****.**",
                    Note = "note note note",
                    Income = 1234m
                };

                this.onlineContext.Add(onlineSpecificUser);
                this.onlineContext.SaveChanges();

                //lock the Users table in the online storage to simulate that the server is not available
                this.LockDbTable("Users");

                User userFromBackup = null;
                try
                {
                    //attempt a retrival operation
                    //as the server is not available (Users locked) the SmartContext will switch to the backup storage
                    userFromBackup = sCtx.GetSingle<User>(usr => usr.UserId == onlineSpecificUser.UserId);
                }
                catch (Exception)
                {
                    //now the SmartCotnext has already switched to use the backup storage
                }

                //release the lock so that the server would available
                this.ReleaseLock();
                Thread.Sleep(20000);
                //During the thime which the tread sleeps the SmartContext will evalueate that the
                //online storage is available and switch to using it

                //As the SmartContext now uses the online storage we can retrieve the online specific user
                User userFromOnline = sCtx.GetSingle<User>(usr => usr.UserId == onlineSpecificUser.UserId);
                Assert.IsNull(userFromBackup);
                Assert.IsNotNull(userFromOnline);
            }
        }
        public void TestAutoSwitchSmartContext_SwitchOnUpdate_ObjecShouldBeUpdateInTheBackup()
        {
            using (SmartContext sCtx = new SmartContext())
            {
                User userToUpdate = sCtx.GetSingle<User>();
                string newName = "Tony Stark";
                userToUpdate.Name = newName;

                //Simulate that the online storage is not available
                this.LockDbTable("Users");

                //Upon saving the changes the SmartContext will switch to the backup storage
                //and persist the changes made to the user there
                sCtx.SaveChanges();

                User updatedUserFromBackup = sCtx.GetSingle<User>(usr => usr.UserId == userToUpdate.UserId);
                this.ReleaseLock();
                User updatedUserFromOnline = this.onlineContext.Users.FirstOrDefault(usr => usr.UserId == userToUpdate.UserId);

                Assert.AreEqual(newName, updatedUserFromBackup.Name);
                Assert.AreNotEqual(newName, updatedUserFromOnline);
            }
        }
        public void TestAutoSwitchSmartContext_SwitchOnRetrieval_ObjectsShouldBeRetrievedFromTheBackup()
        {
            using (SmartContext sCtx = new SmartContext())
            {
                User offlineSpecificUser = new User()
                {
                    UserId = 8888,
                    Name = "Special Guy",
                    Email = "*****@*****.**",
                    Note = "note note note",
                    Income = 1234m
                };
                this.offlineContext.Add(offlineSpecificUser);
                this.offlineContext.SaveChanges();

                //Simulate that the online storage is not available
                this.LockDbTable("Users");

                //the SmartContext will now work with the backup storage and the required user will still be retrieved
                User userFromBackup = sCtx.GetSingle<User>(usr => usr.UserId == offlineSpecificUser.UserId);

                Assert.IsNotNull(userFromBackup);
            }
        }
        public void TestAutoSwitchSmartContext_SwitchOnInsert_ObjectShouldBeInsertedInTheBackup()
        {
            using (SmartContext sCtx = new SmartContext())
            {
                int usersInOfflineBefore = this.offlineContext.Users.Count();

                User newUser = new User()
                {
                    UserId = 7777,
                    Name = "Ivan",
                    Email = "*****@*****.**",
                    Note = "note note note",
                    Income = 15543m
                };

                //Simulate that the online storage is not available
                this.LockDbTable("Users");

                sCtx.Add(newUser);

                //Upon saving the changes, the SmartContext will switch to the backup storage and
                //persist the new user object there
                sCtx.SaveChanges();

                int usersInOfflineAfter = this.offlineContext.Users.Count();
                User newUserFromFromBackup = sCtx.GetSingle<User>(usr => usr.UserId == newUser.UserId);
                this.ReleaseLock();
                User newUserFromOnline = this.onlineContext.Users.FirstOrDefault(usr => usr.UserId == newUser.UserId);

                Assert.IsNotNull(newUserFromFromBackup);
                Assert.IsNull(newUserFromOnline);
                Assert.AreNotEqual(usersInOfflineBefore, usersInOfflineAfter);
                Assert.AreEqual(usersInOfflineBefore + 1, usersInOfflineAfter);
            }
        }
        public void TestAutoSwitchSmartContext_SwitchOnDelete_ObjectShouldBeDeletedFromBackup()
        {
            using (SmartContext sCtx = new SmartContext())
            {
                User userToDelete = sCtx.GetSingle<User>();
                int userToDeleteId = userToDelete.UserId;
                sCtx.Delete(userToDelete);

                //Simulate that the online storage is not available
                this.LockDbTable("Users");

                //Upon saving the chanegs the SmartContext will switch to the backup storage
                //and delete the user from there,
                //it will also save the delete operation
                sCtx.SaveChanges();

                User deletedUserFromBackup = sCtx.GetSingle<User>(usr => usr.UserId == userToDelete.UserId);
                this.ReleaseLock();
                User userFromOnline = this.onlineContext.Users.FirstOrDefault(usr => usr.UserId == userToDelete.UserId);

                object deleteOperation = this.offlineContext.GetAll(DeleteOperationDefinition.DeleteOperationFullTypeName)
                    .Cast<object>()
                    .FirstOrDefault(o => o.FieldValue<int>(DeleteOperationDefinition.EntityToDeleteId) == userToDeleteId);

                int deletedEntityId = deleteOperation.FieldValue<int>(DeleteOperationDefinition.EntityToDeleteId);
                string deletedEntityType = deleteOperation.FieldValue<string>((DeleteOperationDefinition.EntityToDeleteType));

                //Deleted from the backup storage
                Assert.IsNull(deletedUserFromBackup);
                //Still present in the online storage
                Assert.IsNotNull(userFromOnline);
                //verify that the delete operation has been backed up
                Assert.AreEqual(userToDeleteId, deletedEntityId);
                Assert.AreEqual("Model.User", deletedEntityType);
            }
        }
        public void TestSmartCotnext_InsertGroupWithExistingRealtedUsers_AllShouldBeBackedUp()
        {
            using (SmartContext sCtx = new SmartContext())
            {
                int usersInOfflineCountBefore = this.offlineContext.Users.Count();
                int groupsInOfflineCountBefore = this.offlineContext.Groups.Count();

                Group newGroup = new Group()
                {
                    GroupId = 8888,
                    Name = "NewGroup",
                    Description = "New Group For Users"
                };
                sCtx.Add(newGroup);
                sCtx.SaveChanges();

                User existingUser = sCtx.GetSingle<User>();

                newGroup.UsersInGroup.Add(existingUser);

                sCtx.SaveChanges();

                int usersInOfflineCountAfter = this.offlineContext.Users.Count();
                int groupsInOfflineCountAfter = this.offlineContext.Groups.Count();
                IEnumerable<User> usersFromOfflineStorage = this.offlineContext.Users.Where(usr => usr.UserId == existingUser.UserId).ToList();
                IEnumerable<Group> groupsFromOfflineStorage = this.offlineContext.Groups.Where(grp => grp.GroupId == newGroup.GroupId).ToList();

                Assert.AreNotEqual(usersInOfflineCountBefore, usersInOfflineCountAfter);
                Assert.AreNotEqual(groupsInOfflineCountBefore, groupsInOfflineCountAfter);
                Assert.AreEqual(1, usersFromOfflineStorage.Count());
                Assert.AreEqual(1, groupsFromOfflineStorage.Count());
            }
        }
        public void TestSmartContext_UpdateUser_UpdatesShouldBeBackedUp()
        {
            using (SmartContext sCtx = new SmartContext())
            {
                User user = sCtx.GetSingle<User>();

                string newUserName = "******";
                user.Name = newUserName;
                sCtx.SaveChanges();

                User userFromOfflineStorage = this.offlineContext.Users.FirstOrDefault(usr => usr.UserId == user.UserId);

                Assert.IsNotNull(userFromOfflineStorage);
                Assert.AreEqual(newUserName, userFromOfflineStorage.Name);
            }
        }
        public void TestSmartContext_RetrieveUser_ShouldBeSavedToOffline()
        {
            using (SmartContext sCtx = new SmartContext())
            {
                int usersInOfflineCountBefore = this.offlineContext.Users.Count();

                User usr = sCtx.GetSingle<User>();
                Assert.IsNotNull(usr);

                int usersInOfflineCountAfter = this.offlineContext.Users.Count();
                User usrFromOfflineStorage = this.offlineContext.Users.FirstOrDefault(u => u.UserId == usr.UserId);

                Assert.IsNotNull(usrFromOfflineStorage);
                Assert.AreEqual(usersInOfflineCountBefore + 1, usersInOfflineCountAfter);
            }
        }
        public void TestSmartContext_RetrieveUserAndRelatedGroup_BothShouldBeSavedToOffline()
        {
            using (SmartContext sCtx = new SmartContext())
            {
                int usersInOfflineCountBefore = this.offlineContext.Users.Count();
                int groupsInOfflineCountBefore = this.offlineContext.Groups.Count();

                FetchStrategy loadWithGroup = new FetchStrategy();
                loadWithGroup.LoadWith<User>(u => u.Group);
                User usr = sCtx.GetSingle<User>(fetchStrategy: loadWithGroup);

                int usersInOfflineCountAfter = this.offlineContext.Users.Count();
                int groupsInOfflineCountAfter = this.offlineContext.Groups.Count();
                User userFromOfflineStorage = this.offlineContext.Users.FirstOrDefault(u => u.UserId == usr.UserId);
                Group groupFromOfflineStorage = this.offlineContext.Groups.FirstOrDefault(grp => grp.GroupId == usr.GroupId);

                Assert.IsNotNull(usr);
                Assert.IsNotNull(userFromOfflineStorage);
                Assert.IsNotNull(groupFromOfflineStorage);
                Assert.AreEqual(usersInOfflineCountBefore + 1, usersInOfflineCountAfter);
                Assert.AreEqual(groupsInOfflineCountBefore + 1, usersInOfflineCountAfter);
            }
        }
        public void TestSmartContext_InsertUsersWithExistingRelatedGroup_AllShouldBeBackedUp()
        {
            using (SmartContext sCtx = new SmartContext())
            {
                int usersInOfflineCountBefore = this.offlineContext.Users.Count();
                int groupsInOfflineCountBefore = this.offlineContext.Groups.Count();

                //The existing related group will actually be backed up the moment
                //it is retrieved from the SmartContext
                Group relatedGroup = sCtx.GetSingle<Group>();

                User newUser1 = new User()
                {
                    UserId = 1337,
                    Name = "Mark",
                    Email = "*****@*****.**",
                    Note = "note note note",
                    Income = 15543m
                };
                newUser1.Group = relatedGroup;

                User newUser2 = new User()
                {
                    UserId = 1338,
                    Name = "Harry",
                    Email = "*****@*****.**",
                    Note = "note note note",
                    Income = 12543m
                };
                newUser2.Group = relatedGroup;

                sCtx.Add(newUser1);
                sCtx.Add(newUser2);
                sCtx.SaveChanges();

                int usersInOfflineCountAfter = this.offlineContext.Users.Count();
                int groupsInOfflineCountAfter = this.offlineContext.Groups.Count();
                IEnumerable<User> usersFromOfflineStorage = this.offlineContext.Users.Where(usr => usr.UserId == newUser1.UserId || usr.UserId == newUser2.UserId).ToList();
                IEnumerable<Group> groupsFromOfflineStorage = this.offlineContext.Groups.Where(grp => grp.GroupId == relatedGroup.GroupId).ToList();

                Assert.AreNotEqual(usersInOfflineCountBefore, usersInOfflineCountAfter);
                Assert.AreNotEqual(groupsInOfflineCountBefore, groupsInOfflineCountAfter);
                Assert.AreEqual(2, usersFromOfflineStorage.Count());
                Assert.AreEqual(1, groupsFromOfflineStorage.Count());
            }
        }