async Task ResetLocalStoreAsync() { _AcquaintanceTable = null; _MobileServiceSQLiteStore?.Dispose(); _MobileServiceSQLiteStore = null; await DeleteOldLocalDatabase().ConfigureAwait(false); _IsInitialized = false; Settings.LocalDataResetIsRequested = false; Settings.DataIsSeeded = false; }
/// <summary> /// Resets the local store. /// </summary> async Task ResetLocalStoreAsync() { _AcquaintanceTable = null; // On UWP, it's necessary to Dispose() and nullify the MobileServiceSQLiteStore before // trying to delete the database file, otherwise an access exception will occur // because of an open file handle. It's okay to do for iOS and Android as well, but not necessary. _MobileServiceSQLiteStore?.Dispose(); _MobileServiceSQLiteStore = null; await DeleteOldLocalDatabase().ConfigureAwait(false); _IsInitialized = false; Settings.LocalDataResetIsRequested = false; Settings.DataIsSeeded = false; }
private async Task CreateSyncConflict(bool autoResolve) { await ClearStore(); bool resolveConflictsOnClient = autoResolve; DateTime now = DateTime.UtcNow; int seed = now.Year * 10000 + now.Month * 100 + now.Day; Log("Using random seed: {0}", seed); Random rndGen = new Random(seed); var offlineReadyClient = CreateClient(); var localStore = new MobileServiceSQLiteStore(StoreFileName); Log("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>(this, offlineReadyClient, conflictHandlingPolicy); await offlineReadyClient.SyncContext.InitializeAsync(localStore, handler); } else { await offlineReadyClient.SyncContext.InitializeAsync(localStore); } Log("Initialized the store and sync context"); var localTable = offlineReadyClient.GetSyncTable <OfflineReadyItem>(); var remoteTable = offlineReadyClient.GetTable <OfflineReadyItem>(); await localTable.PurgeAsync(); Log("Removed all items from the local table"); var item = new OfflineReadyItem(rndGen); await remoteTable.InsertAsync(item); Log("Inserted the item to the remote store:", item); var pullQuery = "$filter=id eq '" + item.Id + "'"; await localTable.PullAsync(null, pullQuery); Log("Changing the item on the server"); item.Age++; await remoteTable.UpdateAsync(item); Log("Updated the item: {0}", item); var localItem = await localTable.LookupAsync(item.Id); Log("Retrieved the item from the local table, now updating it"); localItem.Date = localItem.Date.AddDays(1); await localTable.UpdateAsync(localItem); Log("Updated the item on the local table"); Log("Now trying to pull changes from the server (will trigger a push)"); 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); if (localMergedItem.Equals(expectedMergedItem)) { Log("Item was merged correctly."); } else { errorMessage = string.Format("Error, item not merged correctly. Expected: {0}, Actual: {1}", expectedMergedItem, localMergedItem); } } } catch (MobileServicePushFailedException ex) { Log("Push exception: {0}", ex); if (autoResolve) { errorMessage = "Error, push should have succeeded."; } else { Log("Expected exception was thrown."); } } Log("Cleaning up"); await localTable.DeleteAsync(item); Log("Local table cleaned up. Now sync'ing once more"); await offlineReadyClient.SyncContext.PushAsync(); Log("Done"); localStore.Dispose(); await ClearStore(); if (!String.IsNullOrEmpty(errorMessage)) { Assert.Fail(errorMessage); } }
private async Task AbortPushDuringSync(SyncAbortLocation whereToAbort) { await ClearStore(); SyncAbortLocation abortLocation = whereToAbort; DateTime now = DateTime.UtcNow; int seed = now.Year * 10000 + now.Month * 100 + now.Day; Log("Using random seed: {0}", seed); Random rndGen = new Random(seed); var offlineReadyClient = CreateClient(); var items = Enumerable.Range(0, 10).Select(_ => new OfflineReadyItem(rndGen)).ToArray(); foreach (var item in items) { item.Id = Guid.NewGuid().ToString("D"); } int abortIndex = abortLocation == SyncAbortLocation.Start ? 0 : (abortLocation == SyncAbortLocation.End ? items.Length - 1 : rndGen.Next(1, items.Length - 1)); var idToAbort = items[abortIndex].Id; Log("Will send {0} items, aborting when id = {1}", items.Length, idToAbort); var localStore = new MobileServiceSQLiteStore(StoreFileName); Log("Defined the table on the local store"); localStore.DefineTable <OfflineReadyItem>(); var syncHandler = new AbortingSyncHandler(this, id => id == idToAbort); await offlineReadyClient.SyncContext.InitializeAsync(localStore, syncHandler); Log("Initialized the store and sync context"); var localTable = offlineReadyClient.GetSyncTable <OfflineReadyItem>(); var remoteTable = offlineReadyClient.GetTable <OfflineReadyItem>(); try { foreach (var item in items) { await localTable.InsertAsync(item); } Log("Inserted {0} items in the local table. Now pushing those"); try { await offlineReadyClient.SyncContext.PushAsync(); Assert.Fail("Error, push call should have failed"); } catch (MobileServicePushFailedException ex) { Log("Caught (expected) exception: {0}", ex); } var expectedOperationQueueSize = items.Length - abortIndex; Log("Current operation queue size: {0}", offlineReadyClient.SyncContext.PendingOperations); if (expectedOperationQueueSize != offlineReadyClient.SyncContext.PendingOperations) { Assert.Fail(string.Format("Error, expected {0} items in the queue", expectedOperationQueueSize)); } foreach (var allItemsPushed in new bool[] { false, true }) { HashSet <OfflineReadyItem> itemsInServer, itemsNotInServer; if (allItemsPushed) { itemsInServer = new HashSet <OfflineReadyItem>(items.ToArray()); itemsNotInServer = new HashSet <OfflineReadyItem>(Enumerable.Empty <OfflineReadyItem>()); } else { itemsInServer = new HashSet <OfflineReadyItem>(items.Where((item, index) => index < abortIndex)); itemsNotInServer = new HashSet <OfflineReadyItem>(items.Where((item, index) => index >= abortIndex)); } foreach (var item in items) { var itemFromServer = (await remoteTable.Where(i => i.Id == item.Id).Take(1).ToEnumerableAsync()).FirstOrDefault(); Log("Item with id = {0} from server: {1}", item.Id, itemFromServer == null ? "<<null>>" : itemFromServer.ToString()); if (itemsInServer.Contains(item) && itemFromServer == null) { Assert.Fail(string.Format("Error, the item {0} should have made to the server", item.Id)); } else if (itemsNotInServer.Contains(item) && itemFromServer != null) { Assert.Fail(string.Format("Error, the item {0} should not have made to the server", item.Id)); } } if (!allItemsPushed) { Log("Changing the handler so that it doesn't abort anymore."); syncHandler.AbortCondition = _ => false; Log("Pushing again"); await offlineReadyClient.SyncContext.PushAsync(); Log("Finished pushing all elements"); } } Log("Changing the handler so that it doesn't abort anymore."); syncHandler.AbortCondition = _ => false; Log("Cleaning up"); foreach (var item in items) { await localTable.DeleteAsync(item); } await offlineReadyClient.SyncContext.PushAsync(); Log("Done"); } finally { localStore.Dispose(); ClearStore().Wait(); } }
private async Task NoOptimisticConcurrencyTest() { // If a table does not have a __version column, then offline will still // work, but there will be no conflicts DateTime now = DateTime.UtcNow; int seed = now.Year * 10000 + now.Month * 100 + now.Day; Log("Using random seed: {0}", seed); Random rndGen = new Random(seed); var offlineReadyClient = CreateClient(); var localStore = new MobileServiceSQLiteStore(StoreFileName); Log("Defined the table on the local store"); localStore.DefineTable <OfflineReadyItemNoVersion>(); await offlineReadyClient.SyncContext.InitializeAsync(localStore); Log("Initialized the store and sync context"); var localTable = offlineReadyClient.GetSyncTable <OfflineReadyItemNoVersion>(); var remoteTable = offlineReadyClient.GetTable <OfflineReadyItemNoVersion>(); var item = new OfflineReadyItemNoVersion(rndGen); try { offlineReadyClient.CurrentUser = await Utilities.GetDummyUser(offlineReadyClient); await localTable.InsertAsync(item); Log("Inserted the item to the local store:", item); await offlineReadyClient.SyncContext.PushAsync(); Log("Pushed the changes to the server"); var serverItem = await remoteTable.LookupAsync(item.Id); serverItem.Name = "changed name"; serverItem.Age = 0; await remoteTable.UpdateAsync(serverItem); Log("Server item updated (changes will be overwritten later"); item.Age = item.Age + 1; item.Name = item.Name + " - modified"; await localTable.UpdateAsync(item); Log("Updated item locally, will now push changes to the server: {0}", item); await offlineReadyClient.SyncContext.PushAsync(); serverItem = await remoteTable.LookupAsync(item.Id); Log("Retrieved the item from the server: {0}", serverItem); if (serverItem.Equals(item)) { Log("Items are the same"); } else { Assert.Fail(string.Format("Items are different. Local: {0}; remote: {1}", item, serverItem)); } Log("Cleaning up"); localTable.DeleteAsync(item).Wait(); Log("Local table cleaned up. Now sync'ing once more"); await offlineReadyClient.SyncContext.PushAsync(); } catch (MobileServicePushFailedException ex) { Log("PushResult status: " + ex.PushResult.Status); throw; } finally { offlineReadyClient.Logout(); localStore.Dispose(); ClearStore().Wait(); } }
private async Task BasicOfflineTest() { await ClearStore(); DateTime now = DateTime.UtcNow; int seed = now.Year * 10000 + now.Month * 100 + now.Day; Log("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); Log("Defined the table on the local store"); localStore.DefineTable <OfflineReadyItem>(); await offlineReadyClient.SyncContext.InitializeAsync(localStore); Log("Initialized the store and sync context"); var localTable = offlineReadyClient.GetSyncTable <OfflineReadyItem>(); var remoteTable = offlineReadyClient.GetTable <OfflineReadyItem>(); var item = new OfflineReadyItem(rndGen); try { await localTable.InsertAsync(item); Log("Inserted the item to the local store:", item); Log("Validating that the item is not in the server table"); try { requestsSentToServer++; await remoteTable.LookupAsync(item.Id); Assert.Fail("Error, item is present in the server"); } catch (MobileServiceInvalidOperationException ex) { Log("Ok, item is not in the server: {0}", ex.Message); } Func <int, bool> validateRequestCount = expectedCount => { Log("So far {0} requests sent to the server", handler.RequestCount); if (handler.RequestCount != expectedCount) { Log("Error, expected {0} requests to have been sent to the server", expectedCount); return(false); } else { return(true); } }; if (!validateRequestCount(requestsSentToServer)) { Assert.Fail(string.Format("Error, expected {0} requests to have been sent to the server", requestsSentToServer)); } Log("Pushing changes to the server"); await offlineReadyClient.SyncContext.PushAsync(); requestsSentToServer++; if (!validateRequestCount(requestsSentToServer)) { Assert.Fail(string.Format("Error, expected {0} requests to have been sent to the server", requestsSentToServer)); } Log("Push done; now verifying that item is in the server"); var serverItem = await remoteTable.LookupAsync(item.Id); requestsSentToServer++; Log("Retrieved item from server: {0}", serverItem); if (serverItem.Equals(item)) { Log("Items are the same"); } else { Assert.Fail(string.Format("Items are different. Local: {0}; remote: {1}", item, serverItem)); } Log("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); Log("Item has been updated"); var newItem = new OfflineReadyItem(rndGen); Log("Adding a new item to the local table: {0}", newItem); await localTable.InsertAsync(newItem); if (!validateRequestCount(requestsSentToServer)) { Assert.Fail(string.Format("Error, expected {0} requests to have been sent to the server", requestsSentToServer)); } Log("Pushing the new changes to the server"); await offlineReadyClient.SyncContext.PushAsync(); requestsSentToServer += 2; if (!validateRequestCount(requestsSentToServer)) { Assert.Fail(string.Format("Error, expected {0} requests to have been sent to the server", requestsSentToServer)); } Log("Push done. Verifying changes on the server"); serverItem = await remoteTable.LookupAsync(item.Id); requestsSentToServer++; if (serverItem.Equals(item)) { Log("Updated items are the same"); } else { Assert.Fail(string.Format("Items are different. Local: {0}; remote: {1}", item, serverItem)); } serverItem = await remoteTable.LookupAsync(newItem.Id); requestsSentToServer++; if (serverItem.Equals(newItem)) { Log("New inserted item is the same"); } else { Assert.Fail(string.Format("Items are different. Local: {0}; remote: {1}", item, serverItem)); } Log("Cleaning up"); await localTable.DeleteAsync(item); await localTable.DeleteAsync(newItem); Log("Local table cleaned up. Now sync'ing once more"); await offlineReadyClient.SyncContext.PushAsync(); requestsSentToServer += 2; if (!validateRequestCount(requestsSentToServer)) { Assert.Fail(string.Format("Error, expected {0} requests to have been sent to the server", requestsSentToServer)); } Log("Done"); } catch (MobileServicePushFailedException ex) { Log("Push Result status from MobileServicePushFailedException: " + ex.PushResult.Status); throw; } finally { localStore.Dispose(); ClearStore().Wait(); } }
private async Task AuthenticatedTableSyncTest() { bool isUserLoggedIn = false; DateTime now = DateTime.UtcNow; int seed = now.Year * 10000 + now.Month * 100 + now.Day; Log("Using random seed: {0}", seed); Random rndGen = new Random(seed); var offlineReadyClient = CreateClient(); var localStore = new MobileServiceSQLiteStore(StoreFileName); Log("Defined the table on the local store"); localStore.DefineTable <OfflineReadyItemNoVersion>(); await offlineReadyClient.SyncContext.InitializeAsync(localStore); Log("Initialized the store and sync context"); try { var localTable = offlineReadyClient.GetSyncTable <OfflineReadyItemNoVersion>(); var remoteTable = offlineReadyClient.GetTable <OfflineReadyItemNoVersion>(); var item = new OfflineReadyItemNoVersion(rndGen); await localTable.InsertAsync(item); Log("Inserted the item to the local store:", item); try { await offlineReadyClient.SyncContext.PushAsync(); Log("Pushed the changes to the server"); if (isUserLoggedIn) { Log("As expected, push succeeded"); } else { Assert.Fail("Error, table should only work with authenticated access, but user is not logged in"); } } catch (MobileServicePushFailedException ex) { if (isUserLoggedIn) { Assert.Fail(string.Format("Error, user is logged in but push operation failed: {0}", ex)); } Log("Got expected exception: {0}: {1}", ex.GetType().FullName, ex.Message); Exception inner = ex.InnerException; while (inner != null) { Log(" {0}: {1}", inner.GetType().FullName, inner.Message); inner = inner.InnerException; } } if (!isUserLoggedIn) { Log("Push should have failed, so now will try to log in to complete the push operation"); MobileServiceUser user = await Utilities.GetDummyUser(offlineReadyClient); offlineReadyClient.CurrentUser = user; Log("Logged in as {0}", offlineReadyClient.CurrentUser.UserId); await offlineReadyClient.SyncContext.PushAsync(); Log("Push succeeded"); } await localTable.PurgeAsync(); Log("Purged the local table"); await localTable.PullAsync(null, localTable.Where(i => i.Id == item.Id)); Log("Pulled the data into the local table"); List <OfflineReadyItemNoVersion> serverItems = await localTable.ToListAsync(); Log("Retrieved items from the local table"); Log("Removing item from the remote table"); await remoteTable.DeleteAsync(item); if (!isUserLoggedIn) { offlineReadyClient.Logout(); Log("Logged out again"); } var firstServerItem = serverItems.FirstOrDefault(); if (item.Equals(firstServerItem)) { Log("Data round-tripped successfully"); } else { Assert.Fail(string.Format("Error, data did not round-trip successfully. Expected: {0}, actual: {1}", item, firstServerItem)); } Log("Cleaning up"); await localTable.PurgeAsync(); offlineReadyClient.Logout(); Log("Done"); } finally { localStore.Dispose(); ClearStore().Wait(); offlineReadyClient.Logout(); } }
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)); }
private async Task AbortPushDuringSync(SyncAbortLocation whereToAbort) { ClearStore(); SyncAbortLocation abortLocation = whereToAbort; DateTime now = DateTime.UtcNow; int seed = now.Year * 10000 + now.Month * 100 + now.Day; Random rndGen = new Random(seed); var offlineReadyClient = CreateClient(); var items = Enumerable.Range(0, 10).Select(_ => new OfflineReadyItem(rndGen)).ToArray(); foreach (var item in items) { item.Id = Guid.NewGuid().ToString("D"); } int abortIndex = abortLocation == SyncAbortLocation.Start ? 0 : (abortLocation == SyncAbortLocation.End ? items.Length - 1 : rndGen.Next(1, items.Length - 1)); var idToAbort = items[abortIndex].Id; var localStore = new MobileServiceSQLiteStore(StoreFileName); localStore.DefineTable <OfflineReadyItem>(); var syncHandler = new AbortingSyncHandler(this, id => id == idToAbort); await offlineReadyClient.SyncContext.InitializeAsync(localStore, syncHandler); var localTable = offlineReadyClient.GetSyncTable <OfflineReadyItem>(); var remoteTable = offlineReadyClient.GetTable <OfflineReadyItem>(); try { foreach (var item in items) { await localTable.InsertAsync(item); } await Assert.ThrowsAsync <MobileServicePushFailedException>(() => offlineReadyClient.SyncContext.PushAsync()); var expectedOperationQueueSize = items.Length - abortIndex; Assert.False(expectedOperationQueueSize != offlineReadyClient.SyncContext.PendingOperations); foreach (var allItemsPushed in new bool[] { false, true }) { HashSet <OfflineReadyItem> itemsInServer, itemsNotInServer; if (allItemsPushed) { itemsInServer = new HashSet <OfflineReadyItem>(items.ToArray()); itemsNotInServer = new HashSet <OfflineReadyItem>(Enumerable.Empty <OfflineReadyItem>()); } else { itemsInServer = new HashSet <OfflineReadyItem>(items.Where((item, index) => index < abortIndex)); itemsNotInServer = new HashSet <OfflineReadyItem>(items.Where((item, index) => index >= abortIndex)); } foreach (var item in items) { var itemFromServer = (await remoteTable.Where(i => i.Id == item.Id).Take(1).ToEnumerableAsync()).FirstOrDefault(); Assert.False(itemsInServer.Contains(item) && itemFromServer == null); Assert.False(itemsNotInServer.Contains(item) && itemFromServer != null); } if (!allItemsPushed) { syncHandler.AbortCondition = _ => false; await offlineReadyClient.SyncContext.PushAsync(); } } syncHandler.AbortCondition = _ => false; foreach (var item in items) { await localTable.DeleteAsync(item); } await offlineReadyClient.SyncContext.PushAsync(); } finally { localStore.Dispose(); ClearStore(); } }
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(); } }