public async Task DefineTable_Throws_WhenStoreIsInitialized() { var store = new MobileServiceSQLiteStore(TestDbName); await store.InitializeAsync(); var ex = Throws<InvalidOperationException>(() => store.DefineTable(TestTable, new JObject())); Assert.AreEqual(ex.Message, "Cannot define a table after the store has been initialized."); }
public async Task InitializeAsync_InitializesTheStore() { TestUtilities.DropTestTable(TestDbName, TestTable); var store = new MobileServiceSQLiteStore(TestDbName); store.DefineTable(TestTable, new JObject() { {"id", String.Empty }, {"createdAt", DateTime.UtcNow} }); await store.InitializeAsync(); }
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(); } }
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(); } }
public async Task UpsertAsync_Throws_WhenColumnInItemIsNotDefinedAndItIsLocal() { TestUtilities.DropTestTable(TestDbName, TestTable); using (var store = new MobileServiceSQLiteStore(TestDbName)) { store.DefineTable(TestTable, new JObject() { { "id", String.Empty }, { "dob", DateTime.UtcNow } }); await store.InitializeAsync(); var ex = await ThrowsAsync<InvalidOperationException>(() => store.UpsertAsync(TestTable, new[] { new JObject() { { "notDefined", "okok" } } }, ignoreMissingColumns: false)); Assert.AreEqual(ex.Message, "Column with name 'notDefined' is not defined on the local table 'todo'."); } }
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 { localStore.Dispose(); ClearStore(); } await offlineReadyClient.LogoutAsync(); }
private async Task CreateSyncConflict(bool autoResolve) { 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(); ClearStore(); if (!String.IsNullOrEmpty(errorMessage)) { Assert.Fail(errorMessage); } }
private static void DefineTables(MobileServiceSQLiteStore store) { store.DefineTable <TodoItem>(); }
/*********************************************************************/ /* Define the Tables */ /*********************************************************************/ public void DefineTables() { _eagleDatabase.DefineTable <Assignment>(); _eagleDatabase.DefineTable <Course>(); _eagleDatabase.DefineTable <FourWindsItem>(); _eagleDatabase.DefineTable <VarsityItem>(); _eagleDatabase.DefineTable <GrabAndGoItem>(); _eagleDatabase.DefineTable <Student>(); _eagleDatabase.DefineTable <AzureToken>(); _eagleDatabase.DefineTable <LocalToken>(); _eagleDatabase.DefineTable <Events>(); _eagleDatabase.DefineTable <StudentEvent>(); _eagleDatabase.DefineTable <EventSlot>(); _eagleDatabase.DefineTable <ClassAttendance>(); _eagleDatabase.DefineTable <Offense>(); _eagleDatabase.DefineTable <OffenseCategory>(); _eagleDatabase.DefineTable <ProfessorTimes>(); }
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)); }
private static ZumoTest CreateNoOptimisticConcurrencyTest() { // If a table does not have a __version column, then offline will still // work, but there will be no conflicts return(new ZumoTest("Offline without version column", async delegate(ZumoTest test) { if (ZumoTestGlobals.Instance.IsNetRuntime) { return true; } 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 <OfflineReadyItemNoVersion>(); await offlineReadyClient.SyncContext.InitializeAsync(localStore); test.AddLog("Initialized the store and sync context"); var localTable = offlineReadyClient.GetSyncTable <OfflineReadyItemNoVersion>(); var remoteTable = offlineReadyClient.GetTable <OfflineReadyItemNoVersion>(); var item = new OfflineReadyItemNoVersion(rndGen); await localTable.InsertAsync(item); test.AddLog("Inserted the item to the local store:", item); await offlineReadyClient.SyncContext.PushAsync(); test.AddLog("Pushed the changes to the server"); var serverItem = await remoteTable.LookupAsync(item.Id); serverItem.Name = "changed name"; serverItem.Age = 0; await remoteTable.UpdateAsync(serverItem); test.AddLog("Server item updated (changes will be overwritten later"); item.Age = item.Age + 1; item.Name = item.Name + " - modified"; await localTable.UpdateAsync(item); test.AddLog("Updated item locally, will now push changes to the server: {0}", item); await offlineReadyClient.SyncContext.PushAsync(); serverItem = await remoteTable.LookupAsync(item.Id); test.AddLog("Retrieved the item from the 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("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 true; })); }
public void Init(MobileServiceSQLiteStore store) { client = Xamarin.Forms.DependencyService.Get <IAzureClient>(); store.DefineTable <T>(); SyncTable = client.MobileService.GetSyncTable <T>(); }
public async Task InitializeAsync() { var file = DependencyService.Get <IDatabaseConnection>().DbConnection(dbVersion); _store = new MobileServiceSQLiteStore(file); _store.DefineTable <Game>(); _store.DefineTable <Player>(); _store.DefineTable <GamePlayer>(); _store.DefineTable <Venue>(); _store.DefineTable <VenueAvailabilityPeriod>(); _store.DefineTable <VenueFacilities>(); _store.DefineTable <Facility>(); _store.DefineTable <Availability>(); _store.DefineTable <AvailabilityPeriod>(); _store.DefineTable <Tee>(); _store.DefineTable <Score>(); #if OFFLINE_SYNC_ENABLED await App.MobileService.SyncContext.InitializeAsync(_store).ConfigureAwait(false); await CleanupGames(); //var players = await PlayersTable.ToListAsync(); //if (players.Count == 0) //{ await SyncAsync().ConfigureAwait(false); //} #endif MessagingCenter.Send(this, ServiceMessage.DataServiceInitialized); }
public static async Task InitStore(MobileServiceClient client) { try { if (_databaseInitialized) { return; } var store = new MobileServiceSQLiteStore(Constants.DbFileName); store.DefineTable <UserAccount>(); //INIT all data tables here //Initializes the SyncContext using the default IMobileServiceSyncHandler. var initializeAsync = SharedClient.CurrentClient?.SyncContext.InitializeAsync(store); if (initializeAsync != null) { try { await initializeAsync; } catch (Exception e) { Console.WriteLine(e); throw; } } #if FAKEDATA if (Settings.FirstRun) { //Pre-fill tables //wishes var wishesList = new List <Wish>(FakeDataGenerator.GetWishes()); var wishesRepository = App.DryIocContainer.Resolve <IWishesRepository>(); foreach (var wish in wishesList) { await wishesRepository.CreateWishAsync(wish); } //if (!Settings.InitialWizardRequired) //{ ///else we would never get the accounts list there var accountsSms = FakeDataGenerator.GetAccountsRepositorySms().ToList(); var bankAccountsSmsRepository = App.DryIocContainer.Resolve <IBankAccountsSmsRepository>(); foreach (var accountSms in accountsSms) { await bankAccountsSmsRepository.CreateAccountAsync(accountSms); } // } var accountsApi = FakeDataGenerator.GetAccountsApiRepository1().ToList(); var bankAccountsApi = App.DryIocContainer.Resolve <IBankAccountsApiRepository>(); foreach (var accountApi in accountsApi) { await bankAccountsApi.CreateAccountAsync(accountApi); } var banks = FakeDataGenerator.GetDescriptorApiRepositorySms().ToList(); var bankAccountsSmsDescriptors = App.DryIocContainer.Resolve <IBankAccountDescriptorSmsRepository>(); foreach (var accountDescriptorSms in banks) { await bankAccountsSmsDescriptors.CreateAccountDescriptorAsync(accountDescriptorSms); } var banksApi = FakeDataGenerator.GetDescriptorApiRepositoryApi().ToList(); var bankAccountsApiDescriptors = App.DryIocContainer.Resolve <IBankAccountDescriptorApiRepository>(); foreach (var accountDescriptorApi in banksApi) { await bankAccountsApiDescriptors.CreateAccountDescriptorAsync(accountDescriptorApi); } var regularPaymentTemplates = FakeDataGenerator.GetRegularPaymentTemplates().ToList(); var regularPaymentTemplatesRepository = App.DryIocContainer.Resolve <IRegularPaymentTemplatesRepository>(); foreach (var regularPaymentTemplate in regularPaymentTemplates) { await regularPaymentTemplatesRepository.CreateRegularPaymentTemplateAsync( regularPaymentTemplate); } var regularPayments = FakeDataGenerator.GetRegularPayments().ToList(); var regularPaymentsRepository = App.DryIocContainer.Resolve <IRegularPaymentsRepository>(); foreach (var regularPaymentTemplate in regularPayments) { await regularPaymentsRepository.CreateRegularPaymentAsync( regularPaymentTemplate); } var bankTemplates = FakeDataGenerator.GetBankTemplates().ToList(); var bankTemplatesRepository = App.DryIocContainer.Resolve <IBankTemplateRepository>(); foreach (var templateBank in bankTemplates) { await bankTemplatesRepository.CreateTemplateAsync(templateBank); } var regularPaymentsPaid = FakeDataGenerator.GetRegularPaymentsPaid().ToList(); var regularPaymentsPaidRepository = App.DryIocContainer.Resolve <IRegularPaymentsPaidRepository>(); foreach (var regularPaymentPaid in regularPaymentsPaid) { await regularPaymentsPaidRepository.CreateRegularPaymentPaidAsync(regularPaymentPaid); } } #endif if (Settings.FirstRun) { //Pre-fill tables } Settings.FirstRun = false; _databaseInitialized = true; } catch (Exception e) { Console.WriteLine(e); throw; } }
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 Upsert_ThenLookup_ThenUpsert_ThenDelete_ThenLookup() { TestUtilities.DropTestTable(TestDbName, TestTable); using (var store = new MobileServiceSQLiteStore(TestDbName)) { // define item with all type of supported fields var originalItem = new JObject() { { "id", "abc" }, { "bool", true }, { "int", 45 }, { "double", 123.45d }, { "guid", Guid.NewGuid() }, { "date", testDate }, { "options", new JObject(){ {"class", "A"} } }, { "friends", new JArray(){ "Eric", "Jeff" } } }; store.DefineTable(TestTable, originalItem); // create the table await store.InitializeAsync(); // first add an item await store.UpsertAsync(TestTable, new[] { originalItem }, ignoreMissingColumns: false); // read the item back JObject itemRead = await store.LookupAsync(TestTable, "abc"); // make sure everything was persisted the same Assert.AreEqual(originalItem.ToString(), itemRead.ToString()); // change the item originalItem["double"] = 111.222d; // upsert the item await store.UpsertAsync(TestTable, new[] { originalItem }, ignoreMissingColumns: false); // read the updated item JObject updatedItem = await store.LookupAsync(TestTable, "abc"); // make sure the float was updated Assert.AreEqual(updatedItem.Value<double>("double"), 111.222d); // make sure the item is same as updated item Assert.AreEqual(originalItem.ToString(), updatedItem.ToString()); // make sure item is not same as its initial state Assert.AreNotEqual(originalItem.ToString(), itemRead.ToString()); // now delete the item await store.DeleteAsync(TestTable, new[] { "abc" }); // now read it back JObject item4 = await store.LookupAsync(TestTable, "abc"); // it should be null because it doesn't exist Assert.IsNull(item4); } }
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)); }
public static void DefineTestTable(MobileServiceSQLiteStore store) { store.DefineTable(TestTable, new JObject() { { "id", String.Empty }, { "text", String.Empty }, { "createdAt", DateTime.Now } }); }
private static ZumoTest CreateSyncTestForAuthenticatedTable(bool userIsLoggedIn) { bool isLoggedIn = userIsLoggedIn; var testName = "Sync test for authenticated table, with user " + (isLoggedIn ? "logged in" : "not logged in"); 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 <OfflineReadyItemNoVersion>(); await offlineReadyClient.SyncContext.InitializeAsync(localStore); test.AddLog("Initialized the store and sync context"); var localTable = offlineReadyClient.GetSyncTable <OfflineReadyItemNoVersion>(); var remoteTable = offlineReadyClient.GetTable <OfflineReadyItemNoVersion>(); var item = new OfflineReadyItemNoVersion(rndGen); await localTable.InsertAsync(item); test.AddLog("Inserted the item to the local store:", item); try { await offlineReadyClient.SyncContext.PushAsync(); test.AddLog("Pushed the changes to the server"); if (isLoggedIn) { test.AddLog("As expected, push succeeded"); } else { test.AddLog("Error, table should only work with authenticated access, but user is not logged in"); return false; } } catch (MobileServicePushFailedException ex) { if (isLoggedIn) { test.AddLog("Error, user is logged in but push operation failed: {0}", ex); return false; } test.AddLog("Got expected exception: {0}: {1}", ex.GetType().FullName, ex.Message); Exception inner = ex.InnerException; while (inner != null) { test.AddLog(" {0}: {1}", inner.GetType().FullName, inner.Message); inner = inner.InnerException; } } if (!isLoggedIn) { test.AddLog("Push should have failed, so now will try to log in to complete the push operation"); await offlineReadyClient.LoginAsync(MobileServiceAuthenticationProvider.Facebook); test.AddLog("Logged in as {0}", offlineReadyClient.CurrentUser.UserId); await offlineReadyClient.SyncContext.PushAsync(); test.AddLog("Push succeeded"); } await localTable.PurgeAsync(); test.AddLog("Purged the local table"); await localTable.PullAsync(null, localTable.Where(i => i.Id == item.Id)); test.AddLog("Pulled the data into the local table"); List <OfflineReadyItemNoVersion> serverItems = await localTable.ToListAsync(); test.AddLog("Retrieved items from the local table"); test.AddLog("Removing item from the remote table"); await remoteTable.DeleteAsync(item); if (!isLoggedIn) { offlineReadyClient.Logout(); test.AddLog("Logged out again"); } var firstServerItem = serverItems.FirstOrDefault(); bool testResult = true; if (item.Equals(firstServerItem)) { test.AddLog("Data round-tripped successfully"); } else { test.AddLog("Error, data did not round-trip successfully. Expected: {0}, actual: {1}", item, firstServerItem); testResult = false; } test.AddLog("Cleaning up"); await localTable.PurgeAsync(); test.AddLog("Done"); return testResult; }) { CanRunUnattended = false }); }
public async Task InitializeAsync() { MobileServiceSQLiteStore store; lock (locker) { if (IsInitialized) { return; } IsInitialized = true; var dbId = Settings.DatabaseId; var path = $"syncstore{dbId}.db"; // Old app service from the app-conference demo. Check: https://github.com/xamarinhq/app-conference for more information //MobileService = new MobileServiceClient ("https://xamarinevolveappdemo.azurewebsites.net"); MobileService = new MobileServiceClient("https://megsoftconference.azurewebsites.net/"); store = new MobileServiceSQLiteStore(path); store.DefineTable <Category> (); store.DefineTable <Favorite> (); store.DefineTable <Notification> (); store.DefineTable <FeaturedEvent> (); store.DefineTable <Feedback> (); store.DefineTable <Room> (); store.DefineTable <Session> (); store.DefineTable <Speaker> (); store.DefineTable <Sponsor> (); store.DefineTable <SponsorLevel> (); store.DefineTable <StoreSettings> (); store.DefineTable <MiniHack> (); } await MobileService.SyncContext.InitializeAsync(store, new MobileServiceSyncHandler()).ConfigureAwait(false); await LoadCachedTokenAsync().ConfigureAwait(false); }
public async Task InitializeAsync() { MobileServiceSQLiteStore store; lock (locker) { if (IsInitialized) { return; } IsInitialized = true; var dbId = Settings.DatabaseId; string path = ""; if (dbId == 0) { path = $"syncstore.db"; } else { path = $"syncstore{dbId}.db"; } MobileService = new MobileServiceClient(Constants.EndUrl); store = new MobileServiceSQLiteStore(path); store.DefineTable <Partner>(); store.DefineTable <PartnerCategory>(); store.DefineTable <Country>(); store.DefineTable <Currency>(); store.DefineTable <Models.DataObjects.PartnerGrade>(); store.DefineTable <PartnerTitle>(); store.DefineTable <User>(); store.DefineTable <SaleOrder>(); store.DefineTable <SaleOrderLine>(); store.DefineTable <Message>(); store.DefineTable <Checkin>(); store.DefineTable <Document>(); store.DefineTable <Company>(); store.DefineTable <AccountTax>(); store.DefineTable <Accessory>(); store.DefineTable <Saddle>(); store.DefineTable <Service>(); store.DefineTable <Models.DataObjects.State>(); store.DefineTable <Contract>(); store.DefineTable <StoreSettings>(); store.DefineTable <SaddleAttribute>(); store.DefineTable <SaddleModel>(); store.DefineTable <SaddleValue>(); //TODO Add rest of the tables } await MobileService.SyncContext.InitializeAsync(store, new MobileServiceSyncHandler()).ConfigureAwait(false); await LoadCachedTokenAsync().ConfigureAwait(false); }
public async Task InitializeAsync() { MobileServiceSQLiteStore store; lock (locker) { if (IsInitialized) { return; } IsInitialized = true; var dbId = Settings.DatabaseId; var path = $"syncstore{dbId}.db"; MobileService = new MobileServiceClient("https://utahopensourceappdemo.azurewebsites.net"); store = new MobileServiceSQLiteStore(path); store.DefineTable <Category> (); store.DefineTable <Favorite> (); store.DefineTable <Notification> (); store.DefineTable <FeaturedEvent> (); store.DefineTable <Feedback> (); store.DefineTable <Room> (); store.DefineTable <Session> (); store.DefineTable <Speaker> (); store.DefineTable <Sponsor> (); store.DefineTable <SponsorLevel> (); store.DefineTable <StoreSettings> (); store.DefineTable <MiniHack> (); } await MobileService.SyncContext.InitializeAsync(store, new MobileServiceSyncHandler()).ConfigureAwait(false); await LoadCachedTokenAsync().ConfigureAwait(false); }
public PatientDatabase(string dbPath) { database = new MobileServiceSQLiteStore(dbPath); database.DefineTable <Patient>(); database.InitializeAsync().Wait(); }
private async Task AbortPushDuringSync(SyncAbortLocation whereToAbort) { 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", items.Length); 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(); } }
public async Task InitializeAsync() { MobileServiceSQLiteStore store; lock (locker) { if (IsInitialized) { return; } IsInitialized = true; MobileService = new MobileServiceClient(Constants.ApplicationURL); var dbId = Settings.DatabaseId; string path = ""; if (dbId == 0) { path = $"syncstore.db"; } else { path = $"syncstore{dbId}.db"; } store = new MobileServiceSQLiteStore(path); store.DefineTable <ContactCustomField>(); store.DefineTable <ContactCustomFieldSource>(); store.DefineTable <ContactCustomFieldSourceEntry>(); store.DefineTable <Contact>(); store.DefineTable <Company>(); store.DefineTable <Checkin>(); store.DefineTable <CollectSource>(); store.DefineTable <SalesTeam>(); store.DefineTable <UserSalesTeam>(); store.DefineTable <Tag>(); store.DefineTable <Notification>(); store.DefineTable <Note>(); store.DefineTable <CheckinType>(); store.DefineTable <Opportunity>(); store.DefineTable <ContactSequence>(); store.DefineTable <User>(); //TODO Add rest of the tables } await MobileService.SyncContext.InitializeAsync(store, new MobileServiceSyncHandler()).ConfigureAwait(false); LoadCachedTokenAsync(); }
public async Task Upsert_ThenLookup_ThenUpsert_ThenDelete_ThenLookup() { TestUtilities.DropTestTable(TestDbName, TestTable); using (var store = new MobileServiceSQLiteStore(TestDbName)) { // define item with all type of supported fields var originalItem = new JObject() { { "id", "abc" }, { "bool", true }, { "int", 45 }, { "double", 123.45d }, { "guid", Guid.NewGuid() }, { "date", testDate }, { "options", new JObject() { { "class", "A" } } }, { "friends", new JArray() { "Eric", "Jeff" } } }; store.DefineTable(TestTable, originalItem); // create the table await store.InitializeAsync(); // first add an item await store.UpsertAsync(TestTable, new[] { originalItem }, ignoreMissingColumns : false); // read the item back JObject itemRead = await store.LookupAsync(TestTable, "abc"); // make sure everything was persisted the same Assert.AreEqual(originalItem.ToString(), itemRead.ToString()); // change the item originalItem["double"] = 111.222d; // upsert the item await store.UpsertAsync(TestTable, new[] { originalItem }, ignoreMissingColumns : false); // read the updated item JObject updatedItem = await store.LookupAsync(TestTable, "abc"); // make sure the float was updated Assert.AreEqual(updatedItem.Value <double>("double"), 111.222d); // make sure the item is same as updated item Assert.AreEqual(originalItem.ToString(), updatedItem.ToString()); // make sure item is not same as its initial state Assert.AreNotEqual(originalItem.ToString(), itemRead.ToString()); // now delete the item await store.DeleteAsync(TestTable, new[] { "abc" }); // now read it back JObject item4 = await store.LookupAsync(TestTable, "abc"); // it should be null because it doesn't exist Assert.IsNull(item4); } }
public async Task UpsertAsync_DoesNotThrow_WhenItemIsEmpty() { TestUtilities.DropTestTable(TestDbName, TestTable); using (var store = new MobileServiceSQLiteStore(TestDbName)) { store.DefineTable(TestTable, new JObject() { { "id", String.Empty }, { "dob", DateTime.UtcNow } }); await store.InitializeAsync(); await store.UpsertAsync(TestTable, new[] { new JObject() }, ignoreMissingColumns: true); await store.UpsertAsync(TestTable, new[] { new JObject() }, ignoreMissingColumns: false); } }
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(); } }
public async Task UpsertAsync_Throws_WhenInsertingRecordsWhichAreTooLarge() { TestUtilities.DropTestTable(TestDbName, TestTable); using (var store = new MobileServiceSQLiteStore(TestDbName)) { var template = new JObject { { "id", 0 }, }; //SQLite limits us to 999 "parameters" per prepared statement for (var i = 0; i < 1000; i++) { template["column" + i] = "Hello, world"; } store.DefineTable(TestTable, template); //create the table await store.InitializeAsync(); //attempt to insert a couple of items var item1 = new JObject(template); item1["id"] = 1; var item2 = new JObject(template); item1["id"] = 2; InvalidOperationException ex = await AssertEx.Throws<InvalidOperationException>(() => store.UpsertAsync(TestTable, new[] { item1, item2 }, ignoreMissingColumns: false)); Assert.AreEqual("The number of fields per entity in an upsert operation is limited to 800.", ex.Message); } }
public async Task SystemPropertiesArePreserved_OnlyWhenReturnedFromServer() { ResetDatabase(TestTable); var hijack = new TestHttpHandler(); var store = new MobileServiceSQLiteStore(TestDbName); store.DefineTable <ToDoWithSystemPropertiesType>(); IMobileServiceClient service = await CreateClient(hijack, store); IMobileServiceSyncTable <ToDoWithSystemPropertiesType> table = service.GetSyncTable <ToDoWithSystemPropertiesType>(); // first insert an item var updatedItem = new ToDoWithSystemPropertiesType() { Id = "b", String = "Hey", Version = "abc", CreatedAt = new DateTime(2013, 1, 1, 1, 1, 1, DateTimeKind.Utc), UpdatedAt = new DateTime(2013, 1, 1, 1, 1, 2, DateTimeKind.Utc) }; await table.UpdateAsync(updatedItem); var lookedupItem = await table.LookupAsync("b"); Assert.AreEqual(lookedupItem.String, "Hey"); Assert.AreEqual(lookedupItem.Version, "abc"); // we ignored the sys properties on the local object Assert.AreEqual(lookedupItem.CreatedAt, new DateTime(0, DateTimeKind.Utc)); Assert.AreEqual(lookedupItem.UpdatedAt, new DateTime(0, DateTimeKind.Utc)); Assert.AreEqual(service.SyncContext.PendingOperations, 1L); // operation pending hijack.OnSendingRequest = async req => { // we request all the system properties present on DefineTable<> object Assert.AreEqual(req.RequestUri.Query, "?__systemproperties=__createdAt%2C__updatedAt%2C__version%2C__deleted"); string content = await req.Content.ReadAsStringAsync(); Assert.AreEqual(content, @"{""id"":""b"",""String"":""Hey""}"); // the system properties are not sent to server return(req); }; string updateResult = "{\"id\":\"b\",\"String\":\"Wow\",\"__version\":\"def\",\"__createdAt\":\"2014-01-29T23:01:33.444Z\", \"__updatedAt\":\"2014-01-30T23:01:33.444Z\"}"; hijack.Responses.Add(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(updateResult) }); // push await service.SyncContext.PushAsync(); Assert.AreEqual(service.SyncContext.PendingOperations, 0L); // operation removed lookedupItem = await table.LookupAsync("b"); Assert.AreEqual(lookedupItem.String, "Wow"); Assert.AreEqual(lookedupItem.Version, "def"); // we preserved the system properties returned from server on update Assert.AreEqual(lookedupItem.CreatedAt.ToUniversalTime(), new DateTime(2014, 01, 29, 23, 1, 33, 444, DateTimeKind.Utc)); Assert.AreEqual(lookedupItem.UpdatedAt.ToUniversalTime(), new DateTime(2014, 01, 30, 23, 1, 33, 444, DateTimeKind.Utc)); }
private async Task InitLocalStoreAsync() { // new code to initialize the SQLite store string path = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), localDbFilename); if (!File.Exists(path)) { File.Create(path).Dispose(); } var store = new MobileServiceSQLiteStore(localDbFilename); BeaconActivity beaconact = new BeaconActivity(); GuiSettingsActivity guisettingsact = new GuiSettingsActivity(); store.DefineTable <Beacon>(); store.DefineTable <GuiSettings>(); store.DefineTable <Location>(); store.DefineTable <Map>(); store.DefineTable <Prompt>(); store.DefineTable <PromptStep>(); store.DefineTable <Reminder>(); store.DefineTable <Settings>(); store.DefineTable <UserSettings>(); store.DefineTable <Users>(); store.DefineTable <UserMaps>(); // Uses the default conflict handler, which fails on conflict // To use a different conflict handler, pass a parameter to InitializeAsync. For more details, see http://go.microsoft.com/fwlink/?LinkId=521416 await client.SyncContext.InitializeAsync(store); }
public async Task UpsertAsync_InsertsTheRow_WhenItemHasNullValues() { TestUtilities.DropTestTable(TestDbName, TestTable); // insert a row and make sure it is inserted using (var store = new MobileServiceSQLiteStore(TestDbName)) { store.DefineTable(TestTable, new JObject() { { "id", String.Empty }, { "dob", DateTime.UtcNow }, { "age", 0}, { "weight", 3.5 }, { "code", Guid.NewGuid() }, { "options", new JObject(){} }, { "friends", new JArray(){} }, { "version", String.Empty } }); await store.InitializeAsync(); var inserted = new JObject() { { "id", "abc" }, { "dob", null }, { "age", null }, { "weight", null }, { "code", null }, { "options", null }, { "friends", null }, { "version", null } }; await store.UpsertAsync(TestTable, new[] { inserted }, ignoreMissingColumns: false); JObject read = await store.LookupAsync(TestTable, "abc"); Assert.AreEqual(inserted.ToString(), read.ToString()); } }
public async Task PushAsync_RetriesOperation_WhenConflictOccursInLastPush() { ResetDatabase(TestTable); var hijack = new TestHttpHandler(); string conflictResult = "{\"id\":\"b\",\"String\":\"Hey\",\"__version\":\"def\"}"; hijack.Responses.Add(new HttpResponseMessage(HttpStatusCode.PreconditionFailed) { Content = new StringContent(conflictResult) }); // first push string successResult = "{\"id\":\"b\",\"String\":\"Wow\",\"__version\":\"def\"}"; hijack.Responses.Add(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(successResult) }); // second push var store = new MobileServiceSQLiteStore(TestDbName); store.DefineTable <ToDoWithSystemPropertiesType>(); IMobileServiceClient service = await CreateClient(hijack, store); IMobileServiceSyncTable <ToDoWithSystemPropertiesType> table = service.GetSyncTable <ToDoWithSystemPropertiesType>(); // first insert an item var updatedItem = new ToDoWithSystemPropertiesType() { Id = "b", String = "Hey", Version = "abc" }; await table.UpdateAsync(updatedItem); // then push it to server var ex = await ThrowsAsync <MobileServicePushFailedException>(service.SyncContext.PushAsync); Assert.IsNotNull(ex.PushResult); Assert.AreEqual(ex.PushResult.Status, MobileServicePushStatus.Complete); Assert.AreEqual(ex.PushResult.Errors.Count(), 1); MobileServiceTableOperationError error = ex.PushResult.Errors.FirstOrDefault(); Assert.IsNotNull(error); Assert.AreEqual(error.Handled, false); Assert.AreEqual(error.OperationKind, MobileServiceTableOperationKind.Update); Assert.AreEqual(error.RawResult, conflictResult); Assert.AreEqual(error.TableName, TestTable); Assert.AreEqual(error.Status, HttpStatusCode.PreconditionFailed); var errorItem = error.Item.ToObject <ToDoWithSystemPropertiesType>(JsonSerializer.Create(service.SerializerSettings)); Assert.AreEqual(errorItem.Id, updatedItem.Id); Assert.AreEqual(errorItem.String, updatedItem.String); Assert.AreEqual(errorItem.Version, updatedItem.Version); Assert.AreEqual(errorItem.CreatedAt, updatedItem.CreatedAt); Assert.AreEqual(errorItem.UpdatedAt, updatedItem.UpdatedAt); Assert.AreEqual(error.Result.ToString(Formatting.None), conflictResult); Assert.AreEqual(service.SyncContext.PendingOperations, 1L); // operation not removed updatedItem = await table.LookupAsync("b"); Assert.AreEqual(updatedItem.String, "Hey"); // item is not updated await service.SyncContext.PushAsync(); Assert.AreEqual(service.SyncContext.PendingOperations, 0L); // operation now succeeds updatedItem = await table.LookupAsync("b"); Assert.AreEqual(updatedItem.String, "Wow"); // item is updated }
public async Task UpsertAsync_CanProcessManyRecordsAtOnce() { TestUtilities.DropTestTable(TestDbName, TestTable); using (var store = new MobileServiceSQLiteStore(TestDbName)) { var template = new JObject { { "id", 0 }, { "value1", "Hello, world" }, { "value2", "Hello, world" }, { "value3", "Hello, world" }, { "value4", "Hello, world" }, { "value5", "Hello, world" } }; store.DefineTable(TestTable, template); //create the table await store.InitializeAsync(); //add a whole bunch of items. We want {number of items} * {number of fields} to exceed sqlite's parameter limit const int insertedItemCount = 500; var itemsToInsert = Enumerable.Range(1, insertedItemCount) .Select(id => { var o = new JObject(template); o["id"] = id; return o; }) .ToArray(); //Insert the items await store.UpsertAsync(TestTable, itemsToInsert, ignoreMissingColumns: false); JArray records = (JArray)await store.ReadAsync(MobileServiceTableQueryDescription.Parse(TestTable, "$orderby=id")); //Verify that all 500 records were inserted Assert.AreEqual(records.Count, insertedItemCount); //Verify that all fields are intact for (var i = 0; i < insertedItemCount; i++) { Assert.IsTrue(JToken.DeepEquals(itemsToInsert[i], records[i]), "Results retrieved from DB do not match input"); } } }
public async Task Insert_AllTypes_ThenRead_ThenPush_ThenLookup() { ResetDatabase("AllBaseTypesWithAllSystemPropertiesType"); var hijack = new TestHttpHandler(); var store = new MobileServiceSQLiteStore(TestDbName); store.DefineTable <AllBaseTypesWithAllSystemPropertiesType>(); IMobileServiceClient service = await CreateClient(hijack, store); IMobileServiceSyncTable <AllBaseTypesWithAllSystemPropertiesType> table = service.GetSyncTable <AllBaseTypesWithAllSystemPropertiesType>(); // first insert an item var inserted = new AllBaseTypesWithAllSystemPropertiesType() { Id = "abc", Bool = true, Byte = 11, SByte = -11, UShort = 22, Short = -22, UInt = 33, Int = -33, ULong = 44, Long = -44, Float = 55.66f, Double = 66.77, Decimal = 77.88M, String = "EightyEight", Char = '9', DateTime = new DateTime(2010, 10, 10, 10, 10, 10, DateTimeKind.Utc), DateTimeOffset = new DateTimeOffset(2011, 11, 11, 11, 11, 11, 11, TimeSpan.Zero), Nullable = 12.13, NullableDateTime = new DateTime(2010, 10, 10, 10, 10, 10, DateTimeKind.Utc), TimeSpan = new TimeSpan(0, 12, 12, 15, 95), Uri = new Uri("http://example.com"), Enum1 = Enum1.Enum1Value2, Enum2 = Enum2.Enum2Value2, Enum3 = Enum3.Enum3Value2, Enum4 = Enum4.Enum4Value2, Enum5 = Enum5.Enum5Value2, Enum6 = Enum6.Enum6Value2 }; await table.InsertAsync(inserted); IList <AllBaseTypesWithAllSystemPropertiesType> records = await table.ToListAsync(); Assert.AreEqual(records.Count, 1); Assert.AreEqual(records.First(), inserted); // now push hijack.AddResponseContent(@" {""id"":""abc"", ""bool"":true, ""byte"":11, ""sByte"":-11, ""uShort"":22, ""short"":-22, ""uInt"":33, ""int"":-33, ""uLong"":44, ""long"":-44, ""float"":55.66, ""double"":66.77, ""decimal"":77.88, ""string"":""EightyEight"", ""char"":""9"", ""dateTime"":""2010-10-10T10:10:10.000Z"", ""dateTimeOffset"":""2011-11-11T11:11:11.011Z"", ""nullableDateTime"":""2010-10-10T10:10:10.000Z"", ""timeSpan"":""12:12:15.095"", ""nullable"":12.13, ""uri"":""http://example.com/"", ""enum1"":""Enum1Value2"", ""enum2"":""Enum2Value2"", ""enum3"":""Enum3Value2"", ""enum4"":""Enum4Value2"", ""enum5"":""Enum5Value2"", ""enum6"":""Enum6Value2"", ""__version"":""XYZ""}"); await service.SyncContext.PushAsync(); AllBaseTypesWithAllSystemPropertiesType lookedUp = await table.LookupAsync("abc"); inserted.Version = "XYZ"; Assert.AreEqual(inserted, lookedUp); }
public async Task InitializeAsync() { MobileServiceSQLiteStore store; lock (locker) { if (IsInitialized) { return; } IsInitialized = true; var dbId = Settings.DatabaseId; var path = System.IO.Path.Combine(Settings.SqlitePath, $"syncstore{dbId}.db"); MobileService = new MobileServiceClient("https://devopenspaceworkshop2016.azurewebsites.net"); store = new MobileServiceSQLiteStore(path); store.DefineTable <Category>(); store.DefineTable <Favorite>(); store.DefineTable <Notification>(); store.DefineTable <FeaturedEvent>(); store.DefineTable <Feedback>(); store.DefineTable <Room>(); store.DefineTable <Session>(); store.DefineTable <Workshop>(); store.DefineTable <Speaker>(); store.DefineTable <Sponsor>(); store.DefineTable <SponsorLevel>(); store.DefineTable <StoreSettings>(); store.DefineTable <ApplicationData>(); } try { await MobileService.SyncContext.InitializeAsync(store, new MobileServiceSyncHandler()).ConfigureAwait(false); await LoadCachedTokenAsync().ConfigureAwait(false); } catch (Exception ex) { Debug.WriteLine(ex); } }
private async Task InitLocalStoreAsync() { // new code to initialize the SQLite store writedb(); var store = new MobileServiceSQLiteStore(localDbFilename); store.DefineTable <caapa.SharedBeacon>(); store.DefineTable <GuiSettings>(); store.DefineTable <Location>(); store.DefineTable <Map>(); store.DefineTable <Prompt>(); store.DefineTable <PromptStep>(); store.DefineTable <Reminder>(); store.DefineTable <Settings>(); store.DefineTable <UserMaps>(); store.DefineTable <UserSettings>(); store.DefineTable <Users>(); CurrentPlatform.Init(); // Uses the default conflict handler, which fails on conflict // To use a different conflict handler, pass a parameter to InitializeAsync. For more details, see http://go.microsoft.com/fwlink/?LinkId=521416 await client.SyncContext.InitializeAsync(store); }
public async Task UpsertAsync_ThenReadAsync_AllTypes() { TestUtilities.DropTestTable(TestDbName, TestTable); // first create a table called todo using (MobileServiceSQLiteStore store = new MobileServiceSQLiteStore(TestDbName)) { store.DefineTable(TestTable, JObjectTypes.GetObjectWithAllTypes()); await store.InitializeAsync(); var upserted = new JObject() { { "id", "xyz" }, { "Object", new JObject() { {"id", "abc"} }}, { "Array", new JArray() { new JObject(){{"id", 3}} } }, { "Integer", 123L }, { "Float", 12.5m }, { "String", "def" }, { "Boolean", true }, { "Date", new DateTime(2003, 5, 6, 4, 5, 1, DateTimeKind.Utc) }, { "Bytes", new byte[] { 1, 2, 3} }, { "Guid", new Guid("AB3EB1AB-53CD-4780-928B-A7E1CB7A927C") }, { "TimeSpan", new TimeSpan(1234) } }; await store.UpsertAsync(TestTable, new[] { upserted }, false); var query = new MobileServiceTableQueryDescription(TestTable); var items = await store.ReadAsync(query) as JArray; Assert.IsNotNull(items); Assert.AreEqual(items.Count, 1); var lookedup = items.First as JObject; Assert.AreEqual(upserted.ToString(Formatting.None), lookedup.ToString(Formatting.None)); } }
private void InitializeLocal(string table) { var sqliteFilename = "WellSpringSQLite.db3"; string documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); // Documents folder var path = Path.Combine(documentsPath, sqliteFilename); if (!File.Exists(path)) { File.Create(path).Dispose(); } var store = new MobileServiceSQLiteStore(path); if (table == "CalendarTable") { store.DefineTable <CalendarTable>(); } else if (table == "CommentTable") { } else if (table == "CommunityPostTable") { store.DefineTable <CommunityPostTable>(); } else if (table == "ConsultTable") { store.DefineTable <ConsultTable>(); } else if (table == "CustomFoodsTable") { } else if (table == "ExerciseEnteredTable") { store.DefineTable <ExerciseEnteredTable>(); } else if (table == "ExerciseTable") { store.DefineTable <ExerciseTable>(); } else if (table == "FoodEnteredTable") { store.DefineTable <FoodEnteredTable>(); } else if (table == "FoodsTable") { store.DefineTable <FoodsTable>(); } else if (table == "GoalTable") { store.DefineTable <GoalTable>(); } else if (table == "GroupMeetUpMemberTable") { } else if (table == "JourneyTable") { } else if (table == "MeetUpMemberTable") { } else if (table == "MeetupsTable") { store.DefineTable <MeetupsTable>(); } else if (table == "NurseTable") { } else if (table == "UserTable") { store.DefineTable <UserTable>(); } else { store.DefineTable <TodoItem>(); } azureDatabase.SyncContext.InitializeAsync(store); }