Ejemplo n.º 1
0
        private static ZumoTest CreateSyncConflictTest(bool autoResolve)
        {
            var testName = "Offline - dealing with conflicts - " +
                           (autoResolve ? "client resolves conflicts" : "push fails after conflicts");
            bool resolveConflictsOnClient = autoResolve;

            return(new ZumoTest(testName, async delegate(ZumoTest test)
            {
                DateTime now = DateTime.UtcNow;
                int seed = now.Year * 10000 + now.Month * 100 + now.Day;
                test.AddLog("Using random seed: {0}", seed);
                Random rndGen = new Random(seed);

                var offlineReadyClient = CreateClient();

                var localStore = new MobileServiceSQLiteStore(StoreFileName);
                test.AddLog("Defined the table on the local store");
                localStore.DefineTable <OfflineReadyItem>();

                ConflictResolvingSyncHandler <OfflineReadyItem> .ConflictResolution conflictHandlingPolicy;
                conflictHandlingPolicy = (client, server) =>
                                         new OfflineReadyItem
                {
                    Id = client.Id,
                    Age = Math.Max(client.Age, server.Age),
                    Date = client.Date > server.Date ? client.Date : server.Date,
                    Flag = client.Flag || server.Flag,
                    FloatingNumber = Math.Max(client.FloatingNumber, server.FloatingNumber),
                    Name = client.Name
                };
                if (resolveConflictsOnClient)
                {
                    var handler = new ConflictResolvingSyncHandler <OfflineReadyItem>(test, offlineReadyClient, conflictHandlingPolicy);
                    await offlineReadyClient.SyncContext.InitializeAsync(localStore, handler);
                }
                else
                {
                    await offlineReadyClient.SyncContext.InitializeAsync(localStore);
                }

                test.AddLog("Initialized the store and sync context");

                var localTable = offlineReadyClient.GetSyncTable <OfflineReadyItem>();
                var remoteTable = offlineReadyClient.GetTable <OfflineReadyItem>();

                await localTable.PurgeAsync();
                test.AddLog("Removed all items from the local table");

                var item = new OfflineReadyItem(rndGen);
                await remoteTable.InsertAsync(item);
                test.AddLog("Inserted the item to the remote store:", item);

                var pullQuery = "$filter=id eq '" + item.Id + "'";
                await localTable.PullAsync(null, pullQuery);

                test.AddLog("Changing the item on the server");
                item.Age++;
                await remoteTable.UpdateAsync(item);
                test.AddLog("Updated the item: {0}", item);

                var localItem = await localTable.LookupAsync(item.Id);
                test.AddLog("Retrieved the item from the local table, now updating it");
                localItem.Date = localItem.Date.AddDays(1);
                await localTable.UpdateAsync(localItem);
                test.AddLog("Updated the item on the local table");

                test.AddLog("Now trying to pull changes from the server (will trigger a push)");
                bool testResult = true;
                try
                {
                    await localTable.PullAsync(null, pullQuery);
                    if (!autoResolve)
                    {
                        test.AddLog("Error, pull (push) should have caused a conflict, but none happened.");
                        testResult = false;
                    }
                    else
                    {
                        var expectedMergedItem = conflictHandlingPolicy(localItem, item);
                        var localMergedItem = await localTable.LookupAsync(item.Id);
                        if (localMergedItem.Equals(expectedMergedItem))
                        {
                            test.AddLog("Item was merged correctly.");
                        }
                        else
                        {
                            test.AddLog("Error, item not merged correctly. Expected: {0}, Actual: {1}", expectedMergedItem, localMergedItem);
                            testResult = false;
                        }
                    }
                }
                catch (MobileServicePushFailedException ex)
                {
                    test.AddLog("Push exception: {0}", ex);
                    if (autoResolve)
                    {
                        test.AddLog("Error, push should have succeeded.");
                        testResult = false;
                    }
                    else
                    {
                        test.AddLog("Expected exception was thrown.");
                    }
                }

                test.AddLog("Cleaning up");
                await localTable.DeleteAsync(item);
                test.AddLog("Local table cleaned up. Now sync'ing once more");
                await offlineReadyClient.SyncContext.PushAsync();
                test.AddLog("Done");

                return testResult;
            }, ZumoTestGlobals.RuntimeFeatureNames.STRING_ID_TABLES));
        }
        private async Task CreateSyncConflict(bool autoResolve)
        {
            ClearStore();
            bool     resolveConflictsOnClient = autoResolve;
            DateTime now    = DateTime.UtcNow;
            int      seed   = now.Year * 10000 + now.Month * 100 + now.Day;
            Random   rndGen = new Random(seed);

            var offlineReadyClient = CreateClient();

            var localStore = new MobileServiceSQLiteStore(StoreFileName);

            localStore.DefineTable <OfflineReadyItem>();

            ConflictResolvingSyncHandler <OfflineReadyItem> .ConflictResolution conflictHandlingPolicy;
            conflictHandlingPolicy = (client, server) =>
                                     new OfflineReadyItem
            {
                Id             = client.Id,
                Age            = Math.Max(client.Age, server.Age),
                Date           = client.Date > server.Date ? client.Date : server.Date,
                Flag           = client.Flag || server.Flag,
                FloatingNumber = Math.Max(client.FloatingNumber, server.FloatingNumber),
                Name           = client.Name
            };
            if (resolveConflictsOnClient)
            {
                var handler = new ConflictResolvingSyncHandler <OfflineReadyItem>(this, offlineReadyClient, conflictHandlingPolicy);
                await offlineReadyClient.SyncContext.InitializeAsync(localStore, handler);
            }
            else
            {
                await offlineReadyClient.SyncContext.InitializeAsync(localStore);
            }

            var localTable  = offlineReadyClient.GetSyncTable <OfflineReadyItem>();
            var remoteTable = offlineReadyClient.GetTable <OfflineReadyItem>();

            await localTable.PurgeAsync();

            var item = new OfflineReadyItem(rndGen);
            await remoteTable.InsertAsync(item);

            var pullQuery = "$filter=id eq '" + item.Id + "'";
            await localTable.PullAsync(null, pullQuery);

            item.Age++;
            await remoteTable.UpdateAsync(item);

            var localItem = await localTable.LookupAsync(item.Id);

            localItem.Date = localItem.Date.AddDays(1);
            await localTable.UpdateAsync(localItem);

            string errorMessage = string.Empty;

            try
            {
                await localTable.PullAsync(null, pullQuery);

                if (!autoResolve)
                {
                    errorMessage = "Error, pull (push) should have caused a conflict, but none happened.";
                }
                else
                {
                    var expectedMergedItem = conflictHandlingPolicy(localItem, item);
                    var localMergedItem    = await localTable.LookupAsync(item.Id);

                    Assert.Equal(expectedMergedItem, localMergedItem);
                }
            }
            catch (MobileServicePushFailedException)
            {
                if (autoResolve)
                {
                    errorMessage = "Error, push should have succeeded.";
                }
            }

            await localTable.DeleteAsync(item);

            await offlineReadyClient.SyncContext.PushAsync();

            localStore.Dispose();
            ClearStore();
            Assert.True(String.IsNullOrEmpty(errorMessage));
        }
Ejemplo n.º 3
0
        private static ZumoTest CreateBasicTest()
        {
            return(new ZumoTest("Basic offline scenario", async delegate(ZumoTest test)
            {
                DateTime now = DateTime.UtcNow;
                int seed = now.Year * 10000 + now.Month * 100 + now.Day;
                test.AddLog("Using random seed: {0}", seed);
                Random rndGen = new Random(seed);

                CountingHandler handler = new CountingHandler();
                var requestsSentToServer = 0;
                var offlineReadyClient = CreateClient(handler);

                var localStore = new MobileServiceSQLiteStore(StoreFileName);
                test.AddLog("Defined the table on the local store");
                localStore.DefineTable <OfflineReadyItem>();

                await offlineReadyClient.SyncContext.InitializeAsync(localStore);
                test.AddLog("Initialized the store and sync context");

                var localTable = offlineReadyClient.GetSyncTable <OfflineReadyItem>();
                var remoteTable = offlineReadyClient.GetTable <OfflineReadyItem>();

                var item = new OfflineReadyItem(rndGen);
                await localTable.InsertAsync(item);
                test.AddLog("Inserted the item to the local store:", item);

                test.AddLog("Validating that the item is not in the server table");
                try
                {
                    requestsSentToServer++;
                    await remoteTable.LookupAsync(item.Id);
                    test.AddLog("Error, item is present in the server");
                    return false;
                }
                catch (MobileServiceInvalidOperationException ex)
                {
                    test.AddLog("Ok, item is not in the server: {0}", ex.Message);
                }

                Func <int, bool> validateRequestCount = expectedCount =>
                {
                    test.AddLog("So far {0} requests sent to the server", handler.RequestCount);
                    if (handler.RequestCount != expectedCount)
                    {
                        test.AddLog("Error, expected {0} requests to have been sent to the server", expectedCount);
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                };

                if (!validateRequestCount(requestsSentToServer))
                {
                    return false;
                }

                test.AddLog("Pushing changes to the server");
                await offlineReadyClient.SyncContext.PushAsync();
                requestsSentToServer++;

                if (!validateRequestCount(requestsSentToServer))
                {
                    return false;
                }

                test.AddLog("Push done; now verifying that item is in the server");

                var serverItem = await remoteTable.LookupAsync(item.Id);
                requestsSentToServer++;
                test.AddLog("Retrieved item from server: {0}", serverItem);
                if (serverItem.Equals(item))
                {
                    test.AddLog("Items are the same");
                }
                else
                {
                    test.AddLog("Items are different. Local: {0}; remote: {1}", item, serverItem);
                    return false;
                }

                test.AddLog("Now updating the item locally");
                item.Flag = !item.Flag;
                item.Age++;
                item.Date = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, now.Millisecond, DateTimeKind.Utc);
                await localTable.UpdateAsync(item);
                test.AddLog("Item has been updated");

                var newItem = new OfflineReadyItem(rndGen);
                test.AddLog("Adding a new item to the local table: {0}", newItem);
                await localTable.InsertAsync(newItem);

                if (!validateRequestCount(requestsSentToServer))
                {
                    return false;
                }

                test.AddLog("Pushing the new changes to the server");
                await offlineReadyClient.SyncContext.PushAsync();
                requestsSentToServer += 2;

                if (!validateRequestCount(requestsSentToServer))
                {
                    return false;
                }

                test.AddLog("Push done. Verifying changes on the server");
                serverItem = await remoteTable.LookupAsync(item.Id);
                requestsSentToServer++;
                if (serverItem.Equals(item))
                {
                    test.AddLog("Updated items are the same");
                }
                else
                {
                    test.AddLog("Items are different. Local: {0}; remote: {1}", item, serverItem);
                    return false;
                }

                serverItem = await remoteTable.LookupAsync(newItem.Id);
                requestsSentToServer++;
                if (serverItem.Equals(newItem))
                {
                    test.AddLog("New inserted item is the same");
                }
                else
                {
                    test.AddLog("Items are different. Local: {0}; remote: {1}", item, serverItem);
                    return false;
                }

                test.AddLog("Cleaning up");
                await localTable.DeleteAsync(item);
                await localTable.DeleteAsync(newItem);
                test.AddLog("Local table cleaned up. Now sync'ing once more");
                await offlineReadyClient.SyncContext.PushAsync();
                requestsSentToServer += 2;
                if (!validateRequestCount(requestsSentToServer))
                {
                    return false;
                }
                test.AddLog("Done");
                return true;
            }, ZumoTestGlobals.RuntimeFeatureNames.STRING_ID_TABLES));
        }
        public async Task BasicOfflineTest()
        {
            ClearStore();
            DateTime now    = DateTime.UtcNow;
            int      seed   = now.Year * 10000 + now.Month * 100 + now.Day;
            Random   rndGen = new Random(seed);

            CountingHandler handler = new CountingHandler();
            var             requestsSentToServer = 0;
            var             offlineReadyClient   = CreateClient(handler);

            var localStore = new MobileServiceSQLiteStore(StoreFileName);

            localStore.DefineTable <OfflineReadyItem>();

            await offlineReadyClient.SyncContext.InitializeAsync(localStore);

            var localTable  = offlineReadyClient.GetSyncTable <OfflineReadyItem>();
            var remoteTable = offlineReadyClient.GetTable <OfflineReadyItem>();

            var item = new OfflineReadyItem(rndGen);

            try
            {
                await localTable.InsertAsync(item);

                await Assert.ThrowsAsync <MobileServiceInvalidOperationException>(async() =>
                {
                    requestsSentToServer++;
                    await remoteTable.LookupAsync(item.Id);
                });

                Func <int, bool> validateRequestCount = expectedCount => (handler.RequestCount == expectedCount);
                Assert.True(validateRequestCount(requestsSentToServer));

                await offlineReadyClient.SyncContext.PushAsync();

                requestsSentToServer++;

                Assert.True(validateRequestCount(requestsSentToServer));

                var serverItem = await remoteTable.LookupAsync(item.Id);

                requestsSentToServer++;
                Assert.Equal(serverItem, item);

                item.Flag = !item.Flag;
                item.Age++;
                item.Date = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, now.Millisecond, DateTimeKind.Utc);
                await localTable.UpdateAsync(item);

                var newItem = new OfflineReadyItem(rndGen);
                await localTable.InsertAsync(newItem);

                Assert.True(validateRequestCount(requestsSentToServer));

                await offlineReadyClient.SyncContext.PushAsync();

                requestsSentToServer += 2;

                Assert.True(validateRequestCount(requestsSentToServer));

                serverItem = await remoteTable.LookupAsync(item.Id);

                requestsSentToServer++;
                Assert.Equal(serverItem, item);

                serverItem = await remoteTable.LookupAsync(newItem.Id);

                requestsSentToServer++;
                Assert.Equal(serverItem, newItem);

                await localTable.DeleteAsync(item);

                await localTable.DeleteAsync(newItem);

                await offlineReadyClient.SyncContext.PushAsync();

                requestsSentToServer += 2;
                Assert.True(validateRequestCount(requestsSentToServer));
            }
            catch (MobileServicePushFailedException)
            {
                throw;
            }
            finally
            {
                localStore.Dispose();
                ClearStore();
            }
        }